【发布时间】:2014-10-28 10:33:00
【问题描述】:
WCF Json 反序列化。
我正在使用 Dotnet 4.5 在 WCF 中构建中间件 web 服务,此服务器返回多态类型。
[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
{ }
/// <summary>
/// Contract for a service for testing various web operations.
/// </summary>
[ServiceContract]
[ServiceKnownType(typeof(SomethingA))]
[ServiceKnownType(typeof(SomethingB))]
public interface ITesting
{
/// <summary>
/// Test passing in and returning an object using POST and json.
/// </summary>
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "use-polymorphic-somethings",
Method = "POST")]
List<Something> UsePolymorphicSomethings();
}
/// <summary>
/// Implementation of the ITesting service contract.
/// </summary>
public class Testing : ITesting
{
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;
}
}
在客户端,我试图反序列化它以保留集合中的不同类型。这方面的 MSDN 文档对我来说似乎真的很弱。我遇到的第一个问题是,添加对 System.Web.Http 的引用创建了对第三方开源组件 Newtonsoft.Json 的未记录的动态依赖,我必须从网上下载该组件。
前两种反序列化方法失败,但我发现第三种方法有效。
我想知道的是为什么前两种方法会失败?理想情况下,我希望采用第一种工作方式,因为这是最精简的。
[TestMethod]
public void UsePolymorphicSomethings_Test1()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = new Uri("http://localhost:8733/");
HttpResponseMessage response = http.PostAsJsonAsync(
"Design_Time_Addresses/InSite8WebServiceLib2/Testing/use-polymorphic-somethings",
new StringContent(string.Empty)).Result;
List<Something> ret = response.Content.ReadAsAsync<List<Something>>().Result;
// FAILS.
Assert.AreEqual(typeof(SomethingA), somethings[0].GetType());
Assert.AreEqual(typeof(SomethingB), somethings[1].GetType());
}
}
[TestMethod]
public void UsePolymorphicSomethings_Test2()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = new Uri("http://localhost:8733/");
HttpResponseMessage response = http.PostAsJsonAsync(
"Design_Time_Addresses/InSite8WebServiceLib2/Testing/use-polymorphic-somethings",
new StringContent(string.Empty)).Result;
string ret1 = response.Content.ReadAsStringAsync().Result;
Newtonsoft.Json.JsonSerializerSettings s = new Newtonsoft.Json.JsonSerializerSettings();
s.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All;
List<Something> r = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Something>>(ret1, s);
// FAILS.
Assert.AreEqual(typeof(SomethingA), somethings[0].GetType());
Assert.AreEqual(typeof(SomethingB), somethings[1].GetType());
}
}
[TestMethod]
public void UsePolymorphicSomethings_Test3()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = new Uri("http://localhost:8733/");
HttpResponseMessage response = http.PostAsJsonAsync(
"Design_Time_Addresses/InSite8WebServiceLib2/Testing/use-polymorphic-somethings",
new StringContent(string.Empty)).Result;
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());
}
}
【问题讨论】:
-
嗨,我相信最后一种方法有效而其他两种方法无效的原因。是因为当你使用 WebMessageFormat.Json 时,服务器端使用的序列化器是 DataContractJsonSerializer。因此,在服务器端和客户端使用相同的序列化程序最终会得到满意的结果是有道理的。例如,如果您想使用 NewstonSoft,您将不得不在服务器端创建一个消息格式化程序类、一个 Web http 行为、一个行为扩展元素和一个 Web 内容类型映射器,然后您需要将所有这些连接起来,可能在Web 或应用程序配置文件。
-
我明白了。在这种情况下,UsePolymorphicSomethings_Test1 必须使用不同的支持 JSON 的反序列化器(因为它确实执行了反序列化,只是不正确),这引发了几个问题。 ReadAsAsync 默认使用哪个 JSON 序列化程序?为什么默认不使用 DataContractJsonSerializer?并且可以不将 ReadAsAsync 配置为默认使用 DataContractJsonSerializer,因为它的默认配置是无用的?
-
如果不需要,我真的不想使用 Newtonsoft,我尝试使用 Newtonsoft 类反序列化的唯一原因是因为 System.Net.Http 在我的集成测试程序集中创建了一个对它的动态(运行时)依赖,这使我推测它可能在某种程度上与这个问题有关。
标签: c# json wcf serialization