【问题标题】:How use OData filters with swagger in an asp.net core WebApi project?如何在 asp.net 核心 WebApi 项目中使用 OData 过滤器和 swagger?
【发布时间】:2021-11-17 21:36:29
【问题描述】:

我有一个使用 C# 在 ASP.NET 5/core 之上和 EntityFrameworkCore 编写的 Web API。

我在查询数据库时使用OData 应用过滤器。

我需要手动将ODataQueryOptions 应用到我的DbSet<> 以生成分页信息。

这是我的代码

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    private readonly DbContext _db;

    public ProductsController(DbContext db)
    {
        _db = db;
    }

    [HttpGet]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All, AllowedFunctions = AllowedFunctions.AllFunctions, MaxTop = 500)]
    public PagedProduct Search(ODataQueryOptions<Product> queryOptions)
    {
        // create a query for that would count the total rows
        var countQuery = queryOptions.ApplyTo(Repository.Query(),  AllowedQueryOptions.Top | AllowedQueryOptions.Skip) as IQueryable<Product>;

        // create a query to pull the data
        var query = queryOptions.ApplyTo(Repository.Query()) as IQueryable<Product>;

        var result = new PagedProduct()
        {
            CurrentPage = 1, // TODO get the current page value from the queryOptions
            PageSize = 100,  // TODO get the page size value from the queryOptions
        };

        result.TotalRecords = await countQuery.Count();
        result.Data = await query.ToList();

        return result;
    }
}

但上面的代码导致 Swagger UI 失败。我收到以下错误

获取错误 未定义 /swagger/v1/swagger.json

该错误是由于在搜索操作中使用ODataQueryOptions 作为参数引起的。

如何让 Swagger UI 与 ODataQueryOptions 一起使用?

【问题讨论】:

  • 您是否尝试将 Odata 特定属性添加到路由? [ODataRoute][ProducesResponseType(typeof(ODataValue&lt;IEnumerable&lt;Product&gt;&gt;), StatusCodes.Status200OK)]
  • 包中不存在ODataValue

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


【解决方案1】:

几年前我遇到过类似的问题,所以也许我的解决方案对你有用。

我在控制器中使用“本机”参数而不是 ODataQueryOptions:

    [Route("", Name = "GetDocuments")]
    [HttpGet]
    [Produces(typeof(PageDto<DocumentShortDto>))]
    public async Task<IActionResult> GetDocumentsAsync(
        [FromQuery(Name = "$top")] int top,
        [FromQuery(Name = "$skip")] int skip,
        [FromQuery(Name = "$orderby")] string orderby,
        [FromQuery(Name = "$filter")] string filter)

然后我在以下类的帮助下创建了 ODataQueryOptions:

public static class ODataBuilder
{
    public static ODataQueryOptions<T> BuildOptions<T>(HttpRequest request)
    {
        var modelBuilder = new ODataConventionModelBuilder();
        modelBuilder.AddEntityType(typeof(T));
        var edmModel = modelBuilder.GetEdmModel();
        var oDataQueryContext = new ODataQueryContext(edmModel, typeof(T), new ODataPath());

        return new ODataQueryOptions<T>(oDataQueryContext, request);
    }
}

这种方法的优点是用户现在可以指定所需的参数并在 Swagger 中运行请求。

如果 Swagger 抛出 InvalidOperationException 并显示消息“将至少一种媒体类型添加到支持的媒体类型列表中”,这意味着某些 OData 格式化程序具有不受支持的媒体类型.

由于服务仅使用本机参数并且不响应 OData,因此您可以在启动代码时安全地删除所有 OData 格式化程序并解决此问题:

services.AddMvcCore(options =>
{
    var inputFormattersToRemove = options.InputFormatters.OfType<ODataInputFormatter>().ToList();
    foreach (var formatter in inputFormattersToRemove)
    {
        options.InputFormatters.Remove(formatter);
    }

    var outputFormattersToRemove = options.OutputFormatters.OfType<ODataOutputFormatter>().ToList();
    foreach (var formatter in outputFormattersToRemove)
    {
        options.OutputFormatters.Remove(formatter);
    }
});

【讨论】:

  • 非常感谢您在这里的帮助。我试过了,但得到了这个错误The query specified in the URI is not valid. The limit of '0' for Top query has been exceeded. The value from the incoming request is '500'我用这个`[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All,AllowedFunctions = AllowedFunctions.AllFunctions,MaxTop = 1000)]`装饰了我的操作方法,所以它可以是1000,但我是请求 500 但它说限制是 0
  • 嗯....这与 Microsoft.AspNetCore.OData 7.4.0-beta 成功合作。
  • EnableQueryAttribute 没用,我认为。您应该手动设置 MaxTop。也许阅读docs.microsoft.com/en-us/aspnet/web-api/overview/… 会有所帮助。
  • 再次感谢!我将接受答案。但是,现在有这个问题The property 'Title' cannot be used in the $filter query option. I am guessing I need to configure a service somehow to allow odata to filter by all the properties. Any idea how? Here is how I currently configure odata services.AddControllers().AddOData();`
  • 是的,您必须使用调用 services.AddOData() 来配置 Odata。但我记得除此之外,我还需要删除 OData 格式化程序:
猜你喜欢
  • 1970-01-01
  • 2019-01-20
  • 2020-09-23
  • 2016-12-12
  • 2021-06-22
  • 2021-05-25
  • 2021-04-03
  • 1970-01-01
  • 2019-06-01
相关资源
最近更新 更多