在使用的WebAPI的OData只在运行时已知特性 [英] Using OData in webapi for properties known only at runtime

查看:90
本文介绍了在使用的WebAPI的OData只在运行时已知特性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一个非常简单的类型,我想用.NET C#的WebAPI控制器上的OData源公开为集合的一部分:

Say I have a very simple type which I'd like to expose on an OData feed as part of a collection using a .NET C# webapi controller:

public class Image
{
    /// <summary>
    /// Get the name of the image.
    /// </summary>
    public string Name { get; set; }

    public int Id { get; set; }

    internal System.IO.Stream GetProperty(string p)
    {
        throw new System.NotImplementedException();
    }

    private Dictionary<string, string> propBag = new Dictionary<string, string>();
    internal string GetIt(string p)
    {
        return propBag[p];
    }
}

在我WebApiConfig.cs我做事情的标准对其进行配置:

In my WebApiConfig.cs I do the standard thing to configure it:

        ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
        var imagesES = modelBuilder.EntitySet<Image>("Images");

而根据Excel中,这是一个伟大的饲料。但是,在我的收藏,那propBag包含其他数据的有限列表(说A,B和C或类似)。我希望他们在我的OData源作为额外的属性。我首先想到的是去尝试这样的东西时,配置发生了:

And according to Excel, this is a great feed. But in my collection, that propBag contains a finite list of other data (say "a", "b", and "c" or similar). I'd like them as extra properties in my OData feed. My first thought was to try something like this when the configuration happened:

        ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
        var imagesES = modelBuilder.EntitySet<Image>("Images");
        images.EntityType.Property(c => c.GetIt("a"))

这完全失败,因为,实际上是在不lambda函数传递一个前pression树,这种方法使得试图解析它。并预计财产去参考。

This fails completely because that is actually an expression tree that is being passed in, not a lambda function, and this method makes an attempt to parse it. And expects a property de-reference.

什么方向,我应该去会在这里?对于一些背景:我试图创建一个ODATA只读用一个简单的平面对象源。获取简单的版本是工作在网络上很容易找到以下教程。

What direction should I be going in here? For some context: I'm trying to create an odata read-only source with a single simple flat object. Getting the simple version working was easy following tutorials found on the web.

更新:

cellik,下面,我指出一个方向。我只是跟着它,据我可以走了,和我非常接近了。

cellik, below, pointed me in one direction. I just followed it as far as I could go, and I got very close.

首先,我创建了一个酒店信息类重新present动态特性:

First, I created a property info class to represent the dynamic properties:

public class LookupInfoProperty : PropertyInfo
{
    private Image _image;
    private string _propName;
    public LookupInfoProperty(string pname)
    {
        _propName = pname;
    }

    public override PropertyAttributes Attributes
    {
        get { throw new NotImplementedException(); }
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override MethodInfo[] GetAccessors(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override MethodInfo GetGetMethod(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override ParameterInfo[] GetIndexParameters()
    {
        throw new NotImplementedException();
    }

    public override MethodInfo GetSetMethod(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override Type PropertyType
    {
        get { return typeof(string); }
    }

    public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override Type DeclaringType
    {
        get { throw new NotImplementedException(); }
    }

    public override object[] GetCustomAttributes(Type attributeType, bool inherit)
    {
        throw new NotImplementedException();
    }

    public override object[] GetCustomAttributes(bool inherit)
    {
        return new object[0];
    }

    public override bool IsDefined(Type attributeType, bool inherit)
    {
        throw new NotImplementedException();
    }

    public override string Name
    {
        get { return _propName; }
    }

    public override Type ReflectedType
    {
        get { return typeof(Image); }
    }
}

正如你所看到的,只有极少数的方法需要被实现。然后,我创建了一个自定义序列:

As you can see, very few of the methods need to be implemented. I then created a custom serializer:

public class CustomSerializerProvider : DefaultODataSerializerProvider
{
    public override ODataEdmTypeSerializer CreateEdmTypeSerializer(IEdmTypeReference edmType)
    {
        if (edmType.IsEntity())
        {
            // entity type serializer
            return new CustomEntityTypeSerializer(edmType.AsEntity(), this);
        }
        return base.CreateEdmTypeSerializer(edmType);
    }
}

public class CustomEntityTypeSerializer : ODataEntityTypeSerializer
{
    public CustomEntityTypeSerializer(IEdmEntityTypeReference edmType, ODataSerializerProvider serializerProvider)
        : base(edmType, serializerProvider)
    {
    }

    /// <summary>
    /// If we are looking at the proper type, try to do a prop bag lookup first.
    /// </summary>
    /// <param name="structuralProperty"></param>
    /// <param name="entityInstanceContext"></param>
    /// <returns></returns>
    public override ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, EntityInstanceContext entityInstanceContext)
    {
        if ((structuralProperty.DeclaringType as IEdmEntityType).Name == "Image")
        {
            var r = (entityInstanceContext.EntityInstance as Image).GetIt(structuralProperty.Name);
            if (r != null)
                return new ODataProperty() { Name = structuralProperty.Name, Value = r };
        }
        return base.CreateStructuralProperty(structuralProperty, entityInstanceContext);
    }
}

这是在我的WebApiConfig注册的方法进行配置:

Which are configured in my WebApiConfig Register method:

config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new CustomSerializerProvider(), new DefaultODataDeserializerProvider()));

最后,我创建了图片类,而一属性添加到它:

And, finally, I create the Image class, and add the "a" property to it:

        ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
        var imagesES = modelBuilder.EntitySet<Image>("Images");
        var iST = modelBuilder.StructuralTypes.Where(t => t.Name == "Image").FirstOrDefault();
        iST.AddProperty(new LookupInfoProperty("a"));
        Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
        config.Routes.MapODataRoute("ODataRoute", "odata", model);

有只有一个问题 - 在大多数来自Excel等客户端来测试数据的查询,EntityInstance为空。事实上,这是一个去preciated财产 - 你是使用EdmObject来代替。这确实有实际的对象实例的引用。然而,在目前的每晚构建(你必须有任何的这个工作)的EdmObject的访问是内部的 - 并且因此不能使用它

There is only one problem - in most of the test queries coming from a client like Excel, the EntityInstance is null. Indeed, it is a depreciated property - you are to use EdmObject instead. And that does have a reference to the actual object Instance. However, in the current nightly builds (which you must have for any of this to work) the EdmObject's access is internal - and so one can't use it.

更新2:有关于<一个这方面的一些最低限度的文件href=\"https://aspnetwebstack.$c$cplex.com/wikipage?title=OData%20formatter%20extensibility&referringTitle=Specs\"相对=nofollow> ASP codePLEX网站。

所以非常接近!

推荐答案

不是一个真正的解决问题的方法,但希望这有助于。

Not really a solution to your problem but hope this helps.

这是在我们的积压顶部的功能之一。我们倾向于称之为无类型支持在内部我们的团队同时参考它。

This is one of the top features in our backlog. We tend to call it 'Typeless support' internally in our team while referring it.

与网络API的问题是,它要求每个与该服务是暴露每个电火花类型强烈CLR类型。此外,CLR类型与EDM类型之间的映射是一对一不可配置。这也是最IQueryable的实现是如何工作了。

The problem with web API is that it requires a strong CLR type for each and every EDM type that the service is exposing. Also, the mapping between the CLR type and the EDM type is one-to-one and not configurable. This is also how most IQueryable implementations work too.

与无类型的支持,我们的想法是要打破这种要求和有EDM类型,而一个强大的后盾CLR类型提供支持。例如,您的所有EDM实体可以通过键值的字典进行备份。

The idea with typeless support is to break that requirement and provide support for having EDM types without a backing strong CLR type. For example, all your EDM entities can be backed by a key-value dictionary.

这篇关于在使用的WebAPI的OData只在运行时已知特性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆