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.
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 have a class that inherits from JsonConverter:
JsonDataBagCreationConverter<T> : JsonConverter where T : IDataBag
I have a class Company that implements IDataBag
When I deserialize a single property of Company JsonDataBagCreationConverter has its ReadJson method invoked as I expect.
When I deserialize an array of Company, JsonDataBagCreationConverter has its ReadJson method invoked as I expect.
It also works for generic lists of Company.
But for certain containers of Company json.net will not recognize that the contents of the list is of type Company. So JsonDataBagCreationConverter is not used when I deserialize.
ie containers of type
System.Collections.DictionaryEntry,
System.Collections.ArrayList,
System.Collections.Hashtable,
System.Collections.SortedList
that stores Company objects.
I know that these containers are non-generic.
Is it possible to make the (de-)serializer look at the contents of these containers and use the JsonDataBagCreationConverter when the contents is Idatabag (ie a company)?
Best regards
Jan
Remove the where T : IDataBag from the converter and override CanConvert and write your logic to check your type there and accordly return true or false.
I'm switching from InProc session to SQL server session. Currently, my session object looks like this:
public class UserSession{
public string TheStrings {get;set;}
public int TheInts {get;set;}
public List<MyObjectModel> ListOfObjects {get;set;}
}
It basically holds strings, ints and several lists of objects. What I do is store this object in the session and then when I need to access the session, I can write UserSession.TheStrings.
Now that I'm cconverting this to SQL session, serialization comes in play. Do I need to add the [serializable] attribute only to the entire class or do I also need to add it to the class definition of all the MyObjectModels as well?
Thanks.
I am pretty sure it will serialize by default as long as everything in your objects are simple types.
SerializableAttribute Class
Apply the SerializableAttribute attribute to a type to indicate that
instances of this type can be serialized. The common language runtime
throws SerializationException if any type in the graph of objects
being serialized does not have the SerializableAttribute attribute
applied.
Apply the SerializableAttribute attribute even if the class also
implements the ISerializable interface to control the serialization
process.
All the public and private fields in a type that are marked by the
SerializableAttribute are serialized by default, unless the type
implements the ISerializable interface to override the serialization
process. The default serialization process excludes fields that are
marked with the NonSerializedAttribute attribute. If a field of a
serializable type contains a pointer, a handle, or some other data
structure that is specific to a particular environment, and cannot be
meaningfully reconstituted in a different environment, then you might
want to apply the NonSerializedAttribute attribute to that field.
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;
}