XML docs in service fabric web api

I usually use the swashbuckle swagger library to auto-document my web apis, but ran into issues when trying to deploy said APIs to a service fabric cluster – the swashbuckle/swagger initialization code threw “file not found” exception when trying to load the XML file generated by the build.

In order to get it to work, I edited the csproj file to generated the XML files for x64 config as well – from

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 <DocumentationFile>bin\Debug\net461\win7-x64\WebApi.xml</DocumentationFile>
 </PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
 <DocumentationFile>bin\Release\net461\win7-x64\WebApi.xml</DocumentationFile>
 </PropertyGroup>

 

to

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 <DocumentationFile>bin\Debug\net461\win7-x64\AssetsGraphWebApi.xml</DocumentationFile>
 </PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
 <DocumentationFile>bin\Release\net461\win7-x64\AssetsGraphWebApi.xml</DocumentationFile>
 </PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
 <DocumentationFile>bin\Debug\net461\win7-x64\AssetsGraphWebApi.xml</DocumentationFile>
 </PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
 <DocumentationFile>bin\Release\net461\win7-x64\AssetsGraphWebApi.xml</DocumentationFile>
 </PropertyGroup>

That’s twice this has had me stumped for a few minutes, hopefully this short post can help somebody else as well.

.net Web API and Route Name not found in Route Collection

Another entry in the series “tweets and blog posts I write mostly to have somewhere to look the next time I encounter this error”: this time, I spent too much time figuring out why this piece of code in an MVC view:

@Url.HttpRouteUrl("GetPerformance", new { id = Model.PerformanceId })

combined with this (working, I might add) API endpoint

[RoutePrefix("api/performances")]
public class PerformancesController : ApiController
{
    [HttpGet]
    [Route("", Name="GetPerformance")
    public Performance GetPerformances(string id = "")
    {
        // Some code...
    }
}

did not resolve to /api/controllers/{id}, but instead presented me with a glorious yellow screen proudly presenting and ArgumentException with the exception message

A route named ‘GetPerformance’ could not be found in the route collection.
Parameter name: name

As if often the case, it turns out I had tried to be a little too clever: This was an episerver project with the legacy global.asax.cs file doing the MVC routing, while the web api was set up in the owin startup.cs class, with a new HttpConfiguration instance created there and attached with app.UseWebApi.

To resolve the error, I had to tie the Web API registration to GlobalConfiguration.Configuration instead of a new instance in startup.cs. With that done, both MVC and API routing were aware of each other, the error went away, and I was able to programmatically create web API route links in MVC views.

OData Web APIs with AutoMapper 3

When developing an API on top of a domain layer, we rarely want to expose the actual domain objects to the API consumers. Rather, it is usually a matter of presenting the consumers with a subset of the domain object’s properties or a DTO/model object representing a composite of multiple domain objects.

Although the combination of OData and Entity Framework does provide some control of the presentation of the objects returned, it quickly falls apart when more advanced combinations and composites are needed. This meant that, to me, OData via .NET Web Api was not a viable alternative in most of my real world (read: customer) projects.

Enter AutoMapper. It has been an invaluable part of my development arsenal for quite some time, and the introduction of LINQ functionality in its latest incarnation makes an already awesome library even better. The LINQ support means that AutoMapper no longer populates the source objects completely, skipping any properties which aren’t needed for the mapping to the destination type. In other words, sensibly designed DTOs and some careful mapping configuration is all that’s needed to create an effective OData API.

Example

Given the domain object below:

[gist https://gist.github.com/JoachimL/6387670 /]

An ordinary domain object, containing a couple of properties we are not likely to want to expose over an OData API. It would be a horrible idea to expose the Image byte array, and there’s no need to expose the user who added the movie to the database, either. For this examples’s sake, we will limit the OData presentation of a movie to its Id, Title and Year Of Release.

[gist https://gist.github.com/JoachimL/6387685 /]

The mapping profile needs to be configured, and that’s typically done in a separate class inheriting from AutoMapper.Profile. AutoMapper does a good job of matching and mapping properties which share names, but has to be told that we just want the year part of the release date: [gist https://gist.github.com/JoachimL/6387662 /]

When that’s done, we merely need to set up an OData controller to delivery Movie objects over OData, and create a service and repository to bring the objects from the database to the controller. The Service, in this example called «MovieService», fetches the domain objects from an instance of the MovieRepository class. This layering might seem a bit contrived in our simple example, but it should prove that this technique is viable in a real world multi-layered architecture.

[gist https://gist.github.com/JoachimL/6387700 /] [gist https://gist.github.com/JoachimL/6387705 /]

I will skip the configuration of the actual OData endpoint, but I have more or less copied it verbatim from http://msdn.microsoft.com/en-us/magazine/dn201742.aspx. In addition, a visual studio 2012 project containing a runnable version of the code in this article is available on GitHub: https://github.com/JoachimL/WebApi.OData.

The most interesting part of this example, at least for those of us familiar with AutoMapper v2, is this line in the service: [gist https://gist.github.com/JoachimL/6387847 /]
In version 2, it would most likely look like this instead: [gist https://gist.github.com/JoachimL/6387854 /]

The difference is the Project().To()-syntax, which ensures that only the property values needed for the mapping are retrieved from the domain objects (and, by extension, the database), The OData endpoint now returns the Title and the Year of Release:

List of all the movies in the database
All movies in the database

SQL Express Profiler proves that the LINQ/AutoMapper/Entity Framework combination leads to an SQL query fetching just the properties needed:

LINQ-generated SQL.
LINQ-generated SQL.

If we try to fetch all Movies starting with a “D”, this is what happens:

movies_whose_filter_start_with_d

And the SQL generated to fetch the objects is still as slim as possible.

How about adding elements to the Movie model which aren’t part of the Movie domain object? No problem, we’ll first extend the Model:

[gist https://gist.github.com/JoachimL/6387670 /]

And then give AutoMapper a hand setting up the properties it’s not able to figure out itself:

[gist https://gist.github.com/JoachimL/6387662 /]

This leads to more data being returned when getting the same URL as previously:

movies_d_with_actors_and_ratings

And even though the SQL’s complexity increases, it’s still limited to the properties/fields it actually needs:

movies_d_with_actors_and_ratings_sql

Hopefully, these examples will give you an idea of how the combination of Entity Framework (and other ORMs) and AutoMapper is a powerful and productive combination. If OData fits the use case, devs can focus on the throttling and security side of things, and let the API consumers themselves decide how they search.

There are some security issues which must be addressed in a production system which I haven’t covered in this article. There is an abundance of advice and tutorials on that topic all around the internet. http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-security-guidance is a good starting point.

I have not yet had the time to experiment with how the OData $expand option can be used within the context of EF/LINQ and AutoMapper.

References:

https://github.com/AutoMapper/AutoMapper/wiki

https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api

http://expressprofiler.codeplex.com/

* For a discussion on the topic, see http://stackoverflow.com/questions/16962081/asp-net-webapi-odata-support-for-dtos.