C# Web Api JSON中的EF TPH继承丢失
我已经成功地设置了一些使用的类,C# Web Api JSON中的EF TPH继承丢失,c#,linq,entity-framework,inheritance,asp.net-web-api,C#,Linq,Entity Framework,Inheritance,Asp.net Web Api,我已经成功地设置了一些使用的类,MyBaseClass,MySubClass1,MySubClass2等等 使用Linqcontext.MyBaseClasses.Where(…)进行查询时,返回的所有对象都正确地使用数据库中鉴别器字段指定的子类。(因此,我可能会得到一个列表,其中包含MySubClass1或MySubClass2的混合对象) 但是,当我通过JSON Web Api调用将这些对象传递给WPF应用程序时,收到的对象都是MyBaseClass,而不是它们开始的正确子类 它们通过返回的
MyBaseClass
,MySubClass1
,MySubClass2
等等
使用Linqcontext.MyBaseClasses.Where(…)
进行查询时,返回的所有对象都正确地使用数据库中鉴别器字段指定的子类。(因此,我可能会得到一个列表,其中包含MySubClass1
或MySubClass2
的混合对象)
但是,当我通过JSON Web Api调用将这些对象传递给WPF应用程序时,收到的对象都是MyBaseClass
,而不是它们开始的正确子类
它们通过返回的对象属性的类型为public virtual List MyThings
,因此我认为它们最终都是这种类型是有意义的,但我希望为每个对象保留正确的子类类型
我如何做到这一点?我是否需要强制EF鉴别器字段以某种方式与所有其他数据一起发送
编辑
1.
在客户端,我现在正试图像这样反序列化JSON(包括$type数据)(如果运气不好,这些项仍然会转换回它们的基类)
HttpResponseMessage response=GetClient().GetAsync(url).Result;
if(响应。IsSuccessStatusCode)
{
字符串jsonMessage;
使用(Stream responseStream=response.Content.ReadAsStreamAsync().Result)
{
jsonMessage=newstreamreader(responseStream.ReadToEnd();
}
列出所需物品;
//新方法
thingsToReturn=JsonConvert.DeserializeObject(jsonMessage);
//以前的方法
//thingsToReturn=response.Content.ReadAsAsync().Result;
归还物品;
}
2.
按照Anish关于SerializerSettings.TypeNameHandling的建议,我现在在JSON中显示了$type信息,但是,这是类型
System.Data.Entity.DynamicProxies.subclass 1_5E07A4CE2F037430DC7BFA000593….
客户端成功反序列化回子类1
是否可以?这是一个序列化问题
您可以自定义Json.Net的序列化程序设置,以便在Json对象中包含类型信息
将此添加到您的HttpConfiguration
:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
其中config
是用于配置和初始化Asp.Net WebApi的HttpConfiguration
实例
这将告诉Json.Net向每个具有类型歧义的Json对象添加一些类型信息。这样的对象将如下所示:
{
"$type":"MyProjectContainingMyTypes.MySubClass1, MyProjectContainingMyTypes",
"Name": "Tyrion Lannister",
"DisplayName": "The Imp",
"Traits": ["funny", "awesome", "clever"]
}
var jsonString = response.Content.ReadAsStringAsync().Result;
var result = dbContext
.Things
.Include(t => t.SomePropertyThatRepresentsSomeNestedObject)
.Skip(0)
.Take(10)
.ToList();
当您在WPF端对其进行反序列化时,Json.Net将知道如何处理此问题
在您的WPF应用程序中,这应该是可行的:
编辑2
安妮什,非常感谢你的投入。如您所见,我现在已经成功地将JSON作为字符串获取,但即使使用JsonConvert.DeserializeObject,我仍然会遇到同样的问题。您认为这与服务返回的$type(作为EF代理类型)不正确有关吗(如我在编辑2中提到的) 对于您的评论,是的,您将无法将EF代理类型反序列化为您想要的类型。这个问题需要在WebApi方面解决 创建代理类是为了允许您延迟加载实体。代理通常用于表示引用/嵌套的实体。这允许从数据库中提取被引用的实体推迟到需要时(如果需要的话) 下面是一些关于使用EF加载懒惰和急切实体的文档的示例 解决方案 如果您想在WebApi控制器操作中添加对象列表并返回它,这将告诉EF从数据库中加载实体并更新类的实例 您在这里有几个选项: 选项1 对查询调用
ToList()
,以创建集合:
var result = (from t in dbContext.Things select t).ToList();
或
当然,您不希望返回无界结果集,因此请添加一个范围:
var result = (from t in dbContext.Things select t).Skip(0).Take(10).ToList();
或
请记住,使用该方法,您必须显式地为嵌套对象添加水合物,如下所示:
{
"$type":"MyProjectContainingMyTypes.MySubClass1, MyProjectContainingMyTypes",
"Name": "Tyrion Lannister",
"DisplayName": "The Imp",
"Traits": ["funny", "awesome", "clever"]
}
var jsonString = response.Content.ReadAsStringAsync().Result;
var result = dbContext
.Things
.Include(t => t.SomePropertyThatRepresentsSomeNestedObject)
.Skip(0)
.Take(10)
.ToList();
选项2
关闭DbContext的延迟加载
就我个人而言,我会选择选项1,我认为最好了解你的实体,并控制你的水合物生成时间和内容。多亏了Anish,他的答案让我走上了正确的道路,也让我走上了正确的道路 为了让继承对象的类型通过web api服务,我必须采取以下步骤: 服务器端 关键是将JsonFormatter序列化程序
TypeNameHandling
设置为TypeNameHandling.Auto
。这可以在WebApiConfig.Register()
中完成,但它显然会向web服务调用返回的所有JSON对象添加$type属性,或者,您可以简单地修饰需要$type的对象的属性
WebApiConfig方法
物业装修方法
客户端
我必须向ReadAsAsync()
调用添加一个JsonMediaTypeFormatter
和SerializerSettings={TypeNameHandling=TypeNameHandling.Auto}
,然后将(正确键入的)对象映射到它们的子类
HttpResponseMessage response = GetClient().GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
//this formatter responds to the $type parameter passed in the JSON to allow us to correctly map object types
//https://kirmir.wordpress.com/2014/05/16/polymorphic-serialization-using-newton-json-net-in-httpcontent/
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = { TypeNameHandling = TypeNameHandling.Auto }
};
List<MyBaseClass> thingsToReturn;
thingsToReturn = response.Content.ReadAsAsync<List<MyBaseClass>>(new List<MediaTypeFormatter> { formatter }).Result;
return productTestsToReturn;
}
HttpResponseMessage response=GetClient().GetAsync(url).Result;
if(响应。IsSuccessStatusCode)
{
//此格式化程序响应JSON中传递的$type参数,以允许我们正确映射对象类型
//https://kirmir.wordpress.com/2014/05/16/polymorphic-serialization-using-newton-json-net-in-httpcontent/
var formatter=新的JsonMediaTypeFormatter
{
SerializerSettings={TypeNameHandling=TypeNameHandling.Auto}
};
列出所需物品;
thingsToReturn=response.Content.ReadAsAsync(新列表{fo
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
[Newtonsoft.Json.JsonProperty(ItemTypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto)]
public virtual List<MyBaseClass> Things { get; set; }
dbContext.Configuration.ProxyCreationEnabled = false;
List<MyBaseClass> things = dbContext.MyBaseClasses.Include("This").Include("That").ToList();
HttpResponseMessage response = GetClient().GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
//this formatter responds to the $type parameter passed in the JSON to allow us to correctly map object types
//https://kirmir.wordpress.com/2014/05/16/polymorphic-serialization-using-newton-json-net-in-httpcontent/
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = { TypeNameHandling = TypeNameHandling.Auto }
};
List<MyBaseClass> thingsToReturn;
thingsToReturn = response.Content.ReadAsAsync<List<MyBaseClass>>(new List<MediaTypeFormatter> { formatter }).Result;
return productTestsToReturn;
}