【问题标题】:How to include object type in Json for asmx web service using Gson如何使用 Gson 在 Json 中为 asmx Web 服务包含对象类型
【发布时间】:2012-02-08 14:29:44
【问题描述】:

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

例如:

class A{
 string name;
}

class B : A {
 string address;
}

和网络方法:

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

现在在上面的示例场景中,假设我发送 {"obj":{"name":"waqas","address":"sweden"}} 那么我如何强制我的 json 字符串充当 B 类的类型,以便它可以被 Web 方法接受为 A 类的对象以及进一步解析回B类的对象?简而言之,如何在json中保留多态性?

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

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

任何帮助/建议都会有所帮助。


更新:

如果我们仔细观察 asmx web 服务的wsdl,那么其类继承父类的对象包含类似<s:extension base="tns:ParentClassName"> 的内容。我认为这个扩展部分是我可能需要转换成 Json 的东西。对此有任何想法吗?

【问题讨论】:

  • 你能把函数改成读取PushJson(B obj)吗?这样框架可能会将 json 反序列化为您想要的类型。
  • 是的,如果我修改 Web 服务,它应该可以工作,但这不是我能够做到的

标签: asp.net json polymorphism gson object-type


【解决方案1】:

您在标题中提到了 GSON,但我不确定它在这张图片中的位置。所以,我可能走错了方向。但是,如果您只是询问让 .NET 反序列化您的 JSON,是的,您可以使用 __type 参数。它必须是第一位的。

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

我能够让它在一个测试项目中工作,但就像我说的,不涉及 GSON。

编辑: 实际上,您可能还希望看到其他答案 https://stackoverflow.com/a/10805715/1539015 讨论如何让 GSON 包含该 __type 参数。

EDIT2: 我创建了一个新的 .NET 网站。添加了一个包含 A 和 B 类的类文件(已修改以使其公开):

public class A
{
    public string name;
}

public class B : A
{
    public string address;
}

然后,我添加了一个 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;
    }
}

然后我编辑了默认页面以使用 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>

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

这里没有 GSON,但我相信我链接的另一篇文章应该显示如何让 GSON 生成 __type 参数。

【讨论】:

  • 不,这不能解决问题。我注意到__type 可能仅在服务器上的类文件中没有定义任何构造函数的情况下才有用。它对翻译提供的 Json 字符串的对象类型没有帮助。
  • 我不同意。在反序列化 json 字符串时与 .NET 通信要实例化哪种类型正是 __type 所做的。
  • 你能发布一些示例代码来展示它是如何实现的吗?
  • 我认为,如果您在 json 请求参数中甚至不包含 __type,则方法 PushJson 在这种情况下仍然有效,因为您的请求包含它需要的所有参数构造一个对象 B。你也可以试试吗?谢谢
  • 我刚刚了解到您说的是框架 2.0。这可能是问题的根源。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 2014-08-06
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    相关资源
    最近更新 更多