如何从 C# 控制器(OData)的 JSON 序列化中修复丢失的子对象(导航属性)?
Posted
技术标签:
【中文标题】如何从 C# 控制器(OData)的 JSON 序列化中修复丢失的子对象(导航属性)?【英文标题】:How to fix a missing child object (navigation property) from JSON serialization from C# controller (OData)? 【发布时间】:2014-04-25 22:57:07 【问题描述】:堆栈:MVC5、WebAPI、OData、EF6
在 MVC 控制器中,我返回一个序列化为 JSON 对象的对象:
.Select(s => new ProjectEditorDTO()
// projection
WebsiteId = s.WebsiteId,
WebsiteGUID = s.WebsiteGUID,
WebsiteName = s.WebsiteName,
WebsiteNotes = s.WebsiteNotes,
Test = "some test string",
DefaultContentType = new ContentTypeDTO
ContentTypeId = s.DefaultContentTypeID,
Description = s.ContentType.Description
);
var r = results.ToList(); // contains DefaultContentType object
return Ok(results, results.GetType());
问题是当我在 Fiddler 中查看返回的数据时,它缺少 JSON 对象内的DefaultContentType
数据。
我有另一个控制器使用相同的对象(单独),并且返回很好。
仅供参考,这里是ContentTypeDTO
:
public class ContentTypeDTO
public int ContentTypeId get; set;
[Required]
[StringLength(100, MinimumLength=3)]
[Display(Name="Content Type")]
public string Description get; set;
//public int NumberOfContentTypes get; set;
//public UserDTO UserDTO get; set;
我正在使用 WebAPI,并将其配置如下以返回 JSON 内容:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
-- 更新--
我正在使用 WebAPI 和 OData,因此生成的调用必须包含 ProjectEditorDTO
对象形式的 ProjectEditor
目标:
modelBuilder.EntitySet<Core.UI.Models.ProjectEditorDTO>("ProjectEditor");
从客户端返回的数据是通过 OData URL 完成的:
?$format=json&$inlinecount=allpages&$top=10
当我添加 $expand=
语法 ($format=json&$inlinecount=allpages&$top=10&$expand=DefaultContentTypeID
) 时,我收到以下错误:
类型 ... 上的属性“DefaultContentTypeID”不是导航属性。只能展开导航属性。
即使在数据库中这被设置为 FK。
我猜测缺少一些扩展语法并确保导航属性有效?
我在这方面一定遗漏了一些非常小的东西......建议?
【问题讨论】:
您的DefaultContentType
是否可以在声明类/命名空间之外访问?也许有什么?
ProjectEditorDTO
内部:public ContentTypeDTO DefaultContentType get; set;
。指的就是这个吧?
是的。没关系,只要确保它可以访问,否则我们可能已经在这里很长时间了! :)
我认为这更多是暴露导航属性的问题。我将重新提出问题以更好地反映这一点。
【参考方案1】:
我看不到 JSON 序列化在哪里。我猜是在Ok
方法中。就我所见,我看到您传递了一个自定义对象,用于像 JSON 对象一样对待。您可以在投影集合时尝试使用通用对象吗?只是避免使用您的类来定义对象,如下所示:
.Select(s => new
// projection
WebsiteId = s.WebsiteId,
WebsiteGUID = s.WebsiteGUID,
WebsiteName = s.WebsiteName,
WebsiteNotes = s.WebsiteNotes,
Test = "some test string",
DefaultContentType = new
ContentTypeId = s.DefaultContentTypeID,
Description = s.ContentType.Description
);
【讨论】:
我更新了显示 JSON 序列化在何处完成的问题。由于我使用的是 WebAAPI 和 OData,因此输出对象定义为ProjectEditorDTO
并且必须与之匹配。当我将其设置为泛型类型时,我收到一个错误,因为它必须是 ProjectEditorDTO
。
哦!我现在看到更新了。抱歉,我想我们是同时写的。我不知道这些东西是如何工作的,但我认为你需要在你的ProjectEditorDTO
类中将DefaultContentType
propertie 设置为virtual
。你能检查一下吗?【参考方案2】:
很抱歉迟到了,我刚看了这个问题。 我遇到了同样的问题,我修复了它,将 [Key] 属性添加到 DTO 类的 id 字段中。有了它,子对象就被正确地视为 NavigationProperty,并且可以毫无错误地调用 $expand。
【讨论】:
以上是关于如何从 C# 控制器(OData)的 JSON 序列化中修复丢失的子对象(导航属性)?的主要内容,如果未能解决你的问题,请参考以下文章