Deserializing inherited classes - c#

I want to send parameter-settings from a backendapplication to the frontend. I also need to be able to have different type of parameters (Portnumbers, folders, static strings and such).
So I've designed a baseclass, Parameter as such:
public abstract class Parameter
{
public abstract bool isValid();
}
Let's say that we have two types of folder parameters:
public abstract class Folder : Parameter
{
public string folderName { get; set; }
protected Folder(string folderName)
{
this.folderName = folderName;
}
}
public class ReadWriteFolder : Folder
{
public ReadWriteFolder(string folderName) : base(folderName)
{
}
public override bool isValid()
{
return isReadable() && isWritable();
}
}
public class ReadFolder : Folder
{
public ReadFolder(string folderName) : base(folderName)
{
}
public override bool isValid()
{
return isReadable();
}
}
This is used from a WebAPI, so this is my controller:
public Dictionary<String, Parameter> Get()
{
Dictionary<String, Parameter> dictionary = new Dictionary<String, Parameter>();
dictionary.Add("TemporaryFiles", new ReadWriteFolder("C:\\temp\\"));
dictionary.Add("AnotherTemporaryFiles", new ReadWriteFolder("D:\\temp\\"));
return dictionary;
}
This yields the following JSON-serialisation:
{"TemporaryFiles":{"folderName":"C:\\temp\\"},"AnotherTemporaryFiles":{"folderName":"D:\\temp\\"}} which seems reasonable.
My question is this: How can I deserialize this back into the original types? Or change the serialization into something that is more easy to deserialize?

What are you using for serialization? If it's JSON.Net (which many here would suggest!), there's a number of realted questions:
how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET
But the crux is the type name handling, which will decorate the elements with the type information to be able to deserialize them:
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
string strJson = JsonConvert.SerializeObject(dictionary, settings);
And then you should be able to deserialize directly.
var returnDictionary = JsonConvert.DeserializeObject<Dictionary<String, Parameter>>(strJson, settings)

Related

How to deep clone the Class that contains DynamicObject in C#?

public class DynamicDictionary : System.Dynamic.DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
{
return this.dictionary?.Keys;
}
}
public class SerializeExtensions
{
public string Name { get; set; }
public DynamicDictionary DynamicObj { get; set; }
}
Please consider the above like my class.
I have a List of SerializeExtensions collection. Now I have to deep clone this list of collections.
This has been properly cloned when I am using the below code.
JsonConvert.DeserializeObject<List<SerializeExtensions>>(JsonConvert.SerializeObject(collection));
This serialization belongs to Newtonsoft.Json. But I need to System.Text.Json for serialization.
So when I am using System.Text.Json serialization, the DynamicObject field has reset to empty. the below code has used.
JsonSerializer.Deserialize<List<SerializeExtensions>>(JsonSerializer.Serialize(collection));
After the serialization, I am getting the output like below
Name: "John"
DynamicObj: {}
Actually, the DynamicObj count is 4 in my case before serialization.
is there any possible to deep clone this kind of class?

custom javascript deserializer in c#

I am working on a C# application which has a browser integrated with it.
The browser will send some data to C# in json format.
Some of the fields from json can be dserialized using javascript deserializer, but I have some data for which a custom deserializer is required, I need to register a deserializer for that but the thing is the custom deserializer must be called only for those special data and the default javascript deserializer must be called for other data, the special data can be identified from there target field's data type / name in C#. How can I achieve this.
something like this.
public class example
{
public string abc;
public someOtherDataType xyz;
public void example()
{
serializer = new JavaScriptSerializer();
// receive json string
serializer.RegisterConverters(new JavaScriptConverter[]
{
new System.Web.Script.Serialization.CS.CustomConverter()
});
//call deserializer
}
}
The json string will be something like
{
"abc" : "valueabc"
"xyz" : "valueXYZ"
}
Now the custom deserializer must be called only during deserializing xyz and default must be called for abc.
Thank you.
The difficulty here is that a JavaScriptConverter allows you to map a JSON object from and to a c# class -- but in your JSON, "xyz" is just a string, not an object. Thus you can't specify a converter for someOtherDataType and instead must specify converters for every class that contains an instance of someOtherDataType.
(Note that the custom converter functionality in Json.NET does not have this restriction. If you were willing to switch to that library you could write a JsonConverter converting all uses of someOtherDataType from and to a JSON string.)
To write such a JavaScriptConverter:
Override JavaScriptConverter.Deserialize
Create a second Dictionary<string, Object> filtering out the fields requiring custom conversion.
Call new JavaScriptSerializer.ConvertToType<T> to deserialize the standard fields from the filtered dictionary.
Manually convert the remaining fields.
Override SupportedTypes to return the container type.
Thus, in your example, you could do:
public class example
{
public string abc;
public someOtherDataType xyz;
}
// Example implementation only.
public class someOtherDataType
{
public string SomeProperty { get; set; }
public static someOtherDataType CreateFromJsonObject(object xyzValue)
{
if (xyzValue is string)
{
return new someOtherDataType { SomeProperty = (string)xyzValue };
}
return null;
}
}
class exampleConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new[] { typeof(example) }; }
}
// Custom conversion code below
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var defaultDict = dictionary.Where(pair => pair.Key != "xyz").ToDictionary(pair => pair.Key, pair => pair.Value);
var overrideDict = dictionary.Where(pair => !(pair.Key != "xyz")).ToDictionary(pair => pair.Key, pair => pair.Value);
// Use a "fresh" JavaScriptSerializer here to avoid infinite recursion.
var value = (example)new JavaScriptSerializer().ConvertToType<example>(defaultDict);
object xyzValue;
if (overrideDict.TryGetValue("xyz", out xyzValue))
{
value.xyz = someOtherDataType.CreateFromJsonObject(xyzValue);
}
return value;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
And then, to test:
public class TestClass
{
public static void Test()
{
// receive json string
string json = #"{
""abc"" : ""valueabc"",
""xyz"" : ""valueXYZ""
}";
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[]
{
new exampleConverter()
});
var example = serializer.Deserialize<example>(json);
Debug.Assert(example.abc == "valueabc" && example.xyz.SomeProperty == "valueXYZ"); // No assert
}
}

Serialize list of interface types with ServiceStack.Text

I'm looking at ways to introduce something other than BinaryFormatter serialization into my app to eventually work with Redis. ServiceStack JSON is what I would like to use, but can it do what I need with interfaces?
It can serialize (by inserting custom __type attribute)
public IAsset Content;
but not
public List<IAsset> Contents;
- the list comes up empty in serialized data. Is there any way to do this - serialize a list of interface types?
The app is big and old and the shape of objects it uses is probably not going to be allowed to change.
Thanks
Quoting from http://www.servicestack.net/docs/framework/release-notes
You probably don't have to do much :)
The JSON and JSV Text serializers now support serializing and
deserializing DTOs with Interface / Abstract or object types. Amongst
other things, this allows you to have an IInterface property which
when serialized will include its concrete type information in a __type
property field (similar to other JSON serializers) which when
serialized populates an instance of that concrete type (provided it
exists).
[...]
Note: This feature is automatically added to all
Abstract/Interface/Object types, i.e. you don't need to include any
[KnownType] attributes to take advantage of it.
By not much:
public interface IAsset
{
string Bling { get; set; }
}
public class AAsset : IAsset
{
public string Bling { get; set; }
public override string ToString()
{
return "A" + Bling;
}
}
public class BAsset : IAsset
{
public string Bling { get; set; }
public override string ToString()
{
return "B" + Bling;
}
}
public class AssetBag
{
[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List<IAsset> Assets { get; set; }
}
class Program
{
static void Main(string[] args)
{
try
{
var bag = new AssetBag
{
Assets = new List<IAsset> {new AAsset {Bling = "Oho"}, new BAsset() {Bling = "Aha"}}
};
string json = JsonConvert.SerializeObject(bag, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto
});
var anotherBag = JsonConvert.DeserializeObject<AssetBag>(json, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto
});

Json.net serialize/deserialize derived types?

json.net (newtonsoft)
I am looking through the documentation but I can't find anything on this or the best way to do it.
public class Base
{
public string Name;
}
public class Derived : Base
{
public string Something;
}
JsonConvert.Deserialize<List<Base>>(text);
Now I have Derived objects in the serialized list. How do I deserialize the list and get back derived types?
You have to enable Type Name Handling and pass that to the (de)serializer as a settings parameter.
Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };
JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);
This will result in correct deserialization of derived classes. A drawback to it is that it will name all the objects you are using, as such it will name the list you are putting the objects in.
If you are storing the type in your text (as you should be in this scenario), you can use the JsonSerializerSettings.
See: how to deserialize JSON into IEnumerable<BaseType> with Newtonsoft JSON.NET
Be careful, though. Using anything other than TypeNameHandling = TypeNameHandling.None could open yourself up to a security vulnerability.
Since the question is so popular, it may be useful to add on what to do if you want to control the type property name and its value.
The long way is to write custom JsonConverters to handle (de)serialization by manually checking and setting the type property.
A simpler way is to use JsonSubTypes, which handles all the boilerplate via attributes:
[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
public virtual string Sound { get; }
public string Color { get; set; }
}
public class Dog : Animal
{
public override string Sound { get; } = "Bark";
public string Breed { get; set; }
}
public class Cat : Animal
{
public override string Sound { get; } = "Meow";
public bool Declawed { get; set; }
}
Use this JsonKnownTypes, it's very similar way to use, it just add discriminator to json:
[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
public string Name;
}
public class Derived : Base
{
public string Something;
}
Now when you serialize object in json will be add "$type" with "base" and "derived" value and it will be use for deserialize
Serialized list example:
[
{"Name":"some name", "$type":"base"},
{"Name":"some name", "Something":"something", "$type":"derived"}
]
just add object in Serialize method
var jsonMessageBody = JsonSerializer.Serialize<object>(model);

Storing a Dictionary with polymorphic values in mongoDB using C#

Let us say we have a key with values which are polymorphic in their sense. Consider the next sample project:
public class ToBeSerialized
{
[BsonId]
public ObjectId MongoId;
public IDictionary<string, BaseType> Dictionary;
}
public abstract class BaseType
{
}
public class Type1 : BaseType
{
public string Value1;
}
public class Type2:BaseType
{
public string Value1;
public string Value2;
}
internal class Program
{
public static void Main()
{
var objectToSave = new ToBeSerialized
{
MongoId = ObjectId.GenerateNewId(),
Dictionary = new Dictionary<string, BaseType>
{
{"OdEd1", new Type1 {Value1="value1"}},
{
"OdEd2",
new Type1 {Value1="value1"}
}
}
};
string connectionString = "mongodb://localhost/Serialization";
var mgsb = new MongoUrlBuilder(connectionString);
var MongoServer = MongoDB.Driver.MongoServer.Create(mgsb.ToMongoUrl());
var MongoDatabase = MongoServer.GetDatabase(mgsb.DatabaseName);
MongoCollection<ToBeSerialized> mongoCollection = MongoDatabase.GetCollection<ToBeSerialized>("Dictionary");
mongoCollection.Save(objectToSave);
ToBeSerialized received = mongoCollection.FindOne();
}
}
Sometimes when I try to deserialize it, I get deserialization errors like "Unknown discriminator value 'The name of concrete type'". What am I doing wrong? If every value stores a _t why cannot it map it correctly?
Driver should know about all discriminators to deserialize any class without errors. There are two ways to do it:
1.Register it globally during app start:
BsonClassMap.RegisterClassMap<Type1>();
BsonClassMap.RegisterClassMap<Type2>();
2.Or though the BsonKnownTypes attibute:
[BsonKnownTypes(typeof(Type1), typeof(Type2)]
public class BaseType
{
}
If you will use #1 or #2 your deserialization will work correctly.
You have to register which types inherit from BaseClass before attempting to deserialize them. This will happen automatically if you serialize first, which is probably why the error occurs only sometimes.
You can register derived types using an attribute:
[BsonDiscriminator(Required = true)]
[BsonKnownTypes(typeof(DerivedType1), typeof(DerivedType2))]
public class BaseClass { ... }
public class DerivedType1 : BaseClass { ... }

Categories