如何使用Gson在Json中为asmx Web服务包含对象类型

时间:2022-12-21 22:13:50

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

在.net 2.0中向asmx Web服务发送数据时,我们如何保留json字符串中的对象类型?

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?

现在在上面的示例场景中,让我们说,我发送{“obj”:{“name”:“waqas”,“address”:“sweden”}}然后我如何强制我的json字符串充当B类的类型,这样它可以被Web方法接受为A类的对象,并进一步解析回B类的对象?总之,如何在json中保留多态?

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

我注意到,当我尝试执行这种模式时,编译器会抛出System.InvalidCastException

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?

附:我注意到.net在序列化为json时为复杂对象添加了__type。是否有可能我们可以包含这个键来帮助.net自动解析具有正确类类型的json字符串?

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?

如果我们仔细观察asmx web服务的wsdl,那么类继承父类的对象包含类似 的对象。我认为这个扩展部分是我可能需要转换为Json的东西。对此有何看法? :extension>

2 个解决方案

#1


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.

你在标题中提到了GSON,但我不确定它在这张照片中的位置。所以,我可能会出现错误的切线。但是,如果您只是想要让.NET反序列化您的JSON,是的,您可以使用__type参数。它必须是第一位的。

{"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.

我能够在测试项目中使用它,但就像我说的那样,没有GSON参与其中。

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

编辑:实际上,您可能还想看到另一个答案https://*.com/a/10805715/1539015,其中讨论了如何让GSON包含该__type参数。

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

编辑2:我创建了一个新的.NET网站。添加了A类和B类的类文件(修改为公开):

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:

然后,我添加了一个Web服务,以获得您在问题中使用的WebMethod。我还包括一个GetJson方法。这是背后的代码:

[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:

然后我编辑了默认页面以使用jQuery调用web方法:

<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.

如果在PushJson的webservice方法中放置断点,则可以看到创建的对象是B类型,并且它也会运行并显示它可以转换为类型B并使用。

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

这里没有GSON,但我相信我链接的其他帖子应该显示如何让GSON生成__type参数。

#2


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:

我不确定这是100%相关的,因为您在评论中提到您无法更改WebService,但使用System.Web.Script.Serialization的JavaScriptSerializer,您可以反序列化为任一类型:

JavaScriptSerializer serializer = new JavaScriptSerializer();
A a = serializer.Deserialize<A>(jsonStr);
B b = serializer.Deserialize<B>(jsonStr);

#1


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.

你在标题中提到了GSON,但我不确定它在这张照片中的位置。所以,我可能会出现错误的切线。但是,如果您只是想要让.NET反序列化您的JSON,是的,您可以使用__type参数。它必须是第一位的。

{"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.

我能够在测试项目中使用它,但就像我说的那样,没有GSON参与其中。

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

编辑:实际上,您可能还想看到另一个答案https://*.com/a/10805715/1539015,其中讨论了如何让GSON包含该__type参数。

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

编辑2:我创建了一个新的.NET网站。添加了A类和B类的类文件(修改为公开):

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:

然后,我添加了一个Web服务,以获得您在问题中使用的WebMethod。我还包括一个GetJson方法。这是背后的代码:

[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:

然后我编辑了默认页面以使用jQuery调用web方法:

<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.

如果在PushJson的webservice方法中放置断点,则可以看到创建的对象是B类型,并且它也会运行并显示它可以转换为类型B并使用。

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

这里没有GSON,但我相信我链接的其他帖子应该显示如何让GSON生成__type参数。

#2


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:

我不确定这是100%相关的,因为您在评论中提到您无法更改WebService,但使用System.Web.Script.Serialization的JavaScriptSerializer,您可以反序列化为任一类型:

JavaScriptSerializer serializer = new JavaScriptSerializer();
A a = serializer.Deserialize<A>(jsonStr);
B b = serializer.Deserialize<B>(jsonStr);