使用词汇注释的OData V4传递数据注释

时间:2016-10-25 13:59:13

标签: asp.net-web-api2 odata data-annotations wcf-data-services odata-v4

有没有人知道如何在OData V4的metatdata中设置/读取基于词汇的注释来定义最大字符串长度等内容?

有一篇文章Client Annotation Support,但它没有显示任何示例代码,我也不是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词汇表文件。 (ValidationVocabularyies.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);

如果有人知道如何通过Name而不是某些字符串值知道该属性,那将是很好的 我确实尝试过builder.EntityType()。Property(p =&gt; p.FirstName)但该类型不是IEdmProperty。
无论如何继续前进...
所以现在使用我的浏览器来获取$元数据我可以清楚地看到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文章,但他们没有告诉你他们在哪里获得了“annotations”集合。

我还在挖掘,但这已成为一个失败的原因 很遗憾微软希望将OData推向如此优质的服务,但几乎没有文档和非常小的支持小组。
我有4个开放的OData问题和很少的点击率 不要误会我的意思,我喜欢OData,但这是一种爱/恨的关系。

更新3
我目前的解决方法是创建一个看起来像我的实体的分部类,然后创建一个包含数据注释的接口 Add data annotations to a class generated by entity framework

0 个答案:

没有答案