ApiController vs ODataController when exposing DTOs

Pavel Voronin picture Pavel Voronin · Aug 14, 2013 · Viewed 14.9k times · Source

Can someone explain me when I should inherit my controller form ODataController vs ApiController ?

The question is caused by the fact that results returned by ApiController can be filtered with OData query.

If I apply QueraybleAttribute to contoller's methods, query is processed even if action returns IEnumerable.
However without this attribute but with the call config.EnableQuerySupport(), query is processed only if method returns IQueryable.
I think it is not consistent behavior. WebAPI documentation and examples imply that controller must inerit from ODataController. And I'm a little confused.
Either ApiController accidentally and partially supports part (at least $skip, $filter and $top) of OData protocol. Or this is by design and I need ODataController for complete ODataSupport.

The real problems is that my service exposes DTOs, not POCOs. There may be no one to one mappings. There's need to convert OData query againts DTOs to EF query against POCOs.
Now just playing with OData. I retrieve entities and convert them to DTOs. Admittedly, this is not very performant to get all of them from DB for each request yet tolerale for experiments. But there's definetely no need to return all entities to the client if it requires some filtered subset of DTOs.
OData query started working out of the box with ApiController and Querayble attribute, but the aforementioned inconsistency makes me thing I doing something wrong.

Answer

Brian Reischl picture Brian Reischl · Aug 14, 2013

Can someone explain me when I should inherit my controller form ODataController vs ApiController?

You would want to inherit from ODataController if you want to expose an endpoint that adheres to the OData protocol. If you want to do something else, such as a REST endpoint, then inherit from ApiController.

Applying some parts of the WebAPI OData framework but not others is probably not a good idea. It may in some cases, but will probably not work well in others. For example you may get querying support, but the $metadata endpoint may not be generated (that's just speculation, the actual symptoms may be different).

It sounds like you're using EntityFramework already. I know there are a number of samples showing how to expose that as an OData endpoint.

If you don't want to do that for some reason, you can implement querying yourself. This is briefly covered in a few places on this tutorial, but the gist is to add a parameter of type ODataQueryOptions<T> to your action, and use the methods on it to filter your result set. However, it can be painful to generate good database queries for all possible OData queries, so you should avoid that if possible.