C# type serialization not as a collection of key value pairs - serialization

I have a class that when serialized, I want to return as a single string without key value pairs. A string becomes a string. An int becomes an int. How do I make my class become a string?
Looking at DataContract and Serializable, it doesn't look that this is possible. The SerializationInfo.AddValue(name, value) setup forces your whole object into a key-value approach. I just want to return "A and B".
[DataContract]
public class MyObject
{
public int A { get; set; }
public int B { get; set; }
}
When serialized using the DataContractJsonSerializer, for example, I want it to be:
4 and 2
Not
{
"A": 4,
"B": 2
}
So let's say I have a parent class that uses both of these custom types:
[DataContract]
public class Parent
{
[DataMember]
public MyObject One { get; set; }
[DataMember]
public MyObject Two { get; set; }
}
I want to it serialize like this:
{
"One": "4 and 2",
"Two": "6 and 8"
}
Instead, the only thing I seem to be able to make it do is:
{
"One": {
"A": 4,
"B": 2
},
"Two": {
"A": 6,
"B": 8
}
}
The only solution that would work, is to add the custom serialization on Parent, setting One and Two accordingly, but I don't want to do that, I want my new class to get serialized as a string everywhere.
Can I serialize a type as a single return value? Or do all types besides built-in ones like int and string have to serialize to an object?

You can simply add a get attribute that returns the attributes as a string in any way that you like...
public class MyObject
{
public int A { get; set; }
public int B { get; set; }
public string MyNewStringAttribute {
get{
return A + " and " + B;
}
}
}
Then, when you can serialize from the controller using the new attribute from an array, linq, etc.

My answer: You can't.
The parent class, MyObject has to implement ISerializable to provide the custom serialization of the class itself. This places the responsibility of correctly serializing the class the way it is intended to each class that wishes to use it, which is an undesirable experience, and highlights a severe design flaw in the supported .NET custom serializer strategy.
[Serializable]
public class Parent : ISerializable
{
public MyObject One { get; set; }
public MyObject Two { get; set; }
public (SerializerInfo info, SerializerContext context)
{
string oneString = info.GetString("One");
One = new MyObject(oneString);
string twoString = info.GetString("Two");
Two = new MyObject(twoString);
}
public override void GetObjectData(SerializerInfo info, SerializerContext context)
{
info.AddValue("One", One.ToString());
info.AddValue("Two", Two.ToString());
}
}
Grumble grumble... add this to the long list of things that .NET has gotten wrong. Static / non interfaced classes for everything making the framework untestable by default without creating plug-n-chug wrappers for everything. Compilers with lossful MSIL/symbols. I could go on and on.

Related

ASP.NET CORE model with a collection<string>

Hi I'm trying to add to a model the property of colors
color is an array of strings.
model
public class dog
{
// other properties
public ICollection<string> Colors { get; set; }
}
dbContext
public DataContext(DbContextOptions options) : base(options)
{
}
public DbSet<Dog> Dogs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>().HasMany(user => user.Dogs).WithOne(dog=> dog.AppUser)
.OnDelete(DeleteBehavior.Cascade);
}
What relation should I do if I want that if I delete a dog so the colors will be deleted as well? because I'm unable to run the migration because I'm getting this error:
The property 'dogs.Colors' could not be mapped because it is of type 'Collection', which is not a supported
primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
I tried searching this question but I didn't really find any useful answers to my issue.
Can anyone please explain to me what causes it and what should I do to fix it?
you can not use ICollection in your database Model becasue that doesn't have equivalent type in Database(such as sqlsever , mysql , ...)
actually you should create other table for 'Color' in this way :
public class dog
{
public int Id {get; set;}
// other properties
public ICollection<Color> Colors { get; set; }
}
public class Color
{
public string Value {get; set;}
public int DogId {get; set}
public dog Dog{ get; set; }
}
also you can add in your DbContext Class :
public DbSet<Color> Colors { get; set; }
Also if you don't want to save ICollection in database, you can ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
For example :
[NotMapped]
public ICollection<string> Colors { get; set; }
I'm thinking of two ways of handling this...
1. Using a backing field
Backing fields allow EF to read and/or write to a field rather than a
property. This can be useful when encapsulation in the class is being
used to restrict the use of and/or enhance the semantics around access
to the data by application code, but the value should be read from
and/or written to the database without using those
restrictions/enhancement
public class Dog
{
// other properties
private string _colors; //this is the backing field
public ICollection<string> Colors
{
get
{
if (string.IsNullOrWhiteSpace(_colors))
return new List<string>(); //empty list
return _colors.Split(",");
}
set
{
//you can have other logic, instead of setting it directly
//in this case, it will overwrite the old value
_colors = string.Join(",", value);
}
}
}
On your database Dogs table, have a column name of Colors with nvarchar or varchar datatype.
When you store the color value, which is a list of string values, convert it to a concatenated single string value. Likewise, whenever you want to have the single string value on your code as a collection, use string to array conversion.
2. Re-model your Dog entity
This will have you create two more tables on your database. These tables are Colors and DogsColors. One thing to note here is both Dog and Color have many to many relationships.
Depending on your dotnet core version, you may have to create one or more entity models.
If you are using Dotnet Core 5 or higher, you only need one entity model Color. Otherwise, you may have to add the DogsColor entity model.
Dotnet core 5 or higher:
.net core 5 many to many relationships
Many to many relationships require a collection navigation property on
both sides. They will be discovered by conventions like other types of
relationships.
public class Color {
public int Id { get; set; }
public string Color { get; set;}
public ICollection<Dog> Dogs {get;set;} //for many to many relationship
}
public class Dog
{
public ICollection<Color> Colors { get; set; }
}
//dbcontext configuration
builder.Entity<Dog>()
.HasMany(i => i.Colors)
.WithMany(i => i.Dogs)
.UsingEntity<Dictionary<string, object>>(
"DogColors",
x => x.HasOne<Color>().WithMany().HasForeignKey("ColorId"),
x => x.HasOne<Dog>().WithMany().HasForeignKey("DogId"));
If you are using Dotnet core 3 or lower:
public class Color {
public int Id { get; set; }
public string Color { get; set;}
}
public class DogColor {
public int Id { get; set; }
public Dog Dog { get; set;}
public Color Color { get; set;}
}
public class Dog
{
public ICollection<DogColor> DogColors { get; set; }
}

.NET Core - Json.NET Deserialisation Mapping

Is it possible to do mapping during the deserialization process of a JSON string to an object?
var resultObject = JsonConvert.DeserializeObject<ConfigItemGetResult>(result);
My JSON string is different from the object I want to deserialize to. So mapping has to happen. I'm trying to avoid making a model that maps 1 to 1 to the JSON string followed by mapping from object to object with for example AutoMapper.
Use Serialization Attributes for configuring your serialization mapping
public class JsonTest
{
[JsonProperty(PropertyName = "SomePropNameFromJson")]
public string SomeProp { get; set; }
[JsonProperty(PropertyName = "SomeNested")]
public SomeClass SomeClass { get; set; }
}
public class SomeClass
{
public SomeClass1 SomeClass1 { get; set; }
}
public class SomeClass1
{
public string text { get; set }
}
Here Json
{ "SomeProp":"value", "SomeNested":{
"SomeClass1":{
"text":"textvalue"
}
} }
Json convert trying to convert text to object by prop name with value via reflection if them finds prop name in text they take value if prop name has different name in JSON you can specify it via [JsonProperty(PropertyName = "SomeNested")] if this attr not set by default it will try get by prop name and it whatever what property is, it some object(your nested objects) or basic type, it will trying to convert it automaticaly.

Dynamic Proxy : wrapping constructors

I'm taking a stab at creating a Active Record implementation (I know about Castle's initiative, and it's very good) for another type of data provider (ESRIs geodatabases, using ESRIs .NET libraries) and I'm reaching something interesting.
I have a question nevertheless. I have my ActiveRecord classes which is like this:
public interface IActiveRecord<T> : IActiveRecord where T : class
{
T Create();
void Update(T record);
void Delete(T record);
}
public interface IActiveRecord
{
int ObjectId { get; set; }
bool Managed { get; }
bool IsValid { get; }
IObject EsriObject { get; set; }
IGeometry Geometry { get; set; }
void Save();
void Delete();
}
I have static Create methods, which go to DynamicProxy and generate me a proxy. But how I can enforce that the instance generated for a inheriting class is proxied too?
public class ActiveRecord<T> : IActiveRecord where T : IActiveRecord,new()
{
// protected constructors
public static T Create(IObject obj)
{
var record = Create();
record.EsriObject = obj;
return (T)record;
}
}
// inherited class
[Workspace(#"C:\teste.gdb")]
[Table("TB_PARCEL",Geometry=esriGeometryType.esriGeometryPolygon)]
public class Parcel : ActiveRecord<Parcel>,IParcel
{
[Field(4, "NM_PARCEL_ID", esriFieldType.esriFieldTypeString)]
public virtual string ParcelId { get; set; }
[Field(5, "NR_PARCEL_NO", esriFieldType.esriFieldTypeInteger)]
public virtual int StreetNumber { get; set; }
public virtual IOwner ParcelOwner { get; set; }
}
Take a look at the tests. The first three tests get intercepted as usual, but not the fourth test. I need A) prevent the user from instancing it's own classes (bad approach for the API in my opinion) or find a way to return from the inherited classes constructors the proxies.
[TestMethod]
public void ActiveRecordConstructor()
{
Parcel p1 = Parcel.Create();
Assert.IsFalse(p1.Managed);
Assert.AreEqual(null, p1.ParcelId);
Parcel p2 = Parcel.Create(2);
Assert.IsFalse(p2.Managed);
IObject fake = _repository.StrictMock<IObject>();
using (_repository.Record())
{
fake.Stub(x => x.get_Value(4)).Return("teste");
}
using (_repository.Playback())
{
Parcel p3 = Parcel.Create(fake);
Assert.IsTrue(p3.Managed);
Assert.AreEqual("teste", p3.ParcelId);
}
// this wont be intercepted
Parcel p4 = new Parcel();
Assert.IsFalse(p4.Managed);
Assert.IsNull(p4.ParcelId);
}
In short I need that whenever a user creates a new Class(), it returns a proxied object. Is that possible while allowing inheritance?
Thanks!
DynamicProxy cannot intercept calls to constructors. It has to control the creation of the object.

ORM with entity classes and domain interfaces/classes

I'm trying to decide how to handle domain-level classes and interfaces with respect to objects populated via ORM (NHibernate in this case). I've mocked up a very simple scenario that helps to illustrate my current situation.
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class CarFromDB
{
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class ModelT : CarFromDB, ICar
{
public bool PassesEmissionStandards(string state)
{
return false;
}
public override string ToString()
{
return Model + " with " + Horsepower + " ponies";
}
}
In this case, CarFromDB is the class that's got the mapping via NHibernate to my database. ICar is the interface that my UI/Controller code is handling. ModelT is one of the classes that have instances passed to the UI.
In my actual domain, the PassesEmissionStandards is a complicated method that differs significantly among the different derived classes, and the CarFromDB class has a dozen simple properties along with references to other classes, both singly and in lists. This information is all used in the PassesEmissionStandards equivalent.
I'm confused about the best way to end up with my derived classes decorated with the interface when I start with a populated base class from the ORM. The ideas I've come up with to try to handle this are:
Decorate CarFromDB with ICar and try to come up with a clean way to implement the extensive PassesEmissionStandards method within it or by calling out to other classes for help
Use AutoMapper or the equivalent + a factory to transform my base class objects into derived class objects
Since the derived class type can be identified from a property in the base class, mapp my derived classes for NHibernate and find some way to hook into NHibernate to instruct it which mapped derived class to use.
I feel like this must be a very common issue, but I searched around SO and other places without finding any solid guidelines. Please note: I'm relatively new to ORM and domain modelling and very new to NHibernate. Any help is appreciated.
I don't think that I understand your problem, why canĀ“t you use:
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public abstract class CarBase : ICar
{
public int Horsepower { get; set; }
public string Model { get; set; }
public abstract bool PassesEmisionStandards(string state);
}
Or if CarBase is used for all derived classes too, you might want to use strategy pattern
public interface IEmissionCalculator
{
void Calculate(IEmissionCalculatorContext context);
}
public CarBase : ICar
{
internal void Assign(IEmissionCalculator calculator){}
public bool PassesEmisionStandards(string state)
{
//assign all info needed for calculations
var ctx = new IEmissionCalculatorContext { };
return _calculator.Check(ctx);
}
}
You can use the same DB-class, but assign different emission caluclations depending of the type of car.
If that doesn't work either, I would use automapper.

Fluent nHibernate and mapping IDictionary<DaysOfWeek,IDictionay<int, decimal>> how to?

I have problem with making mapping of classes with propert of type Dictionary and value in it of type Dictionary too, like this:
public class Class1
{
public virtual int Id { get; set; }
public virtual IDictionary<DayOfWeek, IDictionary<int, decimal>> Class1Dictionary { get; set; }
}
My mapping looks like this:
Id(i => i.Id);
HasMany(m => m.Class1Dictionary);
This doesn't work. The important thing I want have everything in one table not in two. WHet I had maked class from this second IDictionary I heve bigger problem. But first I can try like it is now.
It's not currently possible to use nested collections of any type in NHibernate.
Instead, you should define your property as follows:
public virtual IDictionary<DayOfWeek, Class2> Class1Dictionary { get; set; }
And add a new class:
public class Class2
{
public virtual decimal this[int key]
{
get { return Class2Dictionary[key]; }
set { Class2Dictionary[key] = value; }
}
public virtual IDictionary<int, decimal> Class2Dictionary { get; set; }
}
This way, you can map both classes and dictionaries normally, and still access your dictionary as:
class1Instance.Class1Dictionary[DayOfWeek.Sunday][1] = 9.4