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

Poo*_*eld 10 c# asp.net odata asp.net-core-webapi

使用 Hassan Habib 的Supercharge ASP.NET Core API 和 OData博客文章中的示例代码,我能够使用 OData 查询获取记录计数$count=true

在此处输入图片说明

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

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

使用 Hassan 的示例代码,响应 JSON 被包装在 an 中OData context,有效负载(一个IEnumerable<Student>对象)位于valueJSON 响应的属性中。在我的项目中,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.OdataNuGet 包在正确配置时神奇地改变了响应。

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

Jes*_*ess 5

就我而言,我想扩展现有的 Api 方法,[EnableQuery]但让它包含计数元数据。

我最终扩展了 EnableQuery 属性以返回不同的响应,它工作得很好。

public class EnableQueryWithMetadataAttribute : EnableQueryAttribute
{
    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        if (actionExecutedContext.Result is ObjectResult obj && obj.Value is IQueryable qry)
        {
            obj.Value = new ODataResponse
            {
                Count = actionExecutedContext.HttpContext.Request.ODataFeature().TotalCount,
                Value = qry
            };
        }
    }
    public class ODataResponse
    {
        [JsonPropertyName("@odata.count")]
        public long? Count { get; set; }

        [JsonPropertyName("value")]
        public IQueryable Value { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ren*_*ena 3

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

app.UseMvc(routeBuilder =>
        {
            routeBuilder.Expand().Select().Count().OrderBy().Filter();
            routeBuilder.EnableDependencyInjection();
        });
Run Code Online (Sandbox Code Playgroud)

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

这是一个简单的演示:

Route1.Controller(属性和属性注释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;
    }
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)