Read ODataQueryOptions from httpcontext manually

Viewed 135

Maybe somebody can help. I currently use NSwag (https://github.com/RicoSuter/NSwag) for the api specification and client code generation for my Api. And because of this I can't use the type ODataQueryOptions in my controller methods without many disandvantages.

Currently I have created a solution based an expressions to support nice call from client completly based on Odata filter string.

        [Authorize(Policy = Permissions.Brands.View)]
        [HttpGet]
        [Produces(typeof(IReadOnlyCollection<BrandDto>))]
        public async Task<IActionResult> GetAll([FromOdataFilter] TransferableExpression<BrandDto> filter = null, CancellationToken cancellationToken = default)
        {
            var brands = await Mediator.Send(new GetAllBrandsQuery(filter), cancellationToken);
            return Ok(brands);
        }

So currently the client can use the generated api and make a call like this

            Expression<Func<BrandDto, bool>> expression = dto => dto.Name == "Samsung";
            await _api.Brands_GetAllAsync(new TransferableExpression<BrandDto>(expression));

The request in this example is then a http call like this /api/v1/Brands/?$filter=Name eq 'Samsung'

And on the Backend Side I currently create a real expression from it and filter it an the database and this works fine. And because the whole controller has [EnableQuery] all other Odata params like $select, $orderbyand so one are executed in Memory on the IEnumerable<> and this is something I want to change because I have some wrapped results for paging for example and also I dont like the mix of it.

And If I create teh controller method like this

        [ApiExplorerSettings(IgnoreApi = true)]
        [Authorize(Policy = Permissions.Brands.View)]
        [HttpGet]
        [Produces(typeof(IQueryable<BrandDto>))]
        public async Task<IActionResult> GetAll(ODataQueryOptions<BrandDto> options, CancellationToken cancellationToken = default)
        {
            var brands = await Mediator.Send(new GetAllBrandsQuery(), cancellationToken);
            return Ok(brands.AsQueryable());
        }

then the parameter ODataQueryOptions<BrandDto>is correct filled and I con change my Mediator query and work with it, but the generated code is horrible and also the client project currently didn't have a reference to the OData package and I need to set [ApiExplorerSettings(IgnoreApi = true)] to test it currently.

Now I'am searching for a way to make whatever the ODataModel binder is making to access ODataQueryOptions<BrandDto>directly from HttpContext or Requestbut I cant find a way

Long story short term. I hope somebody understand my problem and can Help me or give me o good Idea.

I guess it should somehow possible to do something like this but I dont know how

    public static ODataQueryOptions<T> ReadODataQueryOptions<T>(this HttpRequest request)
    {
        // I dont know
    }
1 Answers

Try something like that

public async Task<IActionResult> GetAll(
 [FromQuery(Name = "$top")] int top,
 [FromQuery(Name = "$skip")] int skip,
 [FromQuery(Name = "$orderby")] string orderby,
 [FromQuery(Name = "$filter")] string filter,
 [FromServices] ODataQueryOptions<BrandDto> options)
 {
     ...
 }
Related