7

有谁知道如何在 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
我当前的解决方法是创建一个看起来像我的实体的部分类,然后创建一个接口来包含数据注释。
给实体框架生成的类添加数据注解

4

0 回答 0