有谁知道如何在 OData V4 的元数据中设置/读取基于词汇的注释来定义诸如最大字符串长度之类的东西?
有一篇文章客户端注释支持,但它没有显示任何示例代码,而且我不能 100% 确定他们甚至在谈论数据注释。
它有如下代码:
var person = dsc.People.ByKey("russellwhyte").GetValue();
// Try to get an annotation for a property
dsc.TryGetAnnotation<Func<ObservableCollection<string>>, string>(() => person.Emails, fullQualifiedTermName, qualifier, out annotation);
但它没有解释“fullQualifiedTermName”或“qualifier”使用什么。
我正在添加“odata.inculde-annotations=*”,但这似乎没有帮助。
我也尝试过以下方法。
dsc.TryGetAnnotation<Func<string>, string>(() => person.FirstName, "System.ComponentModel.DataAnnotations", out annotation);
但这只会返回null。
我在 2012 年发现了一篇文章Vocabularies in WCF Data Services,其中讨论了对验证元数据的支持。
我要试一试。
我希望在 OData V4 中有一种简单/更好的方法来做到这一点。
更新 1
WCF 词汇表示例在 OData V4 中不起作用,因为 System.Web.Http.HttpConfiguration 中缺少 config.AnnotationsBuilder。
OData V4 支持此处定义的词汇表http://www.odata.org/vocabularies/甚至提供我需要的“元数据注释可以定义特定属性的有效值范围”但似乎没有任何示例代码SAP https://blogs.sap.com/2013/10/07/vocabulary-based-annotations/以外的任何文章使用它。
更新 2
在查看TripPinService之后,我注意到他们有一些预算注释,如下所示。
<Property Name="Budget" Type="Edm.Single" Nullable="false">
<Annotation Term="Org.OData.Measures.V1.ISOCurrency" String="USD"/>
<Annotation Term="Org.OData.Measures.V1.Scale" Int="2"/>
</Property>
幸运的是,该项目的源代码是ODataSamples TripPin
查看服务后,我发现我首先必须创建自己的 xml 词汇表文件。(验证词汇表.xml)
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Org.OData.Validation.V1" Alias="Validation">
<Term Name="StringLength" Type="Edm.String" AppliesTo="Property">
<Annotation Term="Core.Description" String="Set max length of string." />
</Term>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
在 WebApiConfig 文件中,我必须访问 xml 文件并将词汇注释添加到元数据中。
我很幸运,TripPin 的源代码为此提供了一个很好的帮助类。(我将其修改为如下所示)
public static class DataValidationHelpers
{
public static readonly IEdmModel Instance;
public static readonly IEdmTerm StringLengthTerm;
internal const string StringLength = "Org.OData.Validation.V1.StringLength";
static DataValidationHelpers()
{
using (var stream = System.IO.File.OpenRead(System.Web.HttpContext.Current.Server.MapPath("~/bin") + @"\App_Start\ValidationVocabularies.xml"))
{
IEnumerable<EdmError> errors;
System.Xml.XmlReader reader = System.Xml.XmlReader.Create(stream);
CsdlReader.TryParse(reader, out Instance, out errors);
}
StringLengthTerm = Instance.FindDeclaredTerm(StringLength);
}
public static void SetStringLengthAnnotation(this EdmModel model, IEdmProperty property, int length)
{
if (model == null) throw new ArgumentNullException("model");
if (property == null) throw new ArgumentNullException("property");
var target = property;
var term = StringLengthTerm;
var expression = new EdmIntegerConstant(length);
var annotation = new EdmVocabularyAnnotation(target, term, "StringLength", expression);
annotation.SetSerializationLocation(model, EdmVocabularyAnnotationSerializationLocation.Inline);
model.AddVocabularyAnnotation(annotation);
}
}
然后我从 GetEdmModel() 方法内部调用它,如下所示:
var target = ((EdmEntityType)edmModel.FindDeclaredType("Test.Models.Person")).FindProperty("FirstName");
((EdmModel)edmModel).SetStringLengthAnnotation(target, 50);
如果有人知道如何通过名称而不是某个字符串值来访问该属性,那就太好了。
我确实尝试了 builder.EntityType().Property(p => p.FirstName) 但该类型不是 IEdmProperty。
无论如何继续前进......
所以现在使用我的浏览器访问 $metadata 我可以清楚地看到 FirstName 上的字符串长度属性。
<Property Name="FirstName" Type="Edm.String">
<Annotation Term="Org.OData.Validation.V1.StringLength" Qualifier="StringLength" Int="50"/>
</Property>
这很好,但现在讨论下一个问题。如何从客户那里得到它?
好吧,一开始我试过了。
DbContext.TryGetAnnotation<string>(personQueryResponse.FirstName, "Org.OData.Validation.V1.StringLength", out annotation);
但这给了我以下错误。
值不能为空。参数名称:element 然后我尝试了:
DbContext.TryGetAnnotation<Func<string>, string>(() => personQueryResponse.FirstName, "Org.OData.Validation.V1.StringLength", out annotation);
但是注释为空。
我注意到调用 TryGetAnnotation 不会再次调用 OData 服务。
所以我想我必须阅读客户端 CSDL 文件,所以我回顾了 WCF 文章,但他们没有告诉你他们从哪里得到“注释”集合。
我仍在挖掘,但这正在成为一个失败的原因。
令人遗憾的是,微软想将 OData 作为一项如此出色的服务推出,但文档很少,支持小组也很小。
我有 4 个未解决的 OData 问题,而且命中率很低。
不要误会我的意思,我喜欢 OData,但这是一种爱/恨的关系。
更新 3
我当前的解决方法是创建一个看起来像我的实体的部分类,然后创建一个接口来包含数据注释。
给实体框架生成的类添加数据注解