The code examples can be found here. Do what you will with it, but as always, no warranty for you!
Sweet sweet abstraction. Its a pretty powerful thing, right? From a clients perspective everything is nice and tidy, while all of the nasty not so pretty details are tucked away under the covers. And as we all know, in statically typed languages, the king of abstraction is the mighty mighty interface. But it might surprise you, that with the ASP.Net Web API, you cannot use interfaces as parameters to your action methods (say what!!!!!). To be fair, if you think about it, it actually does make sense. After all, how can model binders and formatters possibly know what concrete type you want when they encounter an IFoo interface at run-time. In fact, if you try it, the formatters wont even try, resulting in a lovely null reference exception somewhere down the stack. So if you wanted to do something similar to the code snip below, you are out of luck my friend.
using System.Web.Http; using WebApiInterface.Models; namespace WebApiInterface.Controllers { public class FooController : ApiController { public void Post(IFoo foo) { //Do some stuff to foo } } }
So why doesn’t this work? Again, because the JSON formatter cannot determine the desired run-time type of IFoo you want, it simply skips it. And as a result, you will be left with null. Like I said, its very sad, but it makes sense.
So, what can we do to support this?
How About IoC?
At first glance it may seem like simply plugging in some good ol’ inversion of control might be the answer. After all IoC fixes everything, right? For those of you not familiar with some of the extension points of the Web API, let me explain how leveraging IoC might help. In the Web API’s Global Configuration there is a DependencyResolver property exposed.
GlobalConfiguration.Configuration.DependencyResolver
By setting this configuration option to an IoC enabled dependency resolver, we can control how the Web API resolves dependencies. So for example, when the Web API creates our controllers and it comes across an interface parameter, we can tell it to look in our IoC container for the run-time type bound to the specified interface. This is very useful for injecting a UnitOfWork a Service or any other object we need in our controller. While this is a great first step, it does not directly help us with our desire to have interface types as action parameters. But it is a very important first step, so lets take a look at how we plug IoC into the ASP.Net Web API
Setting Up IoC
OK, let me first say that I know most of the cool kids hate on Unity. But hey, I don’t wear skinny jeans, I still have a PC, and I have grown used to the judgmental glares I get at my local coffee shop as I proudly play with my windows phone. That said, for simple no frills IoC support I still think its a really nice option. So with some help from the great NuGet package we are going to set up our Web API to use unity as our dependency resolver. First run the NuGet package, here are some details on the set up. Once Unity is set up, we need to configure our container like so.
namespace WebApiInterface { public static class UnityConfig { public static void RegisterComponents() { var container = new UnityContainer(); container.RegisterType<IFoo, Foo>(); GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); } } }
Nothing too fancy, just a simple registration stating that when a controller constructor asks for an IFoo, it should get an instance of type Foo. Additionally, you can see that I am setting the DependencyResolver configuration option I mentioned above to the a new instance of the UnityDependencyResolver supplied by the Untiy.WebApi Nuget package. This is what does the actual work of resolving the object instances from the container. With these changes our IoC configuration is ready to go. And god willing, when our controllers are created any dependencies they declare will be resolved by way of our unity container.
And there it is.
But What About Our Action Methods
While setting up IoC this way works great to resolve interface types when our constructors ask for them. It does nothing to help us in our action methods. The image below shows an http post to our Foo controller. As you can see we end up with a null, not a Foo.
Custom Creation Converter
OK so how can we leverage our IoC container setup to resolve interface types in our action methods. As it turns out, for that we need to look for extension points within our configured formatter for a solution. While the Web API’s Dependency Resolver will help us with constructor injection, it does nothing to help us with our action methods. For that we need something a a little different.
For those of you who want a wonderful explanation of model binding and formatters: read this, its a great article.
Looking at our problem it turns out that JSON.Net has one very slick extension option that can help us. And that is the Custom Creation Converter. Much like our dependency resolver gives the Web API the ability to do constructor injection, Custom Creation Converters give JSON.Net specific instructions on how to create object instances during the deserialization process. So when JSON.Net is walking down our object graph, as it finds interface types, it will look for a configured Custom Creation Converter to delegate the object creation process to. This allows us to explicitly influence how objects are created when specific interfaces are found during the model binding process.
The Custom Converter
Here is the code for our custom creation converter.
public class FooCustomConverter : CustomCreationConverter<IFoo> { public override IFoo Create(Type objectType) { return new Foo(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } IFoo obj = Create(objectType); serializer.Populate(reader, obj); return obj; } }
And in order to tell JSON.Net to use this converter we also need to register it. Again we can use the global configuration objects for this.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new FooCustomConverter());
As you can see there is not much to this at all. First we simply derive from the CustomCreationConverter<T> given to us by the JSON.Net framework. This gives us two methods we need to override. First, the Create method. This method creates a new instance of our Foo object. Second, the ReadJson method. This method is called for us by JSON.Net as it reads each JSON element. There are a few things to note here. We want to return null when the token type is null. This happens when no value is supplied for the JSON element. If the token type is not null, we call the Create method to create the new Foo object. Then we use the supplied serializer instance to map the JSON bits into the new Foo object by calling the populate method. And last we return the newly created and mapped object so JSON.Net can add it to the object graph that is being created.
All and all this is pretty simple, but this design has some very serious flaws. For one, it would required a CustomCreationConverter for every interface type you want to support, boo. Secondly since our converters are not using IoC, if we want to support multiple derived types, that logic needs to be put into the converters somehow, booooooooooo. So, lets tighten up our implementation so both of those problems go away.
Enter The IoC Custom Creation Converter
Since we have IoC all ready wired up, it is possible to create a single CustomerCreationConverter to service all of our needs. Notice in the code below, that in our override of the ReadJson method JSON.Net is kind enough to supply us with the type information for each object it is trying to deserialize. This information is precisely what we need to delegate object creation to our unity container. Lets take a look at what this might look like.
public class IocCustomCreationConverter<T> : CustomCreationConverter<T> { public IocCustomCreationConverter() { } public override T Create(Type objectType) { return (T)ServiceLocator.Current.GetInstance(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } var obj = Create(objectType, reader, serializer); serializer.Populate(reader, obj); return obj; } }
As you can see, we did not have to change the code very much. In fact the only major change is in the Create method. Here we ask the container (via the service locator) to create the object instance for us, as opposed to us manually ‘newing’ up the object. We are using the ServiceLocator pattern so we do not need direct access to the container in our JSON serilaizer. If you are not familiar with the ServiceLocator pattern, here is a quick primer on it. Now that we have our IoCCustomerCreationConverter ready to go we need to register this with JSON.Net with the simple one-liner below.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IocCustomCreationConverter<IActionParameter>());
One thing you might notice here is that I am registering the custom creation converter to only work with types that derive from IActionParameter. This is not required but there are some things that we may not want to use our Custom Creation Convert for. For primitive types such as an int or bool, it does not make any sense to ask JSON.Net to use a custom converter. So by using this simple marker interface we can control what types are actually resolved using our new converter.
Wrapping Up
So there you have it! By configuring IoC and adding a single JSON.Net Custom Creation Converter, we are now able to abstract the parameters to our action methods. This is great for testability, as well as creating APIs that may need to serve multiple clients with varying data structures. And that is a pretty cool thing!
BDN