Search code examples
asp.net-coreodata

Is it possible to render View based on OData query?


I've got Asp.Net Core application and there is an abstract controller.

I want to create a method, which will allow me to render list of entities as PartialView.

I've made it like this:

Should return PartialView with list of entities

[HttpGet]
[EnableQuery()]
public async Task<IActionResult> _List()
{
    var result = _context.GetQueryByType<T>(); //returns DbSet<T> of whole table
    return PartialView(await result.ToListAsync());
}

Example PartialView

@model IEnumerable<SomeClass>

<table class="table table-sm table-striped table-hover">
...
</table>

I want to call my method like this:

http://localhost:32769/SomeController/_List?$filter=id%20eq%2009515a38-2a1a-4a53-a4f8-e91e4dbd870b

And get filtered List view.

But anyway I get only whole table data.

The only solution for me is split this logic into 2 methods:

  1. Get filtered Json data via standard Odata methods like:

http://localhost:32769/odata/SomeClass?$filter=ReleaseId%20eq%2011f28258-48cb-4c82-85e0-822850fd1f5c

  1. Pass this data to method:
[HttpPost]
public IActionResult _List([FromBody] IEnumerable<T> entities)
{
    return PartialView(entities);
}

I don't like this solution. Is there any possibility to filter my view data using OData queries?


Solution

  • Thx to ChristophLütjen.

    .ApplyTo() is the solution.

    Finally, working method looks like:

    [HttpGet]
    [EnableQuery]
    public async Task<IActionResult> _List(ODataQueryOptions<T> queryOptions)
    {
        var result= (IQueryable<T>)queryOptions.ApplyTo(_context.GetQueryByType<T>());
        return PartialView(await result.ToListAsync());
    }
    

    Also, it's very important to use ODataQueryOptions<T>, not ODataQueryOptions.

    If you will use not common class, you will get an error, that method should return IEnumerable<T>, but not IActionResult.

    Here is some documentation. Just want to pin it to the answer.

    https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnet.odata.query.odataqueryoptions?view=odata-aspnetcore-7.0

    Hope, that this info will be usefull for someone else.

    upd:

    Also I've found out, that it's not perfect soulution, if you want to use $expand method in your OData queries.

    If you'll try to get type T of expanded query, you'll face the problem of SelectAllAndExpand type.

    In this case this is the solution, I think it's not very beatiful and perfect, but it works:

    [HttpGet]
    [EnableQuery]
    public IActionResult _List(ODataQueryOptions<T> queryOptions)
    {
        var validationSettings = new ODataValidationSettings
        {
            AllowedQueryOptions = AllowedQueryOptions.All,
            AllowedFunctions = AllowedFunctions.All,
        };
    
        queryOptions.Validate(validationSettings);
        IQueryable resultSet = queryOptions.ApplyTo(_context.GetQueryByType<T>(), new ODataQuerySettings());
    
        List<T> resultList = new List<T>();
    
        foreach (var item in resultSet)
        {
            if (item is T)
            {
                resultList.Add((T)item);
            }
            else if (item.GetType().Name == "SelectAllAndExpand`1")
            {
                var entityProperty = item.GetType().GetProperty("Instance");
                resultList.Add((T)entityProperty.GetValue(item));
            }
        }
    
        return PartialView(resultList as IEnumerable<T>);
    }
    

    Found it here: https://github.com/OData/WebApi/issues/1441