如何在 asp.net 核心 WebApi 项目中大摇大摆地使用 OData 过滤器?
How use OData filters with swagger in an asp.net core WebApi project?
我在 ASP.NET 5/core 和 EntityFrameworkCore 的顶部使用 C# 编写了一个 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 失败。我收到以下错误
Fetch error
undefined /swagger/v1/swagger.json
该错误是由于使用 ODataQueryOptions
作为搜索操作的参数造成的。
如何让 Swagger UI 与 ODataQueryOptions
一起工作?
我 运行 几年前遇到过类似的问题,所以也许我的解决方案对你有用。
我在我的控制器中使用了“本地”参数而不是 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)
然后我在以下 class 的帮助下创建了 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 消息“Add at least one media type to the list of supported media types”,这意味着某些 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);
}
});
我在 ASP.NET 5/core 和 EntityFrameworkCore 的顶部使用 C# 编写了一个 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 失败。我收到以下错误
Fetch error undefined /swagger/v1/swagger.json
该错误是由于使用 ODataQueryOptions
作为搜索操作的参数造成的。
如何让 Swagger UI 与 ODataQueryOptions
一起工作?
我 运行 几年前遇到过类似的问题,所以也许我的解决方案对你有用。
我在我的控制器中使用了“本地”参数而不是 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)
然后我在以下 class 的帮助下创建了 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 消息“Add at least one media type to the list of supported media types”,这意味着某些 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);
}
});