在序列化方面,伤害你的是由微风提供的中间 EdmBuilder。见:https://github.com/Breeze/breeze.server.labs/blob/master/EdmBuilder.cs
由于 EdmBuilder.cs 的 cmets 中定义的限制
我们需要 EDM 来定义 Web API OData 路由并作为 Breeze 客户端的元数据源。 Web API OData 文献推荐 System.Web.Http.OData.Builder.ODataConventionModelBuilder。
该组件足以定义路由,但无法作为 Breeze 的元数据源,因为(在撰写本文时)它忽略了包含 Breeze 维护客户端 JavaScript 实体的导航属性所需的外键定义。
此 EDM 生成器要求 EF DbContext 提供满足路由定义和 Breeze 的元数据。
您只会获得 EntityFramework 选择公开的元数据。这可以防止 OData 格式化程序/序列化程序包含该属性 - 它未映射到模型元数据中。
您可以尝试使用自定义序列化程序的解决方案,类似于本文中介绍的内容。 Using OData in webapi for properties known only at runtime
自定义序列化程序大致如下所示(注意:这不起作用..继续阅读,下面...)
public class CustomEntitySerializer : ODataEntityTypeSerializer
{
public CustomEntitySerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider) { }
public override ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
{
ODataEntry entry = base.CreateEntry(selectExpandNode, entityInstanceContext);
Request item = entityInstanceContext.EntityInstance as Request;
if (entry != null && item != null)
{
// add your "NotMapped" property here.
entry.Properties = new List<ODataProperty>(entry.Properties) { new ODataProperty { Name = "UserName", Value = item.UserName} };
}
return entry;
}
}
问题在于底层 ODataJsonLightPropertySerializer 在尝试写入时会检查模型是否存在属性。它调用 Microsoft.Data.OData.WriterValidationUtils 类中的 ValidatePropertyDefined 方法。
internal static IEdmProperty ValidatePropertyDefined(string propertyName, IEdmStructuredType owningStructuredType)
这将使您因运行时异常而失败:
类型“YourNamespace.Models.Request”上不存在属性“用户名”
.确保仅使用由类型定义的属性名称。","type":"Microsoft.Data.OData.ODataException"
"stacktrace":" 在 Microsoft.Data.OData.WriterValidationUtils.ValidatePropertyDefined (String propertyName
, IEdmStructuredType owningStructuredType)\r\n 在 Microsoft.Data.OData.JsonLight.ODataJsonLightPropertySerializer
.WriteProperty(ODataProperty 属性, IEdmStructuredType owningType, Boolean isTopLevel, Boolean allowStreamProperty
, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectionProperties
底线是需要在模型中定义属性才能对其进行序列化。可以想象,您可以重写序列化层的大部分内容,但是 OData 框架中有很多内部/静态/私有/非虚拟位,这让人不快。
解决方案最终以 Breeze 强制您生成模型的方式呈现。假设代码优先实现,您可以将其他模型元数据直接注入到 EntityFramework 生成的 XmlDocument 中。采用 Breeze EdmBuilder 中的方法,稍作修改:
static IEdmModel GetCodeFirstEdm<T>(this T dbContext) where T : DbContext
{
// create the XmlDoc from the EF metadata
XmlDocument metadataDocument = new XmlDocument();
using (var stream = new MemoryStream())
using (var writer = XmlWriter.Create(stream))
{
System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(dbContext, writer);
stream.Position = 0;
metadataDocument.Load(stream);
}
// to support proper xpath queries
var nsm = new XmlNamespaceManager(metadataDocument.NameTable);
nsm.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl");
nsm.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2009/11/edmx");
nsm.AddNamespace("edm", "http://schemas.microsoft.com/ado/2009/11/edm");
// find the node we want to work with & add the 1..N property metadata
var typeElement = metadataDocument.SelectSingleNode("//edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/edm:Schema/edm:EntityType[@Name=\"Request\"]", nsm);
// effectively, we want to insert this.
// <Property Name="UserName" Type="String" MaxLength="1000" FixedLength="false" Unicode="true" Nullable="true" />
var propElement = metadataDocument.CreateElement(null, "Property", "http://schemas.microsoft.com/ado/2009/11/edm");
propElement.SetAttribute("Name", "UserName");
propElement.SetAttribute("Type", "String");
propElement.SetAttribute("FixedLength", "false");
propElement.SetAttribute("Unicode", "true");
propElement.SetAttribute("Nullable", "true");
// append the node to the type element
typeElement.AppendChild(propElement);
// now we're going to save the updated xml doc and parse it.
using (var stream = new MemoryStream())
{
metadataDocument.Save(stream);
stream.Position = 0;
using (var reader = XmlReader.Create(stream))
{
return EdmxReader.Parse(reader);
}
}
}
这会将属性放入要由 OData 层使用的元数据中,并且不需要任何额外的步骤来促进序列化。但是,您需要注意如何塑造模型元数据,因为任何需求/规范都将反映在 Breeze 的客户端验证中。
我已经在 Breeze 提供的 ODataBreezejs 示例中验证了这种方法的 CRUD 操作。 https://github.com/Breeze/breeze.js.samples/tree/master/net/ODataBreezejsSample