I have an abstract class named Extension which has several derived classes such as DerivedExtensionA, DerivedExtensionB, etc.
Now I have a list defined as List<Extension> which contains the derived classes instances.
Now if I serialize the above list, it only serializes the base class properties that are in Extension since the list has the base class Extension type. If I define the list as List<DerivedExtensionA> and then put only instances of DerivedExtensionA in it, then they are serialized fine. But my code is generic which is supposed to accept all types of Extensions, so this isn't a workable solution for me.
So question is ..
How do I keep the list defined as List<Extension> and still be able to fully serialize the contained derived class instances that contain ALL their properties ?
Here is a fiddle showing this behavior: https://dotnetfiddle.net/22mbwb
EDIT: Corrected the fiddle URL
From How to serialize properties of derived classes with System.Text.Json
Serialization of a polymorphic type hierarchy is not supported.
In your fiddle you can use an array of objects:
string allExtensionsSerialized =
JsonSerializer.Serialize((object[])allExtensions.ToArray());
This is the hack I used recently:
public record MyType(
// This nonsense is here because System.Text.Json does not support normal polymorphic serialisation
[property: JsonIgnore] List<X> Messages))
{
// This nonsense is here because System.Text.Json does not support normal polymorphic serialisation
[JsonPropertyName("Messages")]
public object[] MessagesTrick => Messages.ToArray();
For deserialisation, I decided used JsonDocument.Parse inside a dedicated FromJson(string json) method. This works OK, for me, in this specific case.
Actually I ended up changing the definition of the list from List<Extension> to List<object>, and the behavior was corrected. This might not be a workable solution for everyone reading this, but it's fine for me so that's why I'm adding my own answer.
Related
I've been working with JSON.net for a while. I have written both custom converters and custom contract resolvers (generally from modifying examples on S.O. and the Newtonsoft website), and they work fine.
The challenge is, other than examples, I see little explanation as to when I should use one or the other (or both) for processing. Through my own experience, I've basically determined that contract resolvers are simpler, so if I can do what I need with them, I go that way; otherwise, I use custom JsonConverters. But, I further know both are sometimes used together, so the concepts get further opaque.
Questions:
Is there a source that distinguishes when to user one vs. the other? I find the Newtonsoft documentation unclear as to how the two are differentiated or when to use one or the other.
What is the pipeline of ordering between the two?
Great question. I haven't seen a clear piece of documentation that says when you should prefer to write a custom ContractResolver or a custom JsonConverter to solve a particular type of problem. They really do different things, but there is some overlap between what kinds of problems can be solved by each. I've written a fair number of each while answering questions on StackOverflow, so the picture has become a little more clear to me over time. Below is my take on it.
ContractResolver
A contract resolver is always used by Json.Net, and governs serialization / deserialization behavior at a broad level. If there is not a custom resolver provided in the settings, then the DefaultContractResolver is used. The resolver is responsible for determining:
what contract each type has (i.e. is it a primitive, array/list, dictionary, dynamic, JObject, plain old object, etc.);
what properties are on the type (if any) and what are their names, types and accessibility;
what attributes have been applied (e.g. [JsonProperty], [JsonIgnore], [JsonConverter], etc.), and
how those attributes should affect the (de)serialization of each property (or class).
Generally speaking, if you want to customize some aspect of serialization or deserialization across a wide range of classes, you will probably need to use a ContractResolver to do it. Here are some examples of things you can customize using a ContractResolver:
Change the contract used for a type
Serialize all Dictionaries as an Array of Key/Value Pairs
Serialize ListItems as a regular object instead of string
Change the casing of property names when serializing
Use camel case for all property names
Camel case all property names except dictionaries
Programmatically apply attributes to properties without having to modify the classes (particularly useful if you don't control the source of said classes)
Globally use a JsonConverter on a class without the attribute
Remap properties to different names defined at runtime
Allow deserializing to public properties with non-public setters
Programmatically unapply (ignore) attributes that are applied to certain classes
Optionally turn off the JsonIgnore attribute at runtime
Make properties which are marked as required (for SOAP) not required for JSON
Conditionally serialize properties
Ignore read-only properties across all classes
Skip serializing properties that throw exceptions
Introduce custom attributes and apply some custom behavior based on those attributes
Encrypt specially marked string properties in any class
Selectively escape HTML in strings during deserialization
JsonConverter
In contrast to a ContractResolver, the focus of a JsonConverter is more narrow: it is really intended to handle serialization or deserialization for a single type or a small subset of related types. Also, it works at a lower level than a resolver does. When a converter is given responsibility for a type, it has complete control over how the JSON is read or written for that type: it directly uses JsonReader and JsonWriter classes to do its job. In other words, it can change the shape of the JSON for that type. At the same time, a converter is decoupled from the "big picture" and does not have access to contextual information such as the parent of the object being (de)serialized or the property attributes that were used with it. Here are some examples of problems you can solve with a JsonConverter:
Handle object instantiation issues on deserialization
Deserialize to an interface, using information in the JSON to decide which concrete class to instantiate
Deserialize JSON that is sometimes a single object and sometimes an array of objects
Deserialize JSON that can either be an array or a nested array
Skip unwanted items when deserializing from an array of mixed types
Deserialize to an object that lacks a default constructor
Change how values are formatted or interpretted
Serialize decimal values as localized strings
Convert decimal.MinValue to an empty string and back (for use with a legacy system)
Serialize dates with multiple different formats
Ignore UTC offsets when deserializing dates
Make Json.Net call ToString() when serializing a type
Translate between differing JSON and object structures
Deserialize a nested array of mixed values into a list of items
Deserialize an array of objects with varying names
Serialize/deserialize a custom dictionary with complex keys
Serialize a custom IEnumerable collection as a dictionary
Flatten a nested JSON structure into a simpler object structure
Expand a simple object structure into a more complicated JSON structure
Serialize a list of objects as a list of IDs only
Deserialize a JSON list of objects containing GUIDs to a list of GUIDs
Work around issues (de)serializing specific .NET types
Serializing System.Net.IPAddress throws an exception
Problems deserializing Microsoft.Xna.Framework.Rectangle
I'm using [webmethod] attribute in an aspx page to expose a complex data structure(autogenerated from xml->xsd->xsd.exe) to the browser.
After I get the data on the client with jquery, only the top level object includes the "__type" attribute, so I cannot determine the class of any of the nested objects(attributes, array content etc).
Is there a way to make the asp.net serializer include the __type attribute recursively when serializing an object?
I encountered a similar situation with another JSON serializer, the one from ServiceStack.Text. They will put in the __type property if an object is declared as an interface or an abstract class, perhaps the vanilla .NET serializer will do so as well? If that's the case, is there any way for you to declare your object[] array as an array of interfaces? Even something as trivial as cerating an IEmpty with no methods will do the trick.
I am relatively new to Web Parts and Web Forms (I have only worked a lot with the MVC framework).
I am planning to store some data in the control state. All the examples I can find put an object[] array in the control state and the base control state on the 0 index.
I don't really like putting everything in an object[], so I wanted to create an extra class for my web part with typed properties: e.g. MyWebPartControlState. I will store the base control state in a property BaseControlState of type object.
I was wondering if this could cause any problems or if there are any other reasons why this might not be a good idea. I am wondering because it feels logical to me, but I cannot find any examples of control state where they don't put everything in the control state directly or in a object[].
Thanks in advance.
The control state is persisted in the same field as view state and follows the same rules for serialization. All the samples you found use an object array because that's one of the types the optimized state serializer in ASP.NET understands and for which is able to optimize serialization.
If you use a custom object the serializer won't use the optimizations and instead will serialize your object using the BinaryFormatter which will lead to bloated control state. If you want to have a strongly typed view of your state you should implement IStateManager on your custom class so that it encapsulates the transformation of itself from and to simple objects that the serializer understands.
If I recall correctly the serializer can efficiently serialize the following types:
Primitive types (int, long, etc);
DateTime;
string;
Boxed values of supported value types;
Object arrays containing instances of supported types;
Pair and Triplet objects containing instances of supported types.
I wrote a short blogpost illustrating the differences in size resulting from a simple custom class being serialized with BinaryFormatter versus implementing IStateManager and decomposing to simple types that the serializer can optimize. You can find it at:
ASP.NET ViewState Tips and Tricks #2
In Actionscript 3, why does getDefinitionByName() return an Object when the docs say:
Returns a reference to the class object of the class specified by the name parameter.
Based on that, I would conclude that the returned object should be Class instead of Object. Can someone enlighten me why that is not the case?
getDefinitionByName can also return a Function, such as getDefinitionByName('flash.utils.getDefinitionByName').
This only works on namespace-level functions, though, not static class methods.
Despite the method signature, getDefinitionByName does return Class. I think the misleading signature is due to the method existing before the Class object (when it used to return an anonymous/extended object instance).
Perhaps Adobe considered that this function might return different values in a future version of Flash Player. For instance, ECMAScript, the standard on which ActionScript is based, has historically used Function objects with prototypes as the basis for class-like objects. During discussions of the newest versions of the ECMAScript standard, there has been sugestions for "freezing" function-based classes at run-time to make them into something like compile-time Class objects. What if you could also specify a definition name for them? Are they actually of type Class at this point, or are they still or type Function? Probably the later, in my opinion. Both 'Class' and 'Function' references can be generalized as Object, so that return type makes sense in this context.
Note: This explanation is purely speculation based on what I've read in the ECMAScript specification wiki and the blogs of various committee members.
What options are there for serialization when returning instances of custom classes from a WebService?
We have some classes with a number of child collection class properties as well as other properties that may or may not be set depending on usage. These objects are returned from an ASP.NET .asmx WebService decorated with the ScriptService attribute, so are serialized via JSON serialization when returned by the various WebMethods.
The problem is that the out of the box serialization returns all public properties, regardless of whether or not they are used, as well as returning class name and other information in a more verbose manner than would be desired if you wanted to limit the amount of traffic.
Currently, for the classes being returned we have added custom javascript converters that handle the JSON serializtion, and added them to the web.config as below:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="CustomClassConverter" type="Namespace.CustomClassConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
But this requires a custom converter for each class. Is there any other way to change the out of the box JSON serialization, either through extending the service, creating a custom serializer or the like?
Follow Up
#marxidad:
We are using the DataContractJsonSerializer class in other applications, however I have been unable to figure out how to apply it to these services. Here's an example of how the services are set-up:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
The WebMethods are called by javascript and return data serialized in JSON. The only method we have been able to change the serialization is to use the javascript converters as referenced above?
Is there a way to tell the WebService to use a custom DataContractJsonSerializer? Whether it be by web.config configuration, decorating the service with attributes, etc.?
Update
Well, we couldn't find any way to switch the out of the box JavaScriptSerializer except for creating individual JavaScriptConverters as above.
What we did on that end to prevent having to create a separate converter was create a generic JavaScriptConverter. We added an empty interface to the classes we wanted handled and the SupportedTypes which is called on web-service start-up uses reflection to find any types that implement the interface kind of like this:
public override IEnumerable<Type> SupportedTypes
{
get
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder;
if (dynamicAssemblyCheck == null)
{
foreach (Type type in assembly.GetExportedTypes())
{
if (typeof(ICustomClass).IsAssignableFrom(type))
{
yield return type;
}
}
}
}
}
}
The actual implementation is a bit different so that the type are cached, and we will likely refactor it to use custom attributes rather than an empty interface.
However with this, we ran into a slightly different problem when dealing with custom collections. These typically just extend a generic list, but the custom classes are used instead of the List<> itself because there is generally custom logic, sorting etc. in the collection classes.
The problem is that the Serialize method for a JavaScriptConverter returns a dictionary which is serialized into JSON as name value pairs with the associated type, whereas a list is returned as an array. So the collection classes could not be easily serialized using the converter. The solution for this was to just not include those types in the converter's SupportedTypes and they serialize perfectly as lists.
So, serialization works, but when you try to pass these objects the other way as a parameter for a web service call, the deserialization breaks, because they can't be the input is treated as a list of string/object dictionaries, which can't be converted to a list of whatever custom class the collection contains. The only way we could find to deal with this is to create a generic class that is a list of string/object dictionaries which then converts the list to the appropriate custom collection class, and then changing any web service parameters to use the generic class instead.
I'm sure there are tons of issues and violations of "best practices" here, but it gets the job done for us without creating a ton of custom converter classes.
If you don't use code-generated classes, you can decorate your properties with the ScriptIgnoreAttribute to tell the serializer to ignore certain properties. Xml serialization has a similar attribute.
Of course, you cannot use this approach if you want to return some properties of a class on one service method call and different properties of the same class on a different service method call. If you want to do that, return an anonymous type in the service method.
[WebMethod]
[ScriptMethod]
public object GimmieData()
{
var dalEntity = dal.GimmieEntity(); //However yours works...
return new
{
id = dalEntity.Id,
description = dalEntity.Desc
};
}
The serializer could care less about the type of the object you send to it, since it just turns it into text anyway.
I also believe that you could implement ISerializable on your data entity (as a partial class if you have code-gen'd data entities) to gain fine-grained control over the serialization process, but I haven't tried it.
I know this thread has been quiet for a while, but I thought I'd offer that if you override the SupportedTypes property of JavaScriptConverter in you custom converter, you can add the types that should use the converter. This could go into a config file if necessary. That way you wouldn't need a custom converter for each class.
I tried to create a generic converter but couldn't figure out how to identify it in the web.config. Would love to find out if anyone else has managed it.
I got the idea when trying to solve the above issue and stumbled on Nick Berardi's "Creating a more accurate JSON .NET Serializer" (google it).
Worked for me:)
Thanks to all.
If you're using .NET 3.x (or can), a WCF service is going to be your best bet.
You can selectively control which properties are serialized to the client with the [DataMember] attribute. WCF also allows more fine-grained control over the JSON serialization and deserialization, if you desire it.
This is a good example to get started: http://blogs.msdn.com/kaevans/archive/2007/09/04/using-wcf-json-linq-and-ajax-passing-complex-types-to-wcf-services-with-json-encoding.aspx
You can use the System.Runtime.Serialization.Json.DataContractJsonSerializer class in the System.ServiceModel.Web.dll assembly.
Don't quote me on this working for certain, but I believe this is what you are looking for.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public XmlDocument GetXmlDocument()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(_xmlString);
return xmlDoc;
}