【问题标题】:How can I include the dynamic response properties of an OData web api operation on the top level of the response?如何在响应的顶层包含 OData Web api 操作的动态响应属性?
【发布时间】:2022-02-21 17:58:35
【问题描述】:

我构建了一个基于 .net 6 并集成了 Microsoft.AspNetCore.OData 的 c# web api。 我使用字典在我的响应中包含动态属性:

    public class TestObj
    {
        public string Id { get; set; }

        public IDictionary<string, object> Properties { get; set; }

        public TestObj()
        {
            Properties = new Dictionary<string, object>();
        }
    }

我的 GET 操作的示例响应:

{
  "id": "TestId",
  "properties": {
    "key1": "value1",
    "key2": "value2"
  }
}

但我想要响应顶层的属性字典的键值对:

{
  "id": "TestId",
  "key1": "value1",
  "key2": "value2"
}

这可能吗?我尝试了不同的方法,但没有找到解决方案。

【问题讨论】:

    标签: c# odata asp.net-core-webapi


    【解决方案1】:

    您的回复与 OData 的回复不同。 OData 响应应如下所示:

    {
        "@odata.context": "https://localhost:44383/odata/$metadata#TestObj",
        "value": [
            {
                "Id": "TestId"
            }
        ]
    }
    

    所以,请检查您的控制器和路由:

    1. 您的控制器必须继承自 ODataController
    2. 您的请求将发送到 odata 路由

    如果您的班级中有字典并且您使用 ODataConventionModelBuilder,它将自动使其成为 OpenType:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/use-open-types-in-odata-v4

    所以,如果您使用的是 ODataModelBuilder,您需要像这样配置您的字典:

     static IEdmModel GetEdmModel()
            {
                var odataBuilder = new ODataModelBuilder();
    
                var classExample = odataBuilder.EntityType<TestObj>();
                classExample.HasKey(s => s.Id);
                classExample.HasDynamicProperties(d => d.Properties);
                odataBuilder.EntitySet<TestObj>("TestObj");
                return odataBuilder.GetEdmModel();
            }
    

    那么您的回复将如下所示:

    {
        "@odata.context": "https://localhost:44383/odata/$metadata#TestObj",
        "value": [
            {
                "Id": "TestId",
                "key1": "value1",
                "key2": "value2"
            }
        ]
    }
    

    【讨论】:

    • 感谢您的回复。我忘了提一下:在我的 asp.net 4.7 环境中,一切正常。但是在我将它迁移到 .net core (v6) 之后,我遇到了问题,在每个响应中,我都得到了动态属性的封闭属性 {} 属性。我尝试了几个使用 .net5 和 .net6 的示例项目(基于 Microsoft 的 WeatherForeCast 示例),也使用您的示例代码,但没有成功。
    • 您提到:“..您的请求将转到 odata 路由..”像 $select 这样的 OData 属性的使用效果很好,所以我假设请求将转到 odata 路由。
    • @Markus 你能展示你的配置吗?您的 OData 包版本是什么?
    【解决方案2】:

    我尝试了几个 OData 包版本,例如.net5 示例项目中的 Microsoft.AspNetCore.OData 7.5.12。 因为我的真正目标是将现有的 asp.net v4 REST api 迁移到 .net6,所以我还使用 VS2022 对 .net6 和 Microsoft.AspNetCore.OData 8.0.7 进行了一些测试

    虽然为这篇文章精简了基于 .net6 / Microsoft.AspNetCore.OData 8.0.7 的示例代码,但我取得了第一个成功! 现在 Swagger 站点显示了两个 GET 操作: 获取 /DynProp 和 获取 /odata/DynProp。 /odata/DynProp 操作正确显示动态属性!!! 现在我有了一个可以用于迁移的基础。下一步将是:配置路由(例如,从 Swagger 中删除非 OData 操作并为我的操作自定义 OData 路由路径)。 非常感谢您的提示和建议,帮助我不放弃。

    我的工作示例代码:

    控制器:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.OData.Query;
    using Microsoft.AspNetCore.OData.Routing.Controllers;
    
    namespace DynProp.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class DynPropController : ODataController
        {
            [EnableQuery]
            [HttpGet(Name = "GetDyn")]
            public IEnumerable<DynProp> Get()
            {
                List<DynProp> list = new List<DynProp>();
    
                DynProp obj1 = new DynProp();
                obj1.Id = "TestId";
                obj1.Properties.Add("key1", "value1");
                obj1.Properties.Add("key2", "value2");
                list.Add(obj1);
    
                DynProp obj2 = new DynProp();
                obj2.Id = "TestId2";
                obj2.Properties.Add("key1", "value3");
                obj2.Properties.Add("key2", "value4");
                list.Add(obj2);
    
                return list;
            }
        }
    }
    

    DynProp 类/EDM:

    using Microsoft.OData.Edm;
    using Microsoft.OData.ModelBuilder;
    using System.ComponentModel.DataAnnotations;
    
    namespace DynProp
    {
        public class DynProp
        {
            [Key]
            public string Id { get; set; }
            public IDictionary<string, object> Properties { get; set; }
    
            public DynProp()
            {
                Id = "";
                Properties = new Dictionary<string, object>();
            }
        }
    
        public class TestDataModel
        {
            public IEdmModel GetEdmModel()
            {
                var odataBuilder = new ODataModelBuilder();
    
                var classExample = odataBuilder.EntityType<DynProp>();
                classExample.HasKey(s => s.Id);
                classExample.HasDynamicProperties(d => d.Properties);
                var entitySet = odataBuilder.EntitySet<DynProp>("DynProp");
                return odataBuilder.GetEdmModel();
            }
        }
    }
    

    Program.cs(在 .net6 中包括 Startup.cs 的所有部分)

    using DynProp;
    using Microsoft.AspNetCore.OData;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllers().AddOData(options =>
    {
        options.Select().Filter().OrderBy();
        options.AddRouteComponents("odata", new TestDataModel().GetEdmModel());
    });
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    

    GET /odata/DynProp 的结果:

    {
      "@odata.context": "https://localhost:7171/odata/$metadata#DynProp",
      "value": [
        {
          "Id": "TestId",
          "key1": "value1",
          "key2": "value2"
        },
        {
          "Id": "TestId2",
          "key1": "value3",
          "key2": "value4"
        }
      ]
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 2016-09-12
      • 1970-01-01
      • 2016-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多