Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

DataContractJsonSerializer in .NET 3.5


:P
On this page:

.NET 3.5 now includes a JSON serializer in DataContractJsonSerializer. This useful little component makes it pretty painless to create JSON from objects and back. Here's some code to serialize and deserialize JSON to a string and back:

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {        
        Customer person = new Customer();
        person.Name = "John Jones";
        person.Entered = new DateTime(2007, 10, 10);

        person.Addresses.Add(new Address());
        person.Addresses.Add( new Address() );
        
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Customer));        
        MemoryStream ms = new MemoryStream();
        ser.WriteObject(ms, person);        

        string json = Encoding.Default.GetString(ms.ToArray());
        ms.Close();
        Response.Write("<pre>" + Server.HtmlEncode(json) + "</pre>");
        

        // *** Start from scratch with deserialization        
        //ms = new FileStream(Server.MapPath("jsonoutput.txt"), FileMode.Open);
        ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
        
        ser = new DataContractJsonSerializer(typeof(Customer)); 
        Customer person2 = ser.ReadObject(ms) as Customer;
        ms.Close();        

        Response.Write(person2.Name);
    }

    [Serializable]
    public class Customer
    {
        public string Name = "John";
        public DateTime Entered = DateTime.Now;
        public List<Address> Addresses = new List<Address>();        
    }

    [Serializable]
    public class Address
    {
        public string Street = "32 Kaiea Place";
        public string City = "Paia";
        public string State = "HI";
        public string Zip = "96779";

    }
}

Like most other serializers in .NET, to serialize you provide the Type to serialize and a Stream to serialize into. Here a memory stream is used to read the content into a string. To go back the reverse is used - load the string into a memory stream then read the stream and deserialize back into an object.

The output generated is plain old JSON (ie. not MS AJAX style hopped up JSON <g>) (marked up a bit here to make it more readable):

{"Addresses":[{"City":"Paia","State":"HI","Street":"32 Kaiea Place","Zip":"96779"},
{"City":"Paia","State":"HI","Street":"32 Kaiea Place","Zip":"96779"}],
"Entered":"\/Date(1192010400000-1000)\/","Name":"John Jones"}

The good news is that the serializer does fairly well with plain old .NET objects and collections/dictionaries. As you can see above it turned the List of objects into an array that can be consumed on the client and can be turned back into the list on the return trip.

Two way serialization like this makes perfect sense but you should also be able to utilize this functionality in retrieving generic JSON data from the client and feed it to the server to deserialize. This can be pretty handy especially if you are NOT using MS AJAX or even any other framework or simply need to return JSON as an alternate output mechanism (say in an MVC Framework request).

Deserialization works based on a .NET  signature which the incoming JSON data has to match. This means that as long as the inbound JSON object matches the type signature of the type you want to create, the deserialization will work. What's nice is that the JSON signature doesn't have to match exactly. So if GetPerson() is expecting a Person object and the client only sends the Name and Entered the deserialization still works.

I'm glad this works because this is a common scenario in AJAX client applications where you often just send data that you actually changed rather than everything back to the server and since it's so damn easy in JavaScript to create objects on the fly it's easy to parcel up data that you want to update in a small object map.

The other reason this is important is because unlike a standalone Web application a WCF service that's using WebHttpBinding doesn't have access to the actual POST buffer so you can't just pick up regular POST variables for example. Even though there's WebOperationContext that's accessible as part of a WCF WebHttp service this object doesn't have access to the POST  entity body, so the only effective way to pass data to the server with such a service is via the parameter payload. Using JSON on the client and sending it to the server becomes the most effective way to do this.

Couple other things of note: DataSets will serialize, but they serialize as an XML string not as an array of rows of objects, which would have been preferable. As it is using a DataSet client side in AJAX like this isn't going to be terribly useful unless you load the contents into a DOM and parse it that way. Not bloody likely <s>...

Fortunately in .NET 3.5 it's also fairly easy to take a DataSet and turn it into a List of typed objects with something like this:

List<Customer> custResult =
   (from c in ds.Tables["CustomerList"].AsEnumerable()
    where c.Field<string>("Company").CompareTo("B") > 0
    select new Customer { 
Name = c.Field<string>("Company"), Entered = c.Field<DateTime?> ("Entered") } ).ToList();

which then CAN be serialized. But of course the object returned must have the Customer type defined in some way first for this to work.

Note also that Anonymous types cannot be serialized because they are not marked as Serializable, so the following does NOT work:

var TPerson = new { Name = "Rick", Company = "West Wind", Entered = DateTime.Now };

 

DataContractJsonSerializer ser1 = new DataContractJsonSerializer( TPerson.GetType() );       

MemoryStream ms1 = new MemoryStream();

ser1.WriteObject(ms1,TPerson);       

 

string json1 = Encoding.Default.GetString(ms1.ToArray());

Response.Write(json1);

ms1.Close();

Shame that because this would could be quite useful in some scenarios for data shaping and returning a final response back to a client that is a stripped down and focused type rather than say a full customer object. I wish there was some way to force anonymous types to be created with a Serializable flag.

Note also that the DataContractSerializer does not generate JSON that can be directly consumed by MS AJAX. MS AJAX serialized JSON objects look a little bit different:

{"d":{"__type":"ScriptCallbacks.BusinessObjects.CustomerEntity",
"PhoneNumbers":{
"HomePhone":"(503) 121-1212",
"WorkPhone":"(503) 333-1222",
"Entered":"\/Date(1198908717056)\/"},
"Orders":null,
"Customerid":"ANTON",
"Companyname":"Antonio Moreno Taqueria",
"Contactname":"Antonio Moreno",
"Contacttitle":"Owner"
}
}

Note that MS AJAX generates a top level object and then injects a __type property into the actual object's data. Funky... and one of the main reason I really don't like working with MS AJAX. It's just not compatible with anything but itself and makes direct client syntax quite funky.

I don't see a way to make the DataContractJsonSerializer creat MS AJAX style automatically, but if you use the WCF Serialization mechanics (WebHttpBinding) it has options to generate MS AJAX style JSON via the enableWebScript or using WebScriptServiceFactory configuration. Unfortunately there are conflicts between various service attributes (UriTemplate can't be used with script services for example) that make it difficult to reuse a single service both ways. <shrug> One more reason how the proprietary MS Ajax JSON format complicates matters. I'll have more on the various WCF service models that allow serving JSON in a later post.

I was toying with the idea of using this serializer to replace the one I've built for my libraries (in wwHoverPanel), but given the fact that it won't deal with DataSets/DataRow in a meaningful way, and that you can't serialize anything that isn't explicitly typed puts a crimp in my existing code. I have some code that returns anonymous types returned from LINQ to be passed to the AJAX client and I'm not inclined to give that up. It's extremely useful in a number of business object result scenarios.

But overall it's very cool that this functionality has been baked into the .NET framework like this. The DataContractJsonSerializer is easy to use and it's now easy to create JSON service type behavior from just about anywhere. I think the MVC Framework in particular can benefit from this providing a relatively easy mechanism for creating JSON views for example.

Posted in ASP.NET  WCF  AJAX  

The Voices of Reason


 

Hernan Garcia
December 29, 2007

# re: DataContractJsonSerializer in .NET 3.5

Interesting article, I'm using the free Json.Net library from Newtonsoft and it works really well. Upon reading your post I think that It still needs some work, the same problems that you mentioned (not working with Dataset and Anonymous types) make me wonders the real value of this. I have been using JSON a lot latelly, specially to interface with some PHP applications and AJAX apps that use prototype, I need to be able to serialize everything, I think I will continue using Json.NET for the time being.

Rick Strahl
December 29, 2007

# re: DataContractJsonSerializer in .NET 3.5

Well, I suppose it's consistent with how the other serializers work in .NET - they are all dependent on type information and the primary target of the serializer - as the name suggests - is for WCF style serialization which is almost entirely based on type mapping. So it makes some sense.

Still it would be nice to at least support outbound data that isn't strongly typed to start with. Any object that can be reflected over (within reason) should be exportable. This is especially true now with LINQ and the potential for lots of results coming back semi-dynamically generated. Don't think that's going to change though <g>...

laimis
December 31, 2007

# re: DataContractJsonSerializer in .NET 3.5

Do you know if this is much different from JavaScriptSerializer class that came with web extensions assembly? I used it extensively to create JSON object string in ASP.NET 2.0 apps. From your code sample it seems like the class does the same thing, just the name, DataContract is a bit confusing ... should be just simple JsonSerializer, IMO...

Roger Jennings
December 31, 2007

# re: DataContractJsonSerializer in .NET 3.5

Rick,

I've extendend your code into a small test harness with some larger objects and was surprised to find that JSON serialization isn't as lightweight a process as I had expected.

See http://oakleafblog.blogspot.com/2007/12/json-vs-xml-datacontract-serialization.html

Happy New Year!

--rj

Rick Strahl
December 31, 2007

# re: DataContractJsonSerializer in .NET 3.5

@Roger - awesome work checking out the perf considerations. I suppose it's to be expected that JSON is slower since the parsing of the JSON objects is necessarily a bit more complex than parsing the more XML so I'm not terribly surprised that it's slower than XML.

OTOH, you're not likely to use this on two way WCF communications, but only for AJAX/REST scenarios coming from a browser most likely and in that scenario there's not much choice since JSON is so much easier to use on the client than XML.

@laimis - I haven't looked at the JavaScript Serializer recently but I believe that serializer is specific to MS Ajax meaning it creates the special object structure that includes the top level root object with the type information embedded in the top level object's property list.

As to DataContractJsonSerializer - it's consistent with all of the 'new' serializers that are in .NET 3.0 and that work with WCF. Rather than XmlSerializer there's the DataContractSerializer for example and there are definite improvements in these new serializers such as the ability to deal with recursive object references...

Rick Strahl
December 31, 2007

# re: DataContractJsonSerializer in .NET 3.5

Ok, so I checked JavaScriptSerializer briefly here as well and it produces plain JSON output as well (ie. not MS AJAX style formatting and type info). It works directly off strings so it's a little easier yet to use:

Customer person = new Customer();
person.Name = "John Jones (JavaScriptSerializer)";
person.Entered = new DateTime(2007, 10, 10);

person.Addresses.Add(new Address());

Address addr = new Address();
addr.Street = "501 N. 15th Street";
addr.City = "Hood River";
addr.State = "OR";
addr.Zip = "97031";
person.Addresses.Add(new Address());

JavaScriptSerializer ser = new JavaScriptSerializer();
string json = ser.Serialize(person);
Response.Write("<pre>" + Server.HtmlEncode(json) + "</pre>");


ser = new JavaScriptSerializer();                
var person2 = ser.Deserialize<Customer>(json);

Response.Write(person2.Name);


The JavaScriptSerializer, unlike the DataContractSerializer, also works with anonymous types or any object structure for that matter because you pass in an object parameter for serialization and don't provide the type information.

Vijay Santhanam
January 03, 2008

# re: DataContractJsonSerializer in .NET 3.5

Is there any reason to use DataContractJsonSerializer over JavaScriptSerializer except for the fact it's deprecated?

Seems like JavaScriptSerializer is better because it supports anonymous types.

Coming back to the __type and "d" JSON decorations in AJAX.ASP.NET, I think that comes from the JavaScriptTypeConverter that is implemented by the cached WebServiceData instances in ASP.NET.

I concur that these serializers are great for the MVC. We can create a general view page that just spits out JSON. I'd like to see a post by you that uses JSON in MVC. I've played with a few AJAX controller configurations (WebServices, AjaxBaseControllers and SpecializedAjaxControllers) but I'm not terribly happy with any of them. I'm interested to see how you approach it.

Vijay Santhanam
January 03, 2008

# re: DataContractJsonSerializer in .NET 3.5

DataContractJsonSerializer serializes datetimes in a UTC format as opposed to JavaScriptSerializer too.

JavaScriptSerial:
{"Name":"Mr Normal","Address":{"Street":"32 Kaiea Place","City":"Paia","State":"
HI","PostalCode":"96779"},"Created":"\/Date(1199376441686)\/"}

DataContractJson:
{"Address":{"City":"Paia","PostalCode":"96779","State":"HI","Street":"32 Kaiea P
lace"},"Created":"\/Date(1199376410358+1100)\/","Name":"Mr WCF"}

I know JSON doesn't support datetime literals but DataContract seems to deserialize it's own serialized dates correctly - which is a bonus. Up till now, I've avoided DateTime serialization. I might mod the .ToJSON jQuery plugin to handle this correctly. datejs is too big for my liking.

Rick Strahl
January 03, 2008

# re: DataContractJsonSerializer in .NET 3.5

Vijay, the DataContract Serializer seems to understand both methods.

I've updated my serializer both on the server and on the client to support a variety of date formats. It's in the West Wind Ajax Toolkit codebase (formerly wwHoverPanel):

Basically I've added this parsing code to Dean Edwards JSON parser:

To parse:
    parse: function (text) {
    try {
         if (!(!(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                 text.replace(/"(\\.|[^"\\])*"/g, '')))  ))
                 return false;
        
        // *** RAS Update:  Fix up Dates: ISO and MS AJAX format support
        var regEx = /(\"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}.*?\")|(\"\\\/Date\(.*?\)\\\/")/g;
        text = text.replace(regEx,this.regExDate);      
        
        return eval('(' + text + ')');    


RegEx evaluator function:
    // *** RAS Update: RegEx handler for dates ISO and MS AJAX style
    regExDate: function(str,p1, p2,offset,s) 
    {
        str = str.substring(1).replace('"','');
        var date = str;
        
        if (str.substring(0,7) == "\\\/Date(") {  // MS Ajax date: /Date(19834141)/       
            str = str.match(/Date\((.*?)\)/)[1];                        
            date = "new Date(" +  parseInt(str) + ")";
        }
        else { // ISO Date 2007-12-31T23:59:59Z                                     
            var matches = str.split( /[-,:,T,Z]/);        
            matches[1] = (parseInt(matches[1],0)-1).toString();                     
            date = "new Date(Date.UTC(" + matches.join(",") + "))";         
       }                  
        return date;
    },


To encode:
case 'object':
if (x) {
 // RAS: Added Date Parsing
 if (x.toUTCString)
     return e('\"\\/Date(' + x.getTime() + ')\\/\"' ); // MS Ajax style
     //return e('new Date(' + x.getTime() + ')' );

Tom Brothers
January 03, 2008

# re: DataContractJsonSerializer in .NET 3.5

I'm a little off topic here... but do you have any suggestions for a good WCF book?

Rick Strahl
January 03, 2008

# re: DataContractJsonSerializer in .NET 3.5

Michelle Leroux Bustamonte's book from O'Reilly is a great book for getting started as well as providing lots of depth. I also like Juval Lowry's book but it's a more theorhetical and delves deep into the details of the inner workings.

Kevin Davis
February 13, 2008

# re: DataContractJsonSerializer in .NET 3.5

Rick,

Thanks for your example the new DataContractJsonSerializer. However, I am having problems trying to use this. I am using VS 2008, and I select 3.5 framework and I cannot find this new class. I am working in VB.NET (please do not laugh to loud) so this might be the issue...I am at wits to why I cannot find it.

Aloha,

Kevin

Rick Strahl
February 14, 2008

# re: DataContractJsonSerializer in .NET 3.5

Make sure you add the .NET 3.5 version of System.Runtime.Serialization to your references.

http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx

Kevin Davis
February 14, 2008

# re: DataContractJsonSerializer in .NET 3.5

Rick,

Thanks for your response. I tried this before, and as I look up the assemblies under the C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5 I cannot find it. Is this part of the new VS 2008 load? I selected v 3.5 when creating this project. Any suggestions are appreciated!

Aloha,

Kevin

Rick Strahl
February 14, 2008

# re: DataContractJsonSerializer in .NET 3.5

I think DataContractSerializer is a 3.0 assembly, but I could be wrong. It should be in your GAC component list. Make sure your app is set to .NET 3.5 (or 3.0).

Kevin Davis
February 15, 2008

# re: DataContractJsonSerializer in .NET 3.5

Rick,

Mahalo! I found the DataContractSerializer, however I could not find the DataContractJsonSerializer, it is is the 3.0 assembly. I have set my app to .NET 3.5. Sorry to keep on bothering you with these crazy questions.

Aloha,

Kevin

Rick Strahl
February 15, 2008

# re: DataContractJsonSerializer in .NET 3.5

System.ServiceModel.Web.dll

The MSDN documentation is your friend, Kevin. <g>

Kevin Davis
February 18, 2008

# re: DataContractJsonSerializer in .NET 3.5

Rick, you are correct, MSDN is our friend <g> I have one question, my JSON is returning the private members from my class. Is this correct? Here is my copy of my returning Web Service XML: <?xml version="1.0" encoding="utf-8" ?>
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d1p1:type="q1:string" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">{"m_artist":"The Beatles","m_dateTime":"\/Date(1203366997011-1000)\/","m_releaseDate":1967,"m_title":"Sgt Pepper's Lonely Hearts Club Band","m_tracks":["Sgt Pepper's Lonely Hearts Club Band","Little Help From My Friends",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}</anyType>

Aloha,

Kevin

Justin
February 20, 2008

# re: DataContractJsonSerializer in .NET 3.5

So we all know about the problems of using eval() to parse json strings with in javascript. Does anybody have any recommendations for a good javascript json serializer? I have always manually created xml on the client side to create data to post back to the server. Now that we can deserialize json on the server it seems more logical to use json as the transport protocol.

Justin
February 21, 2008

# re: DataContractJsonSerializer in .NET 3.5

Well I looked at the West Wind AJAX Toolkit. I found jason2.js from http://www.JSON.org/js.html

It works for my app, I did not try dates or any complex items. I guess I will get over that hurdle when I come to it.

Thanks a lot Rick for all of your work, your blog rocks.

Rick Strahl
February 21, 2008

# re: DataContractJsonSerializer in .NET 3.5

Yeah Jason2.js works but you will have issues with dates because it only uses ISO string format and the .NET side of things will only pick that up as a date string.


You can grab wwScriptLibrary.js and pick out the JSON class from the code which is free standing (including the above updates). It's based on the original json.js file from Crockford, but adjusted to support .NET style string date formatting.

Vadim
March 17, 2008

# re: DataContractJsonSerializer in .NET 3.5

Anybody succedeed in passing inherited types?(Animal : {Name, Age}, Cat : Animal, Dog : Animal) I'm interested in having WCF on the server side and Silverlight 2 on the client one. Meeting up with different serializers again.

Rick Strahl
March 17, 2008

# re: DataContractJsonSerializer in .NET 3.5

@Vadim - what exactly doesn't work? If I change the code above to:

            [Serializable]
            public class Person
            {
                public string Name = "Jim";
                public DateTime Entered = DateTime.Now;
            }

            [Serializable]
            public class Customer : Person
            {
                public List<Address> Addresses = new List<Address>();
            }

            [Serializable]
            public class Address
            {
                public string Street = "32 Kaiea Place";
                public string City = "Paia";
                public string State = "HI";
                public string Zip = "96779";

            }


and serialize that works fine. You do have to make sure that all types in the inheritance structure are marked either as [Serializable] or with [DataContract] attributes to allow for serialization.

Josef Stadelmann
June 04, 2008

# re: DataContractJsonSerializer in .NET 3.5

I have serialized successfully an instance of YELEM but have an exception with Deserialisation

Encountered unexpected character '<'.

source is: System.Runtime.Serialization


<System.Runtime.InteropServices.ProgId("XELEM_NET.YELEM")> _
<DataContract(Name:="YELEM")> Public Class YELEM

    <DataMember(Name:="key")> Public fldnam As String
    <DataMember(Name:="val")> Public fldval As String

    Private Sub Class_Initialize_Renamed()
    End Sub
    Public Sub New()
        MyBase.New()
        Class_Initialize_Renamed()
    End Sub

    Private Sub Class_Terminate_Renamed()
    End Sub
    Protected Overrides Sub Finalize()
        Class_Terminate_Renamed()
        MyBase.Finalize()
    End Sub

End Class


The object when serialized lookes pritty good
<root type="object">
  <key>Target</key> 
  <val>WmbCreate()</val> 
  </root>


' here calling serializer and deserializer (and serializer works)
        Dim yele As New WebSpSe.YELEM : yele.fldnam = "Target" : yele.fldval = "WmbCreate()"
        Dim jdcs As New DataContractJsonSerializer(GetType(WebSpSe.YELEM))
        WriteObjectWithInstance2(jdcs, yele, "JsonDatacontract.xml")
        '        Dim wscol2jd As WebSpSe.YWSCOL = CType(ReadObjectWithInstance(jdcs, "JsonDatacontract.xml"), WebSpSe.YWSCOL)
        Dim ele2 As WebSpSe.YELEM = CType(ReadObjectWithInstance2(jdcs, "JsonDatacontract.xml"), WebSpSe.YELEM)
        Console.WriteLine("Element is : " + ele2.fldnam.ToString + "   " + ele2.fldval.ToString)
'more caller code ......


'this fails
Private Function ReadObjectWithInstance2(ByVal xm As XmlObjectSerializer, _
                                            ByVal fileName As String) As WebSpSe.YELEM
        Console.WriteLine(xm.GetType())
        Dim fs As New FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read)
        fs.Position = 0
        Dim ele As WebSpSe.YELEM = xm.ReadObject(fs)     'exception as showm ..... why
        fs.Close()
        Console.WriteLine("Done reading {0}", fileName)
        Return ele

    End Function


The stack:
at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, XmlException exception)
at System.Runtime.Serialization.Json.XmlJsonReader.ReadAttributes()
at System.Runtime.Serialization.Json.XmlJsonReader.ReadNonExistentElementName(StringHandleConstStringType elementName)
at System.Runtime.Serialization.Json.XmlJsonReader.Read()
at System.Xml.XmlBaseReader.IsStartElement()
at System.Xml.XmlBaseReader.IsStartElement(XmlDictionaryString localName, XmlDictionaryString namespaceUri)
at System.Runtime.Serialization.XmlReaderDelegator.IsStartElement(XmlDictionaryString localname, XmlDictionaryString ns)
at System.Runtime.Serialization.XmlObjectSerializer.IsRootElement(XmlReaderDelegator reader, DataContract contract, XmlDictionaryString name, XmlDictionaryString ns)
at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalIsStartObject(XmlReaderDelegator reader)
at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)


For a hint very thanks
Josef.Stadelmann
@axa-winterthur.ch

#.think.in
June 15, 2008

# AdRotator: Json serialization

AdRotator: Json serialization

Daniel Mentz
June 27, 2008

# re: DataContractJsonSerializer in .NET 3.5

Thanks for this great blog post.

I tried this out on my machine and I ran into problems regarding character encoding.

You're using the following statement to convert the contents of the MemoryStream to a string.

string json = Encoding.Default.GetString(ms.ToArray());


This does not work for me. German umlauts get corrupted. I *guess* that Encoding.Default is iso-8859-1 whereas DataContractJsonSerializer uses UTF-8 to write to the stream.

string json = Encoding.UTF8.GetString(ms.ToArray());


works for me.

The Hell *I* Say
July 07, 2008

# re: DataContractJsonSerializer in .NET 3.5

It saddens me that the simple and straightforward and easy to use JavaScriptSerializer is marked as "obsolete" and is being replaced by the poorly named and pretty unfriendly to use DataContractJsonSerializer.

I am sure there are really good reasons for this... but keeping the old JavaScriptSerializer interface should have been possible. It was a better interface to program against.

At least in .Net 3.5 with extension methods you can create your own versions of the Serialize() and Deserialize<T>() methods on top of the DataContractJsonSerializer.

Usualdosage
July 18, 2008

# re: DataContractJsonSerializer in .NET 3.5

If you're into Extension methods, you might like these that I put together to encapsulate the the DataContractJsonSerializer...

public static string ToJSON( this object obj )
{
    if ( !IsSerializable(obj) )
    {
        throw new Exception("Target object must be serializable.");
    }
    string json = string.Empty;
    DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
    using ( MemoryStream ms = new MemoryStream() )
    {
        ser.WriteObject(ms, obj);
        json = Encoding.Default.GetString(ms.ToArray());
    }
    return json;
}


...And

public static T FromJSON<T>( this string json )
        {
            using ( MemoryStream ms = new MemoryStream(ASCIIEncoding.Default.GetBytes(json)) )
            {
                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
                return (T)ser.ReadObject(ms);
            }
        }


..And, to ensure an object is indeed serializable...

public static bool IsSerializable( this object obj )
{
    MemoryStream ms = null;
    BinaryFormatter bf = null;
    try
    {
        ms = new MemoryStream();
        bf = new BinaryFormatter();
        bf.Serialize(ms, obj);
        return true;
    }
    catch ( System.Runtime.Serialization.SerializationException )
    {
        return false;
    }
    catch ( Exception exc )
    {
        throw exc;
    }
    finally
    {
        ms.Close();
        ms.Dispose();
    }
}


...And to tie it all together...

public static void RegisterJSONObject( this Page page, object obj, string objectJSName )
{
    string key = Guid.NewGuid().ToString();
    StringBuilder sb = new StringBuilder();
    sb.Append("var jsonText = '" + obj.ToJSON() + "'\n");
    sb.Append("var " + objectJSName + " = eval('(' + jsonText + ')');\n");
    page.ClientScript.RegisterStartupScript(page.GetType(), key, sb.ToString(), true);
}


Hope it helps!

Roger Pence
November 01, 2008

# re: DataContractJsonSerializer in .NET 3.5

Rick--

Just a quick thanks for your great blog. It has helped me many times. Keep up the good work!

If you ever get to San Antonio, I'm good for a cold beverage or two!

rp

W
December 09, 2008

# re: DataContractJsonSerializer in .NET 3.5

After reading this article, I've been trying to find out how to access the session state using a handler via JSON.

1] Browser has ASP.NET SessionStateId (SSId ) in a Cookie
2] Extract SSId From Cookie
3] Send SSId via JSON to an HTTP Handler
4] *Not quite sure how to access Session State and all the info in the Session w/ the SSId *

Any small help would be nice.

Thanks!

Zubin
May 19, 2009

# re: DataContractJsonSerializer in .NET 3.5

I have recently been doing a lot of work with the DataContractJsonSerializer and ended up writing some code that others may find useful. I had a base class which had some behaviors on . Anyone deriving from my base class needed to set some properties.
<a href="http://www.webtrafficroi.com/site-optimisation-tips/">ZK@Web Marketing Blog</a>

Saikrishnan
October 14, 2009

# re: DataContractJsonSerializer in .NET 3.5

The article was very useful. but i have a small problem.
I already have the data in xml format.

The problem is can I convert the XML to JSON using DataContractSerializer Class.

Riza Marhaban
October 22, 2009

# re: DataContractJsonSerializer in .NET 3.5

Hi Rick,

Nice article. What I don't understand is what's the different between DataContractJsonSerializer and Json.Net. SHould I use DataContractJsonSerializer or Json.Net since lots of answer on a forums always said to use Json.Net instead. I cannot find the difference and I tested both the same results, literaly. I read it at codeplex.com/json about Json.Net 3.5. My question, is it Json.Net is now DataContractJsonSerializer? Should I use DataContractJsonSerializer, since its already in the framework assembly.

Thanks.

Ulu
January 05, 2010

# re: DataContractJsonSerializer in .NET 3.5

Hi,

So, how do you consume JSON objects serialized MsAJAX style (with "d" and "__type") in your .Net code?

The good old JavaScriptSerializer works fine with strings and stuff, but then I send a custom object, there's inconsistency: the __type doesn't include the assembly name, so the result cannot be created.

Thanks
ulu

Scott Brower
February 04, 2010

# re: DataContractJsonSerializer in .NET 3.5

Have a problem here with WCF Rest calls that I just cant figure out, so I'll try to document to where it makes sense...

I have this small class:
[DataContract]
    public class ChatRoomParticipant  // Wrapper class for single record
    {
        [DataMember]
        public Guid ChatRoomId { get; set; }
        [DataMember]
        public Guid PersonaId { get; set; }
    }


I call a rest service that has this on the "help" screen:
Reference for http://rest.versionme.com/ChatroomParticipantsService/{AUTHENTICATIONTOKEN}/{APPLICATIONTOKEN}/json/insert
 
 
Url: http://.../ChatroomParticipantsService/.../xml/insert 
 
HTTP Method: POST 
 
...
 
The following is an example request Xml body: 
 
<ChatRoomParticipant xmlns="http://schemas.datacontract.org/2004/07/ChatRoomParticipantsService">
  <ChatRoomId>1627aea5-8e0a-4371-9022-9b504344e724</ChatRoomId>
  <PersonaId>1627aea5-8e0a-4371-9022-9b504344e724</PersonaId>
</ChatRoomParticipant>


The Rest markup is
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{authenticationtoken}/{applicationtoken}/xml/insert")]
        
I have tried using all bodystyles and it still wont work.

It fails (using Fiddler):
Call= 
POST /ChatRoomParticipantsService/3528209f-5e2b-4c14-9fd3-4a827ed8fa52/00000000-0000-0000-0000-000000000000/Xml/insert HTTP/1.1
 
Request body (TestView)= 
<ChatRoomParticipant xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ChatRoomParticipantsService"><ChatRoomId>1627aea5-8e0a-4371-9022-9b504344e724</ChatRoomId><PersonaId>1627aea5-8e0a-4371-9022-9b504344e724</PersonaId></ChatRoomParticipant>
 
Response bosy (TextView)=
ReadResponse() failed: The server did not return a response for this request.  


I can decode the string using Xml in a small test program, but the WCF Rest service refuses to process it, although other calls that are identical in structure work fine. As you can see I sent it the exact code the help screen offers, and it never processes the call. I includes the extra namespace xmlns:i="http://www.w3.org/2001/XMLSchema-instance", but that doesnt seem to affect the other similar calls.

I am sure it's something simple I am missing, but I am at a total loss. If anyone has any ideas I would greatly appreciate any pointers.

Scott Brower
February 04, 2010

# re: DataContractJsonSerializer in .NET 3.5

Got it worked out, had a few typos in my last post but I was using Xml accross the board even though I accidentally pulled up the json help screen. Unloaded the project, did a full recompile, and restarted the webserver and it started behaving itself much better.

Maxi
February 05, 2010

# re: DataContractJsonSerializer in .NET 3.5

Dear Rick,

is it possible to have more than one data contract to one class?
maybe data contract to interfaces whom that class implement I suppose?

Rick Strahl
February 07, 2010

# re: DataContractJsonSerializer in .NET 3.5

No you can have one data contract per interface/class. The way to create more than one contract is to create subclasses of a base class and inherit the contract interface. This way you can have multiple types of operations. IMHO huge shortcoming of REST services in WCF.

srihari
February 24, 2010

# re: DataContractJsonSerializer in .NET 3.5

Hi,

I am building an RESTFull WCF service. My data contract types having the DateTime fields. If I assign the DateTime value of the field to DateTime.MinValue, the format of DateTime showing in the rendered output for Json is "Date(-62135596800000)" . In rest of the cases it is showing the format "2007-10-30T06:56:00"

I tested the Json output with different dateTime values. Those are,

1. If DateTime field value is "DateTime.Now", then Json output format is Date(1266960616682-0800)
2. If DateTime field value is "DateTime.MinValue", then Json output format is Date(-62135596800000)
3. if we asssign any date explicitly, the json output format is "2007-10-30T06:56:00"

I want single DateTime format through out my json output. Could any body help me on this.

Thanks in Adanvce,
Srihari

Maxi
March 10, 2010

# re: DataContractJsonSerializer in .NET 3.5

for fellow programmers who encounter unexpected character. this is from microsoft connect:
Please note that DataContractJsonSerializer only supports the following encodings: UTF-8, UTF-16LE and UTF-16BE.

So, this "ms = new MemoryStream(Encoding.UTF8.GetBytes(json));" will work.

The followings are not promised to work:
ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
ms = new MemoryStream(Encoding.Default.GetBytes(json));

Timothy
May 28, 2010

# re: DataContractJsonSerializer in .NET 3.5

dang usualdosage, your FromJSON extension really saved the day. I was having a hard time figuring how to deserialize a json array serialized with the microsoft script serializer and posted to the server. It was having problems deserializing the date, then I fed the string into your extension method and it worked like a dream.

well, the other ways worked like a dream too, but those were nightmares...

thanks!

yasha
August 14, 2010

# XMLSerializer in VB.NET

Hi rick!
i have written this class to serialize and deserialize some graphical elements like Isymbols and so on. but it works onlly for simplemarkersymbols and not for isymbols. please tell me the reason if you know. i don't know the parts of the WriteObject method.
thankx a lot!
yasha



Public Class ObjectSerializer

Public Shared Function Serialize(ByVal obj As Object) As String
Try
Dim pXMLStream As IXMLStream = New XMLStream()
Dim pXMLWriter As IXMLWriter = New XMLWriter()
pXMLWriter.WriteTo(CType(pXMLStream, IStream))
Dim pXMLSerializer As IXMLSerializer = New XMLSerializer()
pXMLSerializer.WriteObject(pXMLWriter, Nothing, Nothing, "", "", obj)

Return pXMLStream.SaveToString()
Catch ex As Exception
'Throw ex
End Try
End Function

Public Shared Function Deserialize(ByVal str As String) As Object
Try
Dim pXMLStream As IXMLStream = New XMLStream()
pXMLStream.LoadFromString(str)
Dim pXMLReader As IXMLReader = New XMLReader()
pXMLReader.ReadFrom(CType(pXMLStream, IStream))
Dim pXMLSerializer As IXMLSerializer
pXMLSerializer = New XMLSerializer()

Return pXMLSerializer.ReadObject(pXMLReader, Nothing, Nothing)
Catch ex As Exception
Throw ex
End Try
End Function

End Class

Hector
September 20, 2010

# re: DataContractJsonSerializer in .NET 3.5

Hey Rick

Thanks for blog post. It has been a great source of help for me for some time now.
I tried to implement as part of a utility to deserialize data for a web service and it works...somewhat.
The serialization works well, but I am having problems with the deserialization. The deserializeb object is for some reason empty. Here is my code:

[DataContract]
    public class Person
    {
        [DataMember]
        public int Age { get; set; }
 
        [DataMember]
        public string Name { get; set; }
 
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
 
        public Person()
        {
 
        }
        
        public override string  ToString()
        {
            return String.Format("Name: {0}, Age: {1}", this.Name, this.Age);
        }
    }
 
private static void DeserializeFromJson()
        {
            StringBuilder json = new StringBuilder();
            json.Append("{");
            json.Append("\"name\"");
            json.Append(":");
            json.Append("\"Hector\"");
            json.Append(",");
            json.Append("\"age\"");
            json.Append(":");
            json.Append("\"33\"");
            json.Append("}");
 
            Person person = new Person();
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json.ToString()));
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(person.GetType());
            person = serializer.ReadObject(ms) as Person;
            ms.Close();
 
            Console.WriteLine(person.ToString());
            Console.ReadLine();            
        }



Do you or anyone reading this blog have any suggestions for me?

_hector

Rick Strahl
September 20, 2010

# re: DataContractJsonSerializer in .NET 3.5

@Hector - you're encoding the Age incorrectly. You're encoding as string when it should be an int. Why are you hand serializing? Use the DataContractJsonSerializer for serialization as well to ensure you get valid JSON.

Will L
January 18, 2011

# re: DataContractJsonSerializer in .NET 3.5

Note that the "__type" will be added by this serializer in certain cases. For example,

[KnownType(typeof(Customer))]
[Serializable]
public class CustomerBase
.
.
.
 
[Serializable]
public class Customer : CustomerBase


and you return a List<CustomerBase>
        List<CustomerBase> c = new List<CustomerBase>();
        c.Add(person);
        ser = new DataContractJsonSerializer(c.GetType());
        ms = new MemoryStream();
        ser.WriteObject(ms, c);
 
        json = Encoding.Default.GetString(ms.ToArray());
        ms.Close();
        Response.Write("<pre>" + Server.HtmlEncode(json) + "</pre>");


you will get (marked up a bit <g>):
[{"__type":"test.Customer:#","Addresses":[
{"City":"Paia","State":"HI","Street":"32 Kaiea Place","Zip":"96779"},
{"City":"Paia","State":"HI","Street":"32 Kaiea Place","Zip":"96779"}],
"Entered":"\/Date(1191988800000-0400)\/","Name":"John Jones"}]


Don't know if it's by design or not but I discovered it recently and am probably going to resort to manually stripping out the "__type" part.

Punit Singhi
June 16, 2012

# re: DataContractJsonSerializer in .NET 3.5

Great Article. But have a question- My WCF Web method returns the list and I could able to use list without DataContractJsonSerializer in Client Side as json object. And if I use DataContractJsonSerializer, then in Client Side I need to parse the data using JSON.parse as the Webmethod returns string. So why would i even use the DataContractJsonSerializer.

Bil Simser
November 13, 2013

# re: DataContractJsonSerializer in .NET 3.5

Hey Rick,

I know this is an old article but I'm looking at the DataContractJsonSerializer in Json.NET right now and wondering what the difference/advantage is to using JsonConvert.Deserialize<ObjectType>(jsonString).

Thanks!

Rick Strahl
November 13, 2013

# re: DataContractJsonSerializer in .NET 3.5

@Bil - JSON.NET in general is a better JSON serializer as it provides cleaner serialization/deserialization for values. The main thing is for dates - DataContractJsonSerializer() doesn't serialize ISO string dates like every other parser, but MS style date strings. I think in .NET 4 they finally fixed DCJS to support reading ISO dates as dates. Other things that DCJS does badly are collections and the inability to serialize dynamic types (can't serialize of type object). It also doesn't have a dynamic parser, so if you don't have a type to serialize into you're out of luck. JSON.NET has JsonObject/JsonValue/JsonArray to allow dynamic access to a JSON document without a hard type reference which is great if you need to access only a couple of fields out of a large JSON document.

For deserialization the story with DCJS is better since it does understand some things that the serializer doesn't serialize - so for your scenario DCJS might be just fine. But all around if you use any amount of manual JSON parsing I would recommend something other then DCJS. Other than for WCF DCJS seems dead since the Web team is using JSON.NET for everything they push out now including Web API.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024