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
等等

使用Linq
context.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;
}