WCF JSON序列化是不一致的,所以如何正确反序列化?

时间:2014-11-07 11:32:02

标签: c# json wcf serialization

我有一个可序列化的多态类型和服务合同。

[DataContract]
[KnownType(typeof(SomethingA))]
[KnownType(typeof(SomethingB))]
public class Something
{
    [DataMember]
    public int Item1 { get; set; }

    [DataMember]
    public string Item2 { get; set; }
}

[DataContract]
public class SomethingA : Something
{ }

[DataContract]
public class SomethingB : Something
{ }

[ServiceContract]
[ServiceKnownType(typeof(SomethingA))]
[ServiceKnownType(typeof(SomethingB))]
public interface ITesting
{
    [OperationContract]
    [WebInvoke(
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "use-something",
        Method = "POST")]
    Something UseSomething();

    [OperationContract]
    [WebInvoke(
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "use-polymorphic-somethings",
        Method = "POST")]
    List<Something> UsePolymorphicSomethings();

    [OperationContract]
    [WebInvoke(
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Bare,
        UriTemplate = "throw-web-exception",
        Method = "POST")]
    void ThrowServerException();
}

......以及该合同的实施。

using System.Net;
using System.ServiceModel.Web;

public class Testing : ITesting
{
    public Something UseSomething()
    {
        SomethingA a = new SomethingA();
        a.Item1 = 2;
        a.Item2 = "b";
        return a;
    }

    public List<Something> UsePolymorphicSomethings()
    {
        List<Something> retVal = new List<Something>();
        retVal.Add(new SomethingA { Item1 = 1, Item2 = "1" });
        retVal.Add(new SomethingB { Item1 = 1, Item2 = "1" });

        return retVal;
    }

    public void ThrowServerException()
    {
        try
        {
            throw new ApplicationException("Bad news.");
        }
        catch (ApplicationException e)
        {
            throw new WebFaultException<ApplicationException>(e, HttpStatusCode.InternalServerError);
        }
    }
}

我在另一个程序集中有一些功能测试。

using System.Net;
using System.Net.Http;
using System.Runtime.Serialization.Json;

[TestMethod]
public void UseSomething_WebTest()
{
    using (HttpClient http = new HttpClient())
    {
        http.BaseAddress = TestUtil.TestsBaseAddress;

        HttpResponseMessage response = http.PostAsJsonAsync("use-something",
            new StringContent(string.Empty)).Result;

        string ret1 = response.Content.ReadAsStringAsync().Result;

        // Deserializes SomethingA as Something.
        Stream stream = response.Content.ReadAsStreamAsync().Result;
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Something));
        Something ret = (Something)serializer.ReadObject(stream);

        // FAILS.
        Assert.AreEqual(typeof(SomethingA), ret.GetType());
    }
}

[TestMethod]
public void UsePolymorphicSomethings_WebTest()
{
    using (HttpClient http = new HttpClient())
    {
        http.BaseAddress = TestUtil.TestsBaseAddress;

        HttpResponseMessage response = http.PostAsJsonAsync("use-polymorphic-somethings",
            new StringContent(string.Empty)).Result;

        string ret2 = response.Content.ReadAsStringAsync().Result;

        // Deserializes SomethingA and SomethingB correctly.
        Stream stream = response.Content.ReadAsStreamAsync().Result;
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Something>));
        List<Something> somethings = (List<Something>)serializer.ReadObject(stream);

        // SUCCEEDS.
        Assert.AreEqual(typeof(SomethingA), somethings[0].GetType());
        Assert.AreEqual(typeof(SomethingB), somethings[1].GetType());
    }
}

[TestMethod]
public void ThrowServerException1_WebTest()
{
    using (HttpClient http = new HttpClient())
    {
        http.BaseAddress = TestUtil.TestsBaseAddress;

        HttpResponseMessage response = http.PostAsync("throw-web-exception",
           new StringContent(string.Empty)).Result;

        Assert.AreEqual(HttpStatusCode.InternalServerError, response.StatusCode);

        string ret3 = response.Content.ReadAsStringAsync().Result;

        // Deserializes ApplicationException as Exception.
        Stream stream = response.Content.ReadAsStreamAsync().Result;
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Exception));
        Exception e = (Exception)serializer.ReadObject(stream);

        // FAILS.
        Assert.AreEqual(typeof(ApplicationException), e.GetType());
    }
}

在UseSomething_WebTest中,ret1为:

"{\"Item1\":2,\"Item2\":\"b\"}"

...没有嵌入类型信息,不出所料,DataContractJsonSerializer无法反序列化返回的对象的正确类型。

In UsePolymorphicSomethings_WebTest ret2是:

"[{\"__type\":\"SomethingA:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"},{\"__type\":\"SomethingB:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"}]"

...以__type条目的形式嵌入的类型信息,DataContractJsonSerializer正确地反序列化。

在ThrowServerException1_WebTest中,ret3是:

"{\"ClassName\":\"System.ApplicationException\",\"Message\":\"Bad news.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\"   at InSite8WebServiceLib.Testing.ThrowServerException() in d:\\\\SvnSource\\\\Hammersmith\\\\trunk\\\\VisualStudioProjects\\\\InSite8WebService\\\\InSite8WebServiceLib\\\\Testing\\\\Testing.cs:line 74\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":\"8\\u000aThrowServerException\\u000aInSite8WebServiceLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\\u000aInSite8WebServiceLib.Testing\\u000aVoid ThrowServerException()\",\"HResult\":-2146232832,\"Source\":\"InSite8WebServiceLib\",\"WatsonBuckets\":null}"

...以ClassName条目的形式嵌入类型信息,DataContractJsonSerializer无法正确反序列化。

所以我的问题是这个。为什么对于单个WCF WebHttp端点,多个WebInvoke属性方法返回几种不同格式的JSON,其中只有一个DataContractJsonSerializer可以实际反序列化,以及如何修复它以使其正常工作?

1 个答案:

答案 0 :(得分:0)

您可以通过重载构造函数来强制DataContractJsonSerializer始终发出类型信息。然后将 alwaysEmitTypeInformation 参数设置为True。

有关MSDN

的更多信息