在 webapi 中使用 OData 获取仅在运行时已知的属性

2023-11-27

假设我有一个非常简单的类型,我想使用 .NET C# webapi 控制器将其作为集合的一部分公开在 OData feed 上:

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 中,我执行标准操作来配置它:

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

根据 Excel 的说法,这是一个很棒的提要。但在我的集合中,该 propBag 包含其他数据的有限列表(例如“a”、“b”和“c”或类似数据)。我希望它们作为我的 OData feed 中的额外属性。我的第一个想法是在配置发生时尝试这样的事情:

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

这完全失败了,因为这实际上是传入的表达式树,而不是 lambda 函数,并且此方法尝试解析它。并期望属性取消引用。

我应该朝什么方向走?对于某些上下文:我正在尝试使用单个简单的平面对象创建一个 odata 只读源。按照网上找到的教程,让简单版本工作很容易。

Update:

下面的 cellik 给我指出了一个方向。我只是尽我所能地跟着它,而且我已经非常接近了。

首先,我创建了一个属性信息类来表示动态属性:

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); }
    }
}

正如您所看到的,需要实现的方法很少。然后我创建了一个自定义序列化器:

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 Register 方法中配置的:

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

最后,我创建 Image 类,并向其添加“a”属性:

        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 为 null。事实上,它是一个已折旧的属性 - 您将使用 EdmObject 代替。这确实有一个对实际对象实例的引用。然而,在当前的每晚构建中(您必须拥有它才能使其中任何一个工作),EdmObject 的访问是内部的 - 因此无法使用它。

更新 2:有一些关于此的最少文档asp CodePlex 网站.

非常接近!


并不是真正解决您的问题,但希望这会有所帮助。

这是我们待办事项中最重要的功能之一。在我们团队内部引用时,我们倾向于将其称为“无类型支持”。

Web API 的问题在于,它需要为服务公开的每个 EDM 类型提供强大的 CLR 类型。此外,CLR 类型和 EDM 类型之间的映射是一对一且不可配置的。这也是大多数 IQueryable 实现的工作方式。

无类型支持的想法是打破这一要求,并为 EDM 类型提供支持,而无需支持强大的 CLR 类型。例如,您的所有 EDM 实体都可以由键值字典支持。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 webapi 中使用 OData 获取仅在运行时已知的属性 的相关文章

随机推荐

  • Mac OS X 上的黑莓开发

    我最近开始为移动设备创建应用程序 并成功完成了 iPhone 的应用程序 我现在将注意力转向黑莓 但尚未找到令人信服的文章或网站来说明可以做到这一点 也找不到有关如何做到这一点的教程 可以在 Mac OS X 上开发 Blackberry
  • 告诉 GCC *不*链接 libgomp,以便它链接 libiomp5

    我需要找出一个可以输入 gcc 的编译器 链接器指令 以便在指定 fopenmp 时它不会自动链接 libgomp 原因是我正在尝试针对英特尔的 MKL BLAS 进行构建 MKL 需要添加单独的 Intel 库来处理多线程 例如 libm
  • 使用 pkg-config 宏 PKG_CHECK_MODULES 失败

    我确信这是一个相当简单的问题 我有一个非常简单的configure ac 文件 我用它来学习autoconf 和pkg config 如何协同工作 这confgure ac文件看起来像 AC PREREQ 2 61 AC INIT auto
  • 如何判断html页面的哪个元素获得焦点? [复制]

    这个问题在这里已经有答案了 可能的重复 如何找出哪个 DOM 元素具有焦点 javascript 有没有办法确定哪个 html 页面元素具有焦点 Use the document activeElement财产 The document a
  • 在 Bloomberg API 中,如何指定以点差而不是绝对值的形式获取外汇远期?

    如何使用 Bloomberg API 明确请求直接外汇远期 在彭博终端中 您可以通过执行 XDF 选择是否以绝对汇率 直接 或即期 点 的形式获得外汇远期 达到 7 则该选项大约下降了一半 0 表示直接 1 表示偏移 对于大多数默认值 您可
  • 如何在 Web API 中使用“User.Identity.IsAuthenticated”

    User Identity IsAuthenticated总是返回false在我的 ASP NET Web API 项目中 账户内ApiController我有以下内容 ClaimsIdentity identity new ClaimsI
  • 将字符串分割成句子

    我编写了这段代码 用于分割字符串并将其存储在字符串数组中 String sSentence sResult split a z s 但是 我添加了 a z 因为我想处理一些缩写问题 但后来我的结果显示如下 此外 当埃弗里特试图指导他们基础数
  • 错误 C7626:typedef 名称中使用的未命名类无法声明非静态数据成员以外的成员,

    我正在VS2022中使用C 来构建一个项目 我必须包含来自名为的 sdk 的头文件eve h 我已将保存此文件的包含文件夹添加到项目属性中 然而 当我构建这个项目时 我收到许多 C7626 错误 说明以下内容 并指向eve h file E
  • SFINAE 构造函数[重复]

    这个问题在这里已经有答案了 我一直很喜欢像这样的函数 SFINAE 语法 似乎通常工作得很好 template
  • 谷歌浏览器不会在单选按钮上触发模糊事件?

    这是我在此的头一篇博文 大家好 我目前正在开发一个html表单 支持css和jquery 该表单将由 没有经验的用户 使用 因此我的重点在于良好的可用性 因此 我为每个输入字段提供提示以及进一步的说明 为了显示提示 我使用了 onfocus
  • 带有“或”条件的 MongoDB 查询

    所以我有一个跟踪组成员资格的嵌入式文档 每个嵌入文档都有一个指向另一个集合中的组的 ID 开始日期和optional到期日期 我想查询某个组的当前成员 当前 表示开始时间小于当前时间 过期时间大于当前时间或为空 这个条件查询完全阻碍了我 我
  • 将 ASP.NET Web API 应用程序配置为 ASP.NET MVC 应用程序下的虚拟目录

    由于各种工程需求 我需要在现有应用程序 名为 FooApp 的同一应用程序域内开发一个新的 ASP NET Web API 应用程序 名为 BarApp 我想将 ASP NET Web API 应用程序 BarApp 配置为 IIS 8 5
  • iOS开发者可以查看文件系统吗?

    我想知道开发人员是否有某种方法可以在不越狱设备的情况下查看 iOS 设备上的文件系统 例如 iFile 需要它用于开发目的 编辑 感谢您的回答 我知道应用程序文件夹中有一个位置可以读取和写入 但我一直在寻找一种无需编码即可快速查看数据的方法
  • 如何使用 Jest 测试 Thunk 操作?

    我是使用 Jest 对 Redux Thunk 异步操作进行单元测试的新手 这是我的代码 export const functionA a b gt dispatch gt dispatch type CONSTANT A payload
  • 增强的 For 循环异常 [重复]

    这个问题在这里已经有答案了 在玩循环时创建了以下代码 下面的代码将斐波那契值存储到一个数组中 然后使用 for 循环打印它们 int numbers numbers new int 25 numbers 0 1 numbers 1 1 Sy
  • Swift:检测精灵套件 SKShapeNode 绘图的相交

    I m drawing with Sprite Kit I would like to detect when user s drawings are intersecting 我尝试遵循代码 但它不起作用 看起来精灵套件并没有保存所有的点
  • 如何在sql中将字符串拆分为变量?

    我有一个看起来像这样的字符串BAT CAT RAT MAT我想把这个字符串分成4部分 然后将它们存储到4个不同的变量中 分别是 a b c d 在sql中如何实现呢 用于围绕 char 进行拆分 DECLARE A VARCHAR 100
  • 如何解决 npm 中的(读取“isServer”)错误?

    在 npm i 之后捕获此错误 版本 npm 8 0 0 nodejs 16 11 0 npm ERR Cannot read properties of undefined reading isServer 我对 Node 和 npm 的
  • 在 ASP.NET MVC 中编译视图

    我想要一个 msbuild 任务来编译视图 以便我可以查看是否存在编译时错误 编译时 有任何想法吗 来自 RC1 的自述文件 未由谷歌索引 ASP NET 编译器构建后步骤 目前 视图文件中的错误只有在运行时才会被检测到 为了让您在编译时检
  • 在 webapi 中使用 OData 获取仅在运行时已知的属性

    假设我有一个非常简单的类型 我想使用 NET C webapi 控制器将其作为集合的一部分公开在 OData feed 上 public class Image