WCF Json deserialization.WCF Json deserialization сохраняет полиморфные типы сбора
Я создаю промежуточное webservice в WCF с помощью Dotnet 4.5, этот сервер возвращает полиморфный тип.
[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, вам придется перейти на сторону Serer, создать класс форматирования сообщений, поведение веб-http, элемент расширения поведения и конфигуратор типа веб-контента, а затем вам нужно будет подключить все это, возможно, в файлы конфигурации сети или приложения. –
Я вижу. В этом случае UsePolymorphicSomethings_Test1 должен использовать другой десериализатор, совместимый с JSON (поскольку он выполняет десериализацию, просто неправильно), что вызывает несколько вопросов. Какой JSON-сериализатор использует ReadAsAsync по умолчанию? Почему он не использует DataContractJsonSerializer по умолчанию? и может ли ReadAsAsync не настроиться на использование DataContractJsonSerializer по умолчанию, поскольку его конфигурация по умолчанию бесполезна? – Neutrino
Я действительно не хочу использовать Newtonsoft, если мне этого не нужно, единственная причина, по которой я пытался десериализовать использование классов Newtonsoft, заключается в том, что System.Net.Http в моей тестовой сборке интеграции создавал динамическую (runtime) зависимость от нее что заставило меня предположить, что это может быть связано с этим вопросом в некотором роде. – Neutrino