Serialize/Deserialize JSON object in .NET 3.5 Using JavaScriptSerializer

Hello Sitepoint,

I am trying to implement some AJAX(using jQuery) in my company’s CMS system and am running into a couple problems. I have read all over online and looked at quite a few examples but just can’t seem to get this to work or understand the best practice when communicating with methods on the server through AJAX.

I would like to just pass a JSON object into .NET method, deserialize into an object, insert into db, and serialize the object back to the caller without using WCF, etc. The problem is I keep receiving this error message: No parameterless constructor defined for type of \u0027System.String\u0027. If anyone could give me some insight or comprehensive examples to read through I would very much like you forever:)

My JSON as I build it from the form:

 var data = '{"replacementPartsDiagram":{"diagramTitle": "' + DiagramTitle + '","diagramImagePath": "' + DiagramImagePath + '","diagramSortOrder": ' + DiagramSortOrder + ',"flattenedDiagramRefNumbers": "' + FlattenedDiagramRefNumbers + '"}}';

The actual post request going through(according to firebug):

{"replacementPartsDiagram":{"diagramTitle": "Foo Bar","diagramImagePath": "Koala.jpg","diagramSortOrder": 3,"flattenedDiagramRefNumbers": "1,44394,2,45194,--,47092,3,45202,4,44403,5,45200,6,44405,7,44407,8,44409,9,44411"}}

Calling jQuery Ajax method(being called through a jQuery UI dialog add button):


$.ajax({
                            type: 'POST',
                            url: 'categories.aspx/addRPDiagram',
                            data: data,
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            context: this,
                            timeout: 5000,
                            success: function (msg) {
                                alert(msg.d);
                                /*if (msg.d) {
                                alert("Successfully entered the new diagram");
                                }
                                else {
                                alert("Error! The diagram was not entered into the database!");
                                }*/
                                $(this).dialog("close");
                            },
                            error: function (xhr, status, errorThrown) {
                                alert("Error!" + xhr.responseText + '  ' + errorThrown);
                            }
                        });

The webmethod in .NET. I just wanted to see if I could get anything returned at this point:


 <WebMethod()> _
    Public Shared Function addRPDiagram(replacementPartsDiagram As String) As String
        Dim serializer = New JavaScriptSerializer()
        Dim rep As ReplacementPartsDiagram = serializer.Deserialize(Of ReplacementPartsDiagram)(replacementPartsDiagram)
        Return rep.DiagramTitle
    End Function

The ReplacementPartsDiagram Class:


Public Class ReplacementPartsDiagram
    Private _diagramTitle As String
    Private _diagramImagePath As String
    Private _diagramSortOrder As Integer
    Private _flattenedDiagramRefNumbers As String

    Public Sub ReplacementPartsDiagram()

    End Sub

    Public Property DiagramTitle As String
        Get
            Return _diagramTitle
        End Get
        Set(value As String)
            If _diagramTitle = value Then
                Return
            End If
            _diagramTitle = value
        End Set
    End Property

    Public Property DiagramImagePath As String
        Get
            Return _diagramImagePath
        End Get
        Set(value As String)
            If _diagramImagePath = value Then
                Return
            End If
            _diagramImagePath = value
        End Set
    End Property

    Public Property DiagramSortOrder As Integer
        Get
            Return _diagramSortOrder
        End Get
        Set(value As Integer)
            If _diagramSortOrder = value Then
                Return
            End If
            _diagramSortOrder = value
        End Set
    End Property
    Public Property FlattenedDiagramRefNumbers As String
        Get
            Return _flattenedDiagramRefNumbers
        End Get
        Set(value As String)
            If _flattenedDiagramRefNumbers = value Then
                Return
            End If
            _flattenedDiagramRefNumbers = value
        End Set
    End Property


End Class

I just can’t seem to wrap my head around the best way to do this as there is so many examples everywhere. Any direction would be awesome.

Thanks guys!

What you really want to be using is the WebAPI – that does this automagically.

The error message is accurate – it can’t construct an instance of the string class. It will, however, automagically deserialize your json if you just let it take the ReplacementPartsDiagram as the parameter.

I have read a bit on webAPI, but is it supported in 3.5? If so I will read on that.

So your saying my web method signature should look like this?:



Public Shared Function addRPDiagram(replacementPartsDiagram As ReplacementPartsDiagram) As String
        Dim serializer = New JavaScriptSerializer()
        Dim rep As ReplacementPartsDiagram = serializer.Deserialize(Of ReplacementPartsDiagram)(replacementPartsDiagram)
End Function

Thanks WWB!

Web API on 3.5? No, it is 4.0 / 4.5 only.

My VB is a bit rusty, but yes, that looks largely right. What are you returning there? It doesn’t seem to be passing a string back.

Sorry I forgot that portion…Right now I am just trying to return rep.DiagramTitle. The problem I found with setting the parameter to be strongly typed is I don’t see an overloaded version of deserialize.

It only takes the type - (Of T) and the input JSON string - (replacementPartsDiagram). That’s why I initially had the parameter as a string.

I decided to bypass this deserialization part just to see if I could populate an object with the individual properties in the JSON and then serialize the object back again.


Public Shared Function addRPDiagram(diagramTitle As String, diagramImagePath As String, diagramSortOrder As String, flattenedDiagramRefNumbers As String) As String
        Dim serializer = New JavaScriptSerializer()

        Dim rp As New ReplacementPartsDiagram
        rp.DiagramTitle = diagramTitle
        rp.DiagramImagePath = diagramImagePath
        rp.DiagramSortOrder = CInt(diagramSortOrder)
        rp.FlattenedDiagramRefNumbers = flattenedDiagramRefNumbers
        Return serializer.Serialize(rp)


    End Function

The problem I am running into now is accessing the properties on the callback. When I try to alert the values of each property, I see undefined.


 var data = "{'diagramTitle': '" + DiagramTitle + "','diagramImagePath': '" + DiagramImagePath + "','diagramSortOrder': " + DiagramSortOrder + ",'flattenedDiagramRefNumbers': '" + FlattenedDiagramRefNumbers + "'}";
                        $.ajax({
                            type: 'POST',
                            url: 'categories.aspx/addRPDiagram',
                            data: data,
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            context: this,
                            timeout: 5000,
                            success: function (msg) {
                                var repDiag = msg.d;
                                alert(repDiag.diagramTitle);
                                alert(repDiag.diagramImagePath);
                                alert(repDiag.diagramSortOrder);
                                alert(repDiag.flattenedDiagramRefNumbers);
                                /*if (msg.d) {
                                alert("Successfully entered the new diagram");
                                }
                                else {
                                alert("Error! The diagram was not entered into the database!");
                                }*/
                                $(this).dialog("close");
                            }

Any hints to what I am missing?

The trick is you don’t – the web service deserializes the object for ya. Or at least it should.

I figured out why I couldn’t access the values. I am not really understanding why for sure, but parsing the “d” object into a variable let me access them normally.


var data = "{'diagramTitle': '" + DiagramTitle + "','diagramImagePath': '" + DiagramImagePath + "','diagramSortOrder': " + DiagramSortOrder + ",'flattenedDiagramRefNumbers': '" + FlattenedDiagramRefNumbers + "'}";
                        $.ajax({
                            type: 'POST',
                            url: 'categories.aspx/addRPDiagram',
                            data: data,
                            contentType: "application/json; charset=utf-8",
                            dataType: "json",
                            context: this,
                            timeout: 5000,
                            success: function (msg) {

                                result = $.parseJSON(msg.d);
                                alert(result.DiagramTitle);
                                alert(result.DiagramImagePath);
                                alert(result.DiagramSortOrder);
                                alert(result.FlattenedDiagramRefNumbers);
                                /*if (msg.d) {
                                alert("Successfully entered the new diagram");
                                }
                                else {
                                alert("Error! The diagram was not entered into the database!");
                                }*/
                                $(this).dialog("close");
                            }

The actual return from the web method after using the JavaScriptSerializer as this:


{"d":"{\\"DiagramTitle\\":\\"Foo Bar\\",\\"DiagramImagePath\\":\\"Tulips.jpg\\",\\"DiagramSortOrder\\":3,\\"FlattenedDiagramRefNumbers\\":\\"1,44394,2,45194,--,47092,3,45202,4,44403,5,45200,6,44405,7,44407,8,44409,9,44411\\"}"}

Still can’t get the deserialization of the JSON string to work in the webmethod though. Not quite sure what that’s about or what I am missing there. Would DataContracts/Members be a better option?

Just noticed one thing – you should be feeding the javascript side of things a hash, not a string. It is probably jsoning your json now.

DataContracts on your DTO would help.

Finally, if you just want to POST a json string, you might want to look at writing a IHttpHandler and posting to that. Not the most “.NET” thing to do bit it does work pretty well.

I am just using the JavaScriptSerializer on my object for the return to javascript. It wraps it in a “d” object I suppose for security? Anyways, how would I return this as a hash and be able to get the values returned? I am unfamiliar with that.

I wonder if my deserializing the json into a .NET object problem I was having before was because I was because of how my json is formatted…I have seen a lot of examples online where theirs supposedly works without a hitch. I was thinking of trying newton’s JSON.NET instead of the .NET serializer to see if that made a difference.

Do you know of any good sources(books or online tutts) for making a RESTful API in .NET 3.5 and above? Eventually I will refresh this project into MVC and I could see the need coming, but still have to support some of the 3.5 webforms portals we have internally.

Thanks!

Why are you stuck on 3.5? Very little reason not to upgrade to 4.0 which gets you the WebAPI which is quite sweet. Or other nifty toys like nancy. And a slew of awesome language features that you really can’t understand you are missing until you are missing them.

If you really can’t get off 3.5, you might want to check out open rasta.

If your definition of RESTful is really “I need to do a little bit of HTTP GET / POSTing of JSON at low scale” then IHttpHandlers work quite well in my experience.

Json.NET is great. So great they actually folded it into the WebAPI. But serialization-wise it works lots like the JavaScript serializer so problems are likely to transfer. Might help if you post the DTO you are trying to deserialize from / to.

Right now I think I just need a little POSTing of JSON at low scale to get by until the upgrade to MVC and 4.0+'s goodness. I’ll look into just the handlers for these cases right now but is there any difference’s security wise between using the page methods decorated with webmethod and a handler?

I finally did figure out my entire problem from the start using javascriptserializer…I feel like an idiot too.

My client code after creating js object. I did go and get json2.js for JSON.stringify method on the DTO.


var ReplacementPartsDiagram = {};
//assign members
var DTO = { 'ReplacementPartsDiagram': ReplacementPartsDiagram };


Webmethod:


Public Shared Function addRPDiagram(replacementPartsDiagram As ReplacementPartsDiagram) As String

End Function

No capital R…pfffttt. I guess the moral of the story is the names have to match exactly and like you said, Webmethod does automagically deserialize the object and everything works fine using it to serialize it back. I can’t wait to dig into WEBAPI in the future.

Thanks again WWB!

Yup, that is why I asked about the DTO. I think Json.NET handles this a bit better by default, and you could always use attributes to get around this if you wanted to be explicit.

Security-wise there isn’t a difference presuming you are using typical ASP.NET security – anything served by aspnet_isapi can stand behind the same authentication.

Also note that you can use ASP.NET web forms 4.0 (probably with zero code modification) with the web API, you don’t have to use MVC.