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
Tried to run the code provided on GitHub but it is not working as expected. The Service locator will pick up/resolve an interface to the last registered concrete class not based on the given serialized type(i.e json payload).
hfarouk,
Sorry you had issues with the code. Could you provide to me your container registrations so I can better understand what went wrong? Are you using named registrations?
Please let me know and I will do what I can to correct.
BDN
Thank you for this article. I looked around for several hours yesterday looking at various solutions to this situation. Though I dd not go full “generic” I did adapt it to cover the cases I needed with a single converter implementation which took the Interface Type and Implementation class:
public class MyCustomConverter : CustomCreationConverter where C: I , new()
I then registered an instance of the converter for each interface/implementation pair:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new MyCustomConverter());
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new MyCustomConverter());
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new MyCustomConverter());
Thanks for the guidance. I’d still be working on this today without it!
Glad you found it helpful!
Thanks for the nice blog.
Can you please describe more on to deal with different derived types handling through interface parameter in Web API. I have tried the same thing but not able to create instance of different derived types. Please help me on the same.
In the case multiple derived types, I generally will implement a marker interface called IPolymorphic (just a a marker call it anything you want…). Once marked the custom creation converter can use the presense of the interface as an indicator that it needs to use a factory in order to create the correct concrete type.
1. In ReadJson inspect the type and see if it of type IPolymorphic
2. If it is resolve your factory from the container, and ask it for the correct concrete type.
Brette
Great article, will definitely use this info!
I had to smile at your comments about the ‘cool kids,’ as I am a committed Windows / PC user since 1988, when I wanted to go GUI and realized that Macs cost twice as much, so I got a $1000 PC clone and Windows 2.03 (and a year later helped a friend set up a desktop publishing business on Windows 2.11, PageMaker 3.01 and an HP LaserJet II for about a third to a half the cost if we had gone Mac.
My $1000 PC clone was also the last desktop I ever purchased from a store. Been upgrading components and building new ones ever since.
As far as notebooks, $800 is my maximum spend (before RAM upgrades and SSDs), and I have been using 17″ screens for quite a few years. My bank account loves my PC notebooks!
And have also love my Windows Phones – after my HTC I got in 2011 dropped and cracked in 2015, an awesome T-Mobile rep turned me onto the fact that I could get a $40 Lumia 435 minute phone from Best Buy and they could cut my SIM card to fit in it, which is what I did. Worked great until the TLS update and I could do my banking anymore, but at a social gathering, when a friend who works at Microsoft learned I was using a WIndows phone, he gave me a demo Lumia 950XL that he had been having trouble giving away, so my total spend on phones since 2015 has been $40!
While I can’t do some things like FaceTime on my phone, I learned from watching ‘The Jetsons’ that video phone calls are often more trouble than they are worth, and I already know what anyone I call looks like, so I’m not missing it in the least.
Also, while I think the ‘cool kids’ tend to love coding in languages that IMO hearken back to the 70s, when compilers needed semicolons to know when lines of code ended, overloaded punctuation characters like the curly brace for multiple language constructs, and lauded terseness as a benefit because every byte of RAM was precious, while I started my professional programming career in C and C++, and have forgotten more languages than most folks will ever learn, my language of choice has always been BASIC, have coded primarily in VB.NET since the betas, and neither myself nor others have any problems reading and understanding my VB.NET code that I wrote over a decade ago, some of which has been running without modifications on both online and offline applications.
Oh, and I hate skinny jeans. Though they looked stupid (on guys) in the 80s, still do.
[…] fixing it. I looked at ASP.NET Web API Operation with interfaces instead concrete class and also at https://brettedotnet.wordpress.com/2014/07/16/web-api-and-interface-parameters/ and at ASP.NET Web API Operation with interfaces instead concrete class, but none of the […]