0
votes

I currently have an C# WebAPI that uses a version of OData that we wrote. We want to start using Microsoft's OData4 which can do more then our custom implementation.

Creating a controller that extends the ODataController I can create a controller that automatically queries based on the query string. (Shown below)

The problem is that it returns the results of the query when I want it to return the Result object which includes additional data. When I set the return type to Result though it will no longer apply the query string.

How can I use the automatic queryable implementation and still return my own object? I've tried making a public method that returns the correct object and calls a private method returning the queryable but it doesn't filter the queryable correctly.

Am I on the right track, or are there other options?

public class CallController : ODataController
{
    [EnableQuery]
    public IQueryable<Call> GetCall()
    {
        var list = new List<Call>
        {
            new Call
            {
                Id = 4
            },
            new Call
            {
                Id = 9
            },
            new Call
            {
                Id = 1
            }
        };
        return list.AsQueryable();
    }
}

public class Call
{
    public int Id { get; set; }
}

public class Result
{
     public Call[] Calls { get; set; }
     public string NewToken { get; set; }
     public string Warning { get; set; }
}
3

3 Answers

1
votes

You would need to intercept the response with an action filter attribute in the onactionexecuted and convert the value to whatever you want. It wouldn't be pretty since it wouldn't be clear what the method was truly returning. But I don't see any other option with odata as the result must be iquerable.

0
votes

Under the hood, the EnableQuery attribute is executing the action it decorates to get an IQueryable<T>, converting the odata query into something that can be applied to the IQueryable<T>, applying it and returning the results.

In order to work, it needs an IQueryable<T>.

The ODataQueryOptions and example in Ihar's answer may give you what you want, but for various reasons it wasn't as useful to me as EnableQuery and so I ended up with an output formatter.

You can inspect the first output formatters in services.AddMvc(options => { options.OutputFormatters } in Startup.ConfigureServices and see that the first one has a bunch of different payload kinds.

I have been able to insert a custom error handler to handle ODataPayloadKind.Error payloads - re-writing the content returned from the server to remove stack traces etc if not in dev mode. I haven't looked into non-error cases, but you may be able to use what I have here as a starting point.