DayPath Journal

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:

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