【问题标题】:Getting OData Count in ASP.NET Core WebAPI在 ASP.NET Core WebAPI 中获取 OData 计数
【发布时间】:2020-03-09 08:39:15
【问题描述】:

使用 Hassan Habib 的 Supercharging ASP.NET Core API with OData 博客文章中的示例代码,我可以使用 $count=true 的 OData 查询获取记录数:

需要进行什么配置才能将响应对象包装在OData context 中,以便显示@odata.count 属性?

在我自己的 ASP.NET Core Web API 项目中,我无法让简单的 $count 参数工作,我不知道为什么。

使用 Hassan 的示例代码,响应 JSON 包装在 OData context 中,负载(IEnumerable<Student> 对象)位于 JSON 响应的 value 属性中。在我的项目中,OData context 包装器不存在;我的代码从不返回OData context,它只返回IEnumerable<T>类型的有效载荷对象:

我还注意到响应头中的Content-Type 在示例项目中是application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8,而在我的项目中它只是application/json; charset=utf-8。我在这两个项目中都没有看到任何控制这个的设置,所以我假设Microsoft.AspNetCore.Odata NuGet 包在正确配置时会神奇地改变响应。

我的项目也使用 .NET Core 2.2(从 2.1 升级),所有与 Hassan 示例项目相同版本的 NuGet 包,以及 StartUp.cs 类中的所有相同设置...虽然我的 StartUp.cs方式更复杂(因此我不在这里发布它的内容。)

【问题讨论】:

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


    【解决方案1】:

    当我将[Route("api/[controller]")][ApiController]与startup.cs一起使用时,我可以重现您的问题,如下所示:

    app.UseMvc(routeBuilder =>
            {
                routeBuilder.Expand().Select().Count().OrderBy().Filter();
                routeBuilder.EnableDependencyInjection();
            });
    

    要修复它,请确保您已经构建了一个私有方法来在现有数据模型(本例中为 OData 模型)和 EDM 之间进行握手。

    这是一个简单的演示:

    1.Controller(评论Route属性和ApiController属性):

    //[Route("api/[controller]")]
    //[ApiController]
    public class StudentsController : ControllerBase
    {
        private readonly WSDbContext _context;
        public StudentsController(WSDbContext context)
        {
            _context = context;
        }
        // GET: api/Students
        [HttpGet]
        [EnableQuery()]
        public IEnumerable<Student> Get()
        {
            return _context.Students;
        }
    }
    //[Route("api/[controller]")]
    //[ApiController]
    public class SchoolsController : ControllerBase
    {
        private readonly WSDbContext _context;
        public SchoolsController(WSDbContext context)
        {
            _context = context;
        }
        // GET: api/Schools
        [HttpGet]
        [EnableQuery()]
        public IEnumerable<School> Get()
        {
            return _context.Schools;
        }
    

    2.Startup.cs():

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore(action => action.EnableEndpointRouting = false);
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            var connection = @"Server=(localdb)\mssqllocaldb;Database=WSDB;Trusted_Connection=True;ConnectRetryCount=0";
            services.AddDbContext<WSDbContext>(options => options.UseSqlServer(connection));
            services.AddOData();
        }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
    
            app.UseHttpsRedirection();
            app.UseMvc(routeBuilder =>
            {
                routeBuilder.Expand().Select().Count().OrderBy().Filter();
                routeBuilder.MapODataServiceRoute("api", "api", GetEdmModel());
            });
        }
    
        private static IEdmModel GetEdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Student>("Students");
            builder.EntitySet<Student>("Schools");
            return builder.GetEdmModel();
        }
    }
    

    【讨论】:

    • 感谢您给出如此详细的答复。注释掉[Route][ApiController] 属性似乎可以解决问题。控制器不再出现在相关的 Swagger 页面中,但 OData 端点仍然存在,现在返回我正在寻找的 OData 上下文包装器。
    • 我没有必要删除 [Route][ApiController]routeBuilder.Expand().Select().Count() 成功了
    • 这将禁用现有 API 调用的 api/路由,并要求通过 odata 请求我的 api。在 Hassan 的非基于 EDM 的方法中,原因是扩展现有 API 功能以支持 OData。但是如果不引入 EDM,我似乎无法让 $count 工作。
    【解决方案2】:

    一直在和这个作斗争。

    我发现,如果我在 /api/Things 请求我的控制器,大多数 OData 选项都可以工作,但 $count 不能。

    但是,如果我通过 /odata/Things 请求相同的方法,$count 确实可以工作。

    【讨论】:

      【解决方案3】:

      您可以在映射 OData 时设置一个空前缀路由,您将收到 OData 以及您的端点请求。

      routeBuilder.MapODataServiceRoute("ODataEdmModel", "", GetEdmModel());
      

      【讨论】:

        猜你喜欢
        • 2021-05-09
        • 2017-01-04
        • 2016-04-23
        • 1970-01-01
        • 2021-04-09
        • 2023-02-15
        • 2013-02-03
        • 2017-04-04
        • 1970-01-01
        相关资源
        最近更新 更多