Home > Software engineering >  How use OData filters with swagger in an asp.net core WebApi project?
How use OData filters with swagger in an asp.net core WebApi project?

Time:09-25

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.

  • Related