Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to include object type in Json for asmx web service using Gson

How do we preserve the object type in json string when sending data to asmx web service in .net 2.0?

for example:

class A{
 string name;
}

class B : A {
 string address;
}

and the web method:

[WebMethod]
public void PushJson(A obj){
  B b = (B) obj;
}

Now in above example scenario, lets say, i send {"obj":{"name":"waqas","address":"sweden"}} then how can i force my json string to act as type of class B, so that it can be accepted by web method as an object of class A and further parsed back into object of class B? in short, how to preserve polymorphism in json?

I've noticed that the compiler throws me System.InvalidCastException when ever i try to execute such kind of pattern

P.S. I've noticed that .net adds __type for complex objects while serializing into json. Is it possible that we can include this key to help .net to automatically parse json string with correct class type?

any help/suggestion would be helpful.


Update:

If we observe carefully the wsdl of an asmx web-service, so the objects whose classes inherits parent classes are containing something like <s:extension base="tns:ParentClassName">. I think this extension part is the thing which I may need to convert into Json. Any idea regarding this?

like image 444
waqaslam Avatar asked Feb 08 '12 14:02

waqaslam


2 Answers

You mention GSON in your title, but I'm not sure where it is playing into this picture. So, I might be off on the wrong tangent. However, if you are just asking about getting .NET to deserialize your JSON, yes, you can use the __type parameter. It must come first.

{"obj":{"__type":"B","name":"waqas","address":"sweden"}}

I was able to get this to work in a test project, but like I said, no GSON involved.

EDIT: Actually, you might also want to see this other answer https://stackoverflow.com/a/10805715/1539015 that talks about how to get GSON to include that __type parameter.

EDIT2: I made a new .NET web site. Added a class file with your A and B classes (modified to make them public):

public class A
{
    public string name;
}

public class B : A
{
    public string address;
}

I then added a web service to have the WebMethod you had in the question. I also included a GetJson method. Here's the code behind:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {

    public WebService () {
    }

    [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)]
    [WebMethod]
    public B GetJson()
    {
        return new B() { address = "addr", name = "nm" };
    }

    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    [WebMethod]
    public string PushJson(A obj)
    {
        B b = (B)obj;
        return b.address;
    }
}

I then edited the default page to call the web method using jQuery:

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <p>
        <div id="GetResult">Click here for the result of getting json.</div>    
        <div id="PushResult">Click here for the result of pushing json.</div>    
    </p>
    <script type="text/javascript">
        $(document).ready(function () {
            // Add the page method call as an onclick handler for the div.
            $("#GetResult").click(function () {
                $.ajax({
                    type: "GET",
                    url: "WebService.asmx/GetJson",
                    contentType: "application/json; charset=utf-8",
                    success: function (msg) {
                        // Replace the div's content with the page method's return.
                        $("#GetResult").text(msg.d.name);
                    }
                });
            });
            $("#PushResult").click(function () {
                $.ajax({
                    type: "POST",
                    url: "WebService.asmx/PushJson",
                    data: '{"obj":{"__type":"B","name":"waqas","address":"sweden"}}',
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (msg) {
                        // Replace the div's content with the page method's return.
                        $("#PushResult").text(msg.d);
                    }
                });
            });
        });  
    </script>
</asp:Content>

If you place a breakpoint in the webservice method of PushJson, you can see that the object that was created was of type B, and it runs also showing it can be cast to type B and used.

There's no GSON here, but I believe the other post I linked should show how to get GSON to generate the __type parameter.

like image 62
eol Avatar answered Nov 08 '22 09:11

eol


I'm not sure this is 100% relevant, since you mentioned in the comments that you're not able to change the WebService, but using System.Web.Script.Serialization's JavaScriptSerializer, you can deserialize to either type:

JavaScriptSerializer serializer = new JavaScriptSerializer();
A a = serializer.Deserialize<A>(jsonStr);
B b = serializer.Deserialize<B>(jsonStr);
like image 3
Derek Hunziker Avatar answered Nov 08 '22 11:11

Derek Hunziker