Making a non-serializable vendor class serializable - c#

I am using a class from a vendor's DLL that is not XML serializable because one of the class members is an Interface.
However, I do need to serialize an instance of the class.
How can I tell the XmlSerializer to ignore the interface and serialize everything else?

You can do 2 things:
1) Create a class with every thing you want, populate it with the your vendor class, then you serialize it.
Check adapter design pattern
2) Use Json.Net. Once I need to serialize the IPagedList that have metadata and I did this:
public static string SerializePagedList(IPagedList<T> pagedList)
{
string result = JsonConvert.SerializeObject(
// new anonymous class with everything I wanted
new
{
Items = pagedList,
MetaData = pagedList.GetMetaData()
},
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return result;
}
I hope that it helps.

Related

How to Override a Default JsonConverter (specified in an attribute)

I would like the following Author type to have a default JsonConverter, and be able to override it at runtime.
[JsonConverter(typeof(BaseJsonConverter))]
public class Author
{
// The ID of an author entity in the application.
public int ID { set; get; }
// The ID of an Author entity in its source.
public string SourceID { set; set; }
}
I used the following code to override the default converter (i.e., BaseJsonConverter).
public class AlternativeConverter : BaseJsonConverter
{ // the serializer implementation is removed for clarity. }
// Deserialize using AlternativeConverter:
var author = JsonConvert.DeserializeObject<Author>(jsonString, new AlternativeConverter());
Question
Using the above call, the AlternativeConverter is first constructed; however, then an instance of BaseJsonConverter is initialized and used for deserialization. So, the AlternativeConverter is never used.
Executable example: https://dotnetfiddle.net/l0bgYO
Use case
The application is to convert different JSON objects, obtained from different sources, to a common C# type. Commonly data comes from a source for that we define the default converter (i.e., BaseJsonConverter), and for data coming from other sources, we define different converters per each.
Background
I am aware of methods such as this one, and indeed I am using similar method partially. With ref to that article, I need to have different _propertyMappings depending on the source of input, because in my application attribute to property mapping is not one-to-one. For instance, I have the following JSON objects:
{
"id":123
}
// and
{
"id":"456"
}
where the first JSON object should be deserialized to:
author.ID = 123
author.SourceID = null
and the second JSON object should be deserialized as:
author.ID = 0
author.SourceID = "456"
You can use a custom ContractResolver to override a [JsonConverter] attribute programmatically. To solve your problem you could make a custom resolver like this:
public class CustomResolver : DefaultContractResolver
{
private Dictionary<Type, JsonConverter> Converters { get; set; }
public CustomResolver(Dictionary<Type, JsonConverter> converters)
{
Converters = converters;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
JsonObjectContract contract = base.CreateObjectContract(objectType);
if (Converters.TryGetValue(objectType, out JsonConverter converter))
{
contract.Converter = converter;
}
return contract;
}
}
Then, when you wanted to use the AlternativeConverter in place of the BaseJsonConverter, you could use the custom resolver like this:
// map the `Author` type to the `AlternativeConverter`
var converters = new Dictionary<Type, JsonConverter>()
{
{ typeof(Author), new AlternativeConverter() }
};
// Create a resolver with the converter mapping and add it to the serializer settings
var settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver(converters)
};
// Use the settings when deserializing
var author = JsonConvert.DeserializeObject<Author>(jsonString, settings);
Demo Fiddle: https://dotnetfiddle.net/cu0igV
Of course, if all you're really doing with these converters is remapping properties to different names, you could just use a ContractResolver for that in the first place and get rid of the converters altogether. See Json.NET deserialize or serialize json string and map properties to different property names defined at runtime for more information on that approach.
I think you should try to use different JsonSerializerSettings instances for different data sources, with different Converters collections. And remove JsonConverter attributes from your classes.

Use JSON.net Binder/TypeNameHandling for nested types

Using JSON.net, I want to deserialize a list of types that inherit from an abstract class. I have used KnownTypesBinder (source) like
var jsonSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.TypeNameHandling = TypeNameHandling.Auto;
jsonSettings.Binder = new KnownTypesBinder { KnownTypes = new List<Type> { ... } };
Now this works perfectly fine in the WEB API modelbinder; KnownTypesBinder.BindToType is being called an the object can be deserialized. In a different part of the web application I have to deserialize a JSON string, so I would like to re-use the same JsonFormatter. According to the docs, the following should work;
JsonConvert.DeserializeObject<T>(String, JsonSerializerSettings);
However when I do just that:
JsonConvert.DeserializeObject<A>(jsonString, GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings);
The following error is thrown:
JsonSerializationException. Could not create an instance of type C. Type is an interface or abstract class and cannot be instantiated.
My types look something like this;
class A {
public B B { get; set; }
}
class B {
public List<C> C { get; set; }
}
abstract class C { }
class C1: C { }
class C2: C { }
Also creating a new JsonSerializerSettings and setting Binder and TypeNameHandling makes no difference. I found that KnownTypesBinder.BindToType is not being called at all. Is there something in JSON.net that I'm missing?
Feeling stupid here. The discriminator used by JSON.net is called "$type". As I was using curl to send the POST payload, bash tried to resolve $type to an environment variable. As there was no such variable, the final JSON was simply {"": "C"} instead of {"$type": "C"}.

How to pass parameter to constructor deserializing json

I have a small problem with passing some parent instance to a constructor when deserializing an object with Newtonsoft.Json.
Let's assume i have the following classes
public class A
{
public string Str1 { get; set; }
public IList<B> Bs { get; set; }
}
public class B
{
public B(A a)
{
// a should not be null!
Console.WriteLine(a.Str)
}
}
And now i serailze and than deserialize the object a like this:
A a = new A()
a.Bs = new List<B>()
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
var json = JsonConvert.SerializeObject(a);
// Here i need to call the constructor of B when creating new instances
var newA = JsonConvert.DeserializeObject<A>(json);
The problem is, that when deserializing the object, null will be passed to the constructor of B. Does any one has solved this issue/problem before?
Thank you very much!
In your question and comments you've said that the class B does not have any public property for A. So, when you serialize B, then no A will be written to the JSON, because Json.Net only serializes the public information by default. Therefore, when deserializing, there will not be enough information to recreate B, because there is no A in the JSON. So, step one is making B's reference to A visible to Json.Net. If you don't want to make it public, that is fine, but you will at least need to mark the member with a [JsonProperty] attribute to allow Json.Net to "see" it.
public class B
{
[JsonProperty]
private A a;
public B(A a)
{
this.a = a; // be sure to set the A member in your constructor
}
}
Now if you do the above you will run into a second problem: your class structure has a reference loop (A has a list of Bs which each refer back to A), and the serializer will throw an exception by default in this case. The solution is to set the serializer's PreserveReferencesHandling setting to Objects (the default is None). This will not only allow the serializer to handle the reference loops during serialization, but will also preserve the original references during deserialization, so that all the Bs will refer to the same A instance. (This is accomplished via special $id and $ref properties that are written into the JSON.)
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
var json = JsonConvert.SerializeObject(a, settings);
var newA = JsonConvert.DeserializeObject<A>(json, settings);
Working example: https://dotnetfiddle.net/N0FUID
What I like to do it I have to pass objects in a constructor is to create the object first using my default constructor and then call populate object to set all properties that are not skipped as I decorated the properties with [JsonIgore]
var settings = new JsonSerializerSettings()
{
Error = HandleJsonDeserializationError,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
}
var myObject = new ComplexObject(param1,param2);
JsonConvert.PopulateObject(json, myObject, settings);
You can continue populating objects and deal with any issues if you handle serialisation errors in the JsonSettings property. The signature is as follows:
static void HandleJsonDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
errorArgs.ErrorContext.Handled = true;
//loging framework logs the error, set brake point etc when debug.
Logger.Log(currentError, LogLevel.Exceptions);
}

Deserializing object[] that contains primitive types and one class type

I have an object array that contains strings and longs and this class:
public class SimpleMailAddress
{
public string Address { get; set; }
public string Name { get; set; }
public static implicit operator MailAddress(SimpleMailAddress m)
{
return new MailAddress(m.Address, m.Name);
}
}
However, when deserializing the JSON array with Json.Net, I get an anonymous type that contains Address and Name instead of a SimpleMailAddress object.
I don't want to create a strongly-typed object to deserialize into because it will not be reused and I'd have to create a lot of objects for it. Is there a way to do this with Json.Net or any other library?
This is how I'm serializing/deserializing:
var json = JsonConvert.SerializeObject(myObject);
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json);
And MailMessageRequest:
public class MailMessageRequest
{
public string Mailer { get; set; }
public string Method { get; set; }
public object[] Args { get; set; }
}
Json does not contain any inherit knowledge about your SimpleMailAddress class. So when you are telling it to deserialize, the fact that your Args property is of type Object, the deserializer is doing the best it can (by creating an anonymous type). It just sees data, it has no knowledge that you want a SimpleMailAddress object.
Json.net has a JObject class. Try using that instead of Object for your Args parameter if the actual contents of Args may change type.
Then, as needed, you can read the data from the JObject object.
If you don't care about the actual contents of Args, then leave it as Object and ignore it.
Edit: JSon.Net can embed type information during serialization that can be used during deserialization.
Leave your Args parameter as an Object. Then use the TypeNameHandling option of All during both serialization and deserialization.
var json = JsonConvert.SerializeObject(myObject, Formatting.None,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
You should end up with your Args object as your desired SimpleMailAddress object.
The data contact serializers built into the.net framework have the concept of known types where you tell them what types to expect and it uses those during deserialization.
There is a built in Json data contract serializer but I'm not sure it will be compatible with your Json data, it may need to be serialized and deserialized via a datacontract serializer to work using this method.
Got it. I have to use these settings:
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
};
var json = JsonConvert.SerializeObject(object, Formatting.None, settings);
var object = JsonConvert.DeserializeObject<MailMessageRequest>(message.Body, settings);

c# JavaScriptConverter - how to deserialize custom property?

I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.

Categories

Resources