My introduction to the OData v4 timeframe on .NET
The Microsoft OData v4 world is built on top of these NuGet packages: Microsoft.AspNet.OData, Microsoft.OData.Core and Microsoft.OData.Edm. It is far too easy to slip into an older implementation or worse to mix versions, causing the problems outlined in “ODataController returning HTTP 406 Not Available.”
I have turned to a LINQPad file (as a GitHub gist) to summarize my introduction to OData v4:
<script src="https://gist.github.com/BryanWilhite/25046e8d35341ea88e23.js"></script>
Using OWIN Self-Hosting to test Web API
The Microsoft.Owin.SelfHost
(with Microsoft.Owin
, Microsoft.AspNet.WebApi.Owin
, and Owin
) Nuget Package gives us an in-memory, tiny server. This means server code can be tested from a .NET web server that is completely independent of IIS or IIS Express. When I attempt to show this new technology to .NET veterans, oftentimes this technology is so radically different (and just too simple) that it’s hard to understand what’s being said! It may be better to show rather than tell. The gist above shows just how simple the standard OWIN implementation is to use:
var baseAddress = "http://localhost:9000/";
var client = new HttpClient();
try
{
using (WebApp.Start<Startup>(url: baseAddress))
{
HttpResponseMessage response;
Action<string> callOwin = path =>
{
response = client.GetAsync(baseAddress + path).Result;
response.Dump();
response.Content.ReadAsStringAsync().Result.Dump();
};
callOwin("api/$metadata");
callOwin("api/Product?$count=true");
callOwin("api/Product(2)");
callOwin("api/Product?$filter=Category+eq+'Bakery'+and+indexof(Name,'Tortillas')+ne+-1");
}
}
finally
{
client.Dispose();
}
OData EDM model building/routing
The single call WebApp.Start<Startup>()
our way into OWIN. The class definition Startup
has one, conventional method, Configuration()
, that handles HttpConfiguration
just like the conventional ASP.NET MVC *Config
static classes in the App_Start
folder. Our OData concerns for EDM model building and routing are handled in this Startup.Configuration()
method:
var builder = new ODataConventionModelBuilder();
builder
.EntitySet<Product>("Product")
.EntityType.DerivesFrom<IProduct>();
var model = builder.GetEdmModel();
config.MapODataServiceRoute("odata", "api", model);
The EDM model building (with the builder
variable) uses EntityType.DerivesFrom<>()
to tell OData that the interface IProduct
is implemented by Product
. The assumption here is that OData clients should work with interface types rather than server model classes for the sake of simplicity and security through obscurity. Without this builder, the standard OData ./$metadata
call would return almost nothing or not work at all.
The MapODataServiceRoute()
extension method (of HttpConfiguration
) makes a standard OData call, like ./api/Product?$count=true
, possible by way of the route prefix "api"
specified in the second argument of this extension method.
The importance of MetadataController
The ControllerResolver
in our gist above is used in OWIN Startup.Configuration()
to ultimately inject ProductController
into HttpConfiguration
. In my production ASP.NET MVC Web API application, AutoFac would handle this auto-magically. Notice also that ControllerResolver
is ‘manually’ loading MetadataController
. Without MetadataController
, the ./$metadata
call would fail (it should be a 404 error).
Extending from ODataController
The ProductController
extends from ODataController
. One of the not-so-subtle implications with extending from ODataController
is the intent to emit only types defined in the $metadata
output. So, the use of ODataController
, means the controller is confined to emitting Entity Data models.
Related Links
- “Paging with ASP.NET Web API OData”
- “Supporting OData $inlinecount & json verbose with Web API OData”
- “OData support in ASP.NET Web API” [from 2012]
- “Getting started with Web API and OData V4 Part 1”
- “An OData Journey in ASP.NET Web API Part 2 – Introducing Linq to Querystring”
- “I was using OData 4 (System.Web.OData) in my WebApiConfig and OData 3 (System.Web.Http.OData) in my controller. Turns out, they don”
- “Create an OData v4 Endpoint Using ASP.NET Web API 2.2”
- “Web API OData V4 Lessons Learned”
- “Turns out, OData implements one: System.Web.OData.MetadataController, which provides for the $metadata keyword.”
- “Typeless Entity Object Support in WebApi”
- “Does ASP.NET Web API + OData filter at the database level? Let”
- “Open Data Protocol by Example”
- “How to use OData Client Code Generator to generate client-side proxy class”
- “ASP.Net: Web API 2 + Help Pages + OData”
- “Parsing OData Paths, $select and $expand using the ODataUriParser”