WebApiContrib

The  announcement of the ASP.NET Web API got a lot of people interested in playing with, bending, learning the framework to see what was possible to do with it. Some folks were doing that already back when it was WCFWebApi. But the move to the ASP.NET team and having it being part of the ASP.NET MVC 4 beta definitely brought a lot of attention to the Web Api framework.

The WebApiContrib organization

With all that attention, and people playing with it, different contrib efforts were sparkling all around. There was the original WcfWebApiContrib maintained by Darrel Miller. We at Headspring created our own contrib. Folks from Thinktecture created there own. Some other authors were pushing their own extensions to their own repositories. Basically, it was a mess.

Ryan Riley then started the effort to bring everybody together to contribute to a single contrib project. He created an organization on github and a mailing list. After I got contacted by Ryan, I talked with the other Headspring folks and we decided to transfer our WebApiContrib repository from our HeadspringLabs organization to the WebApiContrib one.

This was the first move that we made, after that, Thinktecture extensions were moved and the handlers from the WcfWebApiContrib were also moved.

How can I get it?

Right now, you can head to the github repository and pull the code. I know it’s kinda ghetto in these Nuget and Open Rasta OpenWrap days.

In order to fix this, and Chris Missal is working on it, we need to solve some few issues:

  • Add the packaging task to our build – not a big deal
  • Have a CI server to generate the packages for us – Chris talked with the Codebetter folks and we will have it done by the end of the week approximately
  • Agree on how we are going organize the packages and distribute it.

The latter issue has two parts: package organization and distribution

Package Organization: We are structuring the code so that one can install the core package that has no dependencies. This will give you all extensions that have no extra dependencies. For extensions that depends on other packages we are going to create a specific packages.

For example, if you want to use the NotAcceptableMessageHandler, that has no dependencies, all you have to do is install the core package. On the other hand, if you want to use the ServiceStackTextFormatter, a Media Type Formatter that uses ServiceStack.Text to handle JSON serialization, you will have to install the WebApiContrib.Formatting.ServiceStackTextFormatter package. Our goal is to keep contrib’s users packages dependencies clean, and only have what is really necessary for what the user is trying to do.

Distribution: Nuget currently has two WebApiContrib packages. Those were created for the WCFWeb APIContrib project. This means that replacing those packages will break everything for people that was relying on the WCF version of the package. This might be ok to do, as the WCFWebApi no longer exist and we are going to deprecate the WCFContrib as well. But we haven’t decided that yet. And I’m willing to get some ideas on what should we do to make this as frictionless as possible.

I expect all this to be fixed by next week.

What’s next

We don’t have an official roadmap besides the issues list on github. Besides what’s there, I have some ideas that are now floating on my head but I haven’t started working on them yet:

Provide a better way of creating/embedding links on resources. The ASP.NET Web API has no built in helper to embed links into resources. My goal is to have a helper to make it easier, and hopefully in a strongly typed way, to configure your resource so that the Media Type Formatter can then pull that information and include the links in the resource representation.

Api Documentation Generation. It’s key for the success of a api that it’s well documented. It’s in the ASP.NET Web API team future roadmap to include something to help in this documentation generation. But, until they get there, we still need to document the web apis that we are creating. My initial idea is to implement the Swagger specification and use Swagger-UI to expose the documentation.

Remember it’s a Contrib effort

The goal of a Contrib effort is to group and curate extensions to the ASP.NET Web API that are created by the people using it. So, if you have an idea or created something that extends the ASP.NET Web API please, come talk to us. Send us an email on the mailing list; open an issue to discuss a new idea; send us a pull request. Even if you don’t have an specific idea or feature that you want to discuss but are willing to help our effort, come talk to us.  The WebApiContrib is a community effort and we need your help.

ASP.NET Web API Routing needs a hug

One of my goals with the WebAPIContrib is to be able to write as few code as possible in my API application and let the Contrib help me with the boring boilerplate code.

Looking through the ASP.NET Web API samples, tutorials and blog posts out there, the first thing that jumps on my eye is the whole HttpResponseMessage noise.

I don’t want to have to write all these status code and Location Header settings all over my code. This is boring and adds noise to what actually is important on my controller action. So, my idea was to create objects to represent each status code, something similar to what Restfulie does, and encapsulate all this noise inside these specialized HttpResponseMessages.

I imagined doing something similar to:

But, in the create response I also want to set the Location Header of the new resource. As a first pass, I went with:

Now, in the API code I can have:

Although this achieve my goal of setting the status code and Location header in the HttpResponseMessage I’m still not happy. Mainly because of manually building the URI of the Location. I don’t have to hardcode URLs when I can use the type system to help me with that.

Embracing the type system, or not.

I’m really not happy with hardcoding the URI to set the Location Header. A better way of setting that would be:

With that, all I would have to do is generate the URL for that controller action and set it to the Location Header. Piece of cake, it’s just use the built-in UrlHelper. Or, that’s what I thought.

The System.Web.Http.Routing.UrlHelper has a Route method that returns an URL for a set of route values. OK, so at first glance I just need to translate my Expression<Action<TController>> in a dictionary of route values. This is not a problem, MVCContrib, for example, uses a helper from the MVCFutures assembly to do this. As I’m working in the WebAPIContrib, I didn’t want to take a dependency in the MVCFutures just for this. I ended up coding the reflection part myself.

OK, no I have a RouteValueDictionary, to get the URL back is just call urlHelper.Route(routeValues), right? Not so quickly.

Y’all gotta know the names. All the names

The Route method on UrlHelper is not like the Action method on it’s System.Web.MVC sibling (more on this Mvc x Http later). As you can see in the MSDN documentation, the Route method signature is:

Together with the route values you also have to supply the route name. As I’m building a library for others to use while building their APIs, I don’t know which route to use. My first thought was: I’m just going to iterate over the HttpRouteCollection and the first URL I get back would win. That’s when I started learning more about the ASP.NET Web API routing implementation than I was wanting to.

No foreach for you

When I tried to iterate over the HttpRouteCollection, the following exception was thrown:

Checking on Google, I found out that I had to get a read lock first, before iterating over the collection. This is done through the GetReadLock method that returns a disposable lock object. :SadTrombone: Fooled one more time by the Mvc vs. Http identity issues. Only System.Web.Routing.RouteCollection has the GetReadLock method. The HttpRouteCollection counterpart doesn’t have it.  So, I had to fall back to for loops to get the routes out of the HttpRouteCollection.

Then, another surprise. To refresh your memory, we are doing all this looping things in order to get the route name so that we can use the UrlHelper to get the Location header URI. So, after I was able to get a route object instance, I found out that there is no way to get it’s name. Yeap, you create a route with a name. The UrlHelper asks you for a route name. You can even check in the collection if there are any routes with a given name. But you can’t get the name from a route instance. With dotpeek’s help I figured out that the name is used as the key in the private dictionary that the HttpRouteCollection wraps. But the HttpRouteCollection doesn’t make the Keys property of the dictionaty available to the outside world. That’s it. There is no way for you to programmatically find a routes name.

Ah, the ControllerContext

At this point I was already pretty frustrated. I was working on this during the Dallas Day of .Net and I was afraid I wouldn’t be able to keep cursing only in my head anymore. Actually I believe I said one or two “WTF!” loudly. Anyways, I gave up the whole let’s-find-out-the-route-name-thing and decided to hard code the default one instead. Just so that I could at least see the thing working.

To my despair, I realized that the System.Web.Http.Routing.UrlHelper depends on the HttpControllerContext, not in the RequestContext as System.Web.Mvc.UrlHelper. As I can’t simply create, or at least not as easily, an instance of the HttpControllerContext as I can create one of the RequestContext, I just changed the constructor of the CreateResponse to also include the HttpControllerContext.

I’m definitely not happy with this and I won’t include any of it, as it is, in the WebAPIContrib.

Least Surprise who?

Let’s be clear: this whole thing of System.Web.Mvc vs. System.Web.Http is confusing as hell. Things have the same name but are different types. The api for those types are different. They behave differently. I can see a lot of people struggling as I did when trying to use whatever they are using in their MVC projects in a Web API one.

But the Web API is still in beta and this is what a beta is for, right?

Yes, the ASP.NET Web API is still in Beta and I expect a lot of the library api to change. As Henrik Nielsen asked me to do, I’ll register the issues I had on user voice. And I can only hope they will fix it. Or maybe accept a pull request ;-)