在 ASP.NET Core WebAPI 中获取 OData 计数

Posted

技术标签:

【中文标题】在 ASP.NET Core WebAPI 中获取 OData 计数【英文标题】:Getting OData Count in ASP.NET Core WebAPI 【发布时间】: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方式更复杂(因此我不在这里发布它的内容。)

【问题讨论】:

【参考方案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());

【讨论】:

以上是关于在 ASP.NET Core WebAPI 中获取 OData 计数的主要内容,如果未能解决你的问题,请参考以下文章

如何从 ASP.NET Core WebAPI 获取 int 值?

使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证

Asp.net Core WebAPI 基于资源的控制器级别之外的授权

如何从 asp.net core webapi 获取数据到连接到数据库的 angular 11.0.0。我试图这样做,但它返回空记录

如何在 Asp.Net Core 3.0 WebAPI 中启用 CORS

在 ASP.Net Core 5 WebAPI 中启用 CORS