I have an web API written using C# on the top of ASP.NET 5/core with EntityFrameworkCore.
I am using OData to apply filters on when querying the database.
I need to manually apply the ODataQueryOptions
to my DbSet<>
to generate paged info.
Here is my code
[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;
}
}
But the above code cause Swagger UI to fail. I get the following error
Fetch error undefined /swagger/v1/swagger.json
That error is caused by using ODataQueryOptions
as parameter into the Search action.
How can I get the Swagger UI to work with ODataQueryOptions
?
CodePudding user response:
I ran into similar problem few years ago, so maybe my solution will be useful to you.
I used "native" parameters instead of ODataQueryOptions in my controller:
[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)
Then I created ODataQueryOptions with the help of the following class:
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);
}
}
The advantage of this approach is that the user can now specify required parameters and run requests in Swagger.