Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Supporting ODataQueryOptions in existing Web API

I have a Web API project which has been used for several years without OData support, just with standard URL params.

I now wish to add OData support to this API, but as the API is not built on a queryable model the intention is to receive the ODataQueryOptions<T> object and pass this down to a repository.

Everything I can find to read about supporting OData either assumes that I have a queryable model or is overly simplistic and simply tells me how to make sense of the ODataQueryOptions object. Consequently I'm unable to get a simple method up and running.

Here's what I currently have.

[Route("test")]
[HttpGet]
[EnableQuery]
public IHttpActionResult Test(ODataQueryOptions<TestOptions> options)
{
    var settings = new ODataValidationSettings {
            AllowedFunctions = AllowedFunctions.None,
            AllowedLogicalOperators = AllowedLogicalOperators.Equal,
            AllowedArithmeticOperators = AllowedArithmeticOperators.None,
            AllowedQueryOptions = AllowedQueryOptions.Filter
        };
    try
    {
        options.Validate(settings);
    }
    catch (ODataException exception)
    {
        return BadRequest(exception.Message);
    }

    var binaryOperator = options.Filter?.FilterClause?.Expression as BinaryOperatorNode;
    if (binaryOperator != null)
    {
        var property = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode;
        var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode;

        if (property?.Property != null && constant?.Value != null)
        {
            ;
        }
    }

    return Ok();
}

The TestOptions class (in the ODataQueryOptions<TestOptions> param) is currently an empty class:

public class TestOptions
{
}

I've also added

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // existing code

        config.AddODataQueryFilter();
    }
}

However, upon calling this from a REST API client...

{
"Message": "An error has occurred.",
"ExceptionMessage": "No non-OData HTTP route registered.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " ... "
}

What have I missed? I would have thought that I might have to register OData-enabled methods in the global.asax or similar, but the exception implies that the problem is with non-OData methods, but all the other methods still return as expected (i.e., without any OData involvement).

like image 344
awj Avatar asked Jul 03 '17 13:07

awj


People also ask

Which OData query does Web API support?

Web API Support for OData Queries The following OData query options are commonly used and are supported by Web API: $top : Can be used to retrieve top n records from a data store. $orderby : Can be used to sort the data in ascending or descending order. $filter : Can be used to filter the data based on some condition.

What is the use of OData in Web API?

The Open Data Protocol (OData) is a data access protocol for the web. OData provides a uniform way to query and manipulate data sets through CRUD operations (create, read, update, and delete). ASP.NET Web API supports both v3 and v4 of the protocol.

What is Odataqueryoptions?

OData defines parameters that can be used to modify an OData query. The client sends these parameters in the query string of the request URI. For example, to sort the results, a client uses the $orderby parameter: http://localhost/Products?$orderby=Name. The OData specification calls these parameters query options.

What is ODataController?

ODataController class has methods for reading and writing data using OData format. EnableQuery Attribute class enables querying using OData query syntax.


1 Answers

Actually, this works perfectly without EntityDate or any other model setup. You just need a List<Poco.Language> that you can convert with .AsQueryable() and off you go.

[Route(""), HttpGet]
public IHttpActionResult  Get(ODataQueryOptions<Poco.Language> queryOptions)
{          
    return Ok(queryOptions.ApplyTo(_repository.GetAll().AsQueryable()));
}

Above controller can be called with all types of OData query options, normal routes and no setup in the WebApiConfig.

Poco.Language is just a plain C# POCO class.

like image 91
Remy Avatar answered Oct 22 '22 21:10

Remy