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

2

12

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?

Furey answered 8/2, 2012 at 14:29 Comment(2)
Could you change the function to read PushJson(B obj) instead? That way the framework might deserialize the json to the type you want.Heger
yes, it should probably work if i modify the web service but this is not what i am able toFurey
C
6

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://mcmap.net/q/1011273/-how-to-write-a-custom-serializer-adapter-for-gson-that-i-can-use-with-net 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.

Cordeelia answered 13/8, 2012 at 18:22 Comment(7)
No, this doesn't resolve the problem. I've noticed that __type may only be useful in case the class file on server doesn't have any constructor defined in it. It doesn't help in translating the object type of provided Json string.Furey
I have to disagree. Communicating to .NET which type to instantiate as it deserializes the json string is exactly what __type does.Cordeelia
can you post some sample code to show how can it be achieved?Furey
I think if you dont even include __type in your json request params the method PushJson will still work in this case, because your request contains all the parameters it requires to construct an object B. Can you try that too? thanksFurey
I've just clued in to the fact that you said framework 2.0. This is probably the source of the problems.Cordeelia
When I take out the __type, I get an error on the B b= (B) obj; line saying: Unable to cast object of type 'A' to type 'B'.Cordeelia
If this is a .NET 2.0 web service, we'll have to know how that web service is deserializing JSON.Cordeelia
M
3

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);
Martsen answered 15/2, 2012 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.