ASP.NET json serializer only includes __type for top level class - asp.net

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.

Related

System.Text.Json serialization not using derived classes

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.

Why does [Serializable] cause Newtonsoft.Json serializer to include backing fields?

If I have [Serializable] attribute on a class then it causes the resulting serialised Json string to include backing members created by the framework.
For example I get below for my Id field:
<Id>k__BackingField=20001
I could find many resources on SOF and elsewhere to get around this problem but I couldn't find why Json serializer is behaving differently when it sees [Serializable] attribute.
If the Jason serializer doesn't serialise members and only serialise properties then why does it behave differently when a class is decorated with [Serializable] attribute?
Please note I'm not looking for a way to fix this issue as I have already found that. I would like to know why Newtonsoft.Jsonserialiser behaves differently here.
In case someone wants to find the reason in the future, following explains how objects are serialised by Json.Net:
Breakdown of Type Serialization > Objects
By default a type's properties are serialized in opt-out mode. What
that means is that all public fields and properties with getters are
automatically serialized to JSON, and fields and properties that
shouldn't be serialized are opted-out by placing JsonIgnoreAttribute
on them. To serialize private members, the JsonPropertyAttribute can
be placed on private fields and properties.
Types can also be serialized using opt-in mode. Only properties and
fields that have a JsonPropertyAttribute or DataMemberAttribute on
them will be serialized. Opt-in mode for an object is specified by
placing the JsonObjectAttribute or DataContractAttribute on the type.
Finally, types can be serialized using a fields mode. All fields, both
public and private, are serialized and properties are ignored. This
can be specified by setting MemberSerialization.Fields on a type with
the JsonObjectAttribute or by using the .NET SerializableAttribute and
setting IgnoreSerializableAttribute on DefaultContractResolver to
false.

JSON.net ContractResolver vs. JsonConverter

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

Serialize to ASP.NET ViewState using DataContract/DataMember attributes of EF POCOs

I have a series of EF POCOs which have DataContract attributes, and DataMember attributes for all the properties, except for the navigation properties.
In this way, when I serialize the objects for WCF, only the desired properties are serialized, leaving out the navigation properties.
If I try to store one of these objects in ViewState I get the error that the object is not serializable. But, if I add the Serializable attribute to the object, the serializer tries to serialize also all the navigation properties, which, in turn requires them to be marked also as serializable.
Is there a way to force the ViewState (StateBag) to use the DataContract attributes? Is it possible to customize or replace the ViewState serialization?
If it's not possible, would I have to used the Selializable attribute for the classes, and the NotSerialized for all the navigation properties or is there a better solution?
There is a better solution - not to mix domains. When you serialize objects for WCF you are entering a different domain - the domain of Data Transfer Objects, DTOs in short.
DTOs are separate from your persisting objects, they don't have complex navigation properties, rather - contain the only data needed at the client side.
A commin practice is to use Automapper or a similar subsystem to easily convert from/to DTOs.
http://en.wikipedia.org/wiki/Data_transfer_object

How to implement custom JSON serialization from ASP.NET web service?

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;
}

Resources