In Web Api 2.0 and MVC5 you can only pass: int, bool, double etc.., TimeSpan, DateTime, Guid, decimal, and string values in URI. For any complex type having lists or other complex object within you have to pass serialized JSON/XML in the request body. But what If we want use such complex type from URI? Then read on…
What is binding?
Binding is a mechanism used by the Web Api to mapping request to an object defined in the controller. In this article I will show how to map complex types from URI requests using custom binding and AutoMapper.
I assume you know basics of Web Api bindings and AutoMapper. If not try here (http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api) and here (http://jasona.wordpress.com/2010/02/05/getting-started-with-automapper/).
Sample complex type
Without custom binding:
Normally we use it like this:
FromUri attribute forces Web Api to search data in query string, not from request body.
Our sample query string looks like this:
The result will be: model.SimpleField1 = “aaa”, model.ComplexField1 and model.ComplexField2 will be null – which is absolutely normal. Default behavior is not that smart. If we want to bind those two complex types we need custom binding.
Custom binding allow us to do whatever we like with the request. In this example I will operate only on URI data, but with custom binding we can also get to the body of the request as well.
To map request to our custom object we need to define custom binding by implementing System.Web.Http.ModelBinding.IModelBinder. It only has one method BindModel which return true if binding succeed or false - if not.
Definition of SampleComplexModelBinder
Using our binder is very simple:
As you can see there is attribute ModelBinder which takes as parameter type of our binder. Nice and simple! Now, let’s look at our SampleComplexModelBinder:
The most important lines are:
In this block we create total graph of our complex object. But is that mean that we need separate binder to every complex type we have? Well... no ;)
Definition of AutoMapperBinder
Below is very simple binder that use AutoMapper. This solution shows, that we can have only one generic binder to all our complex types. The only thing we should do before is to register our complex types in AutoMapper and define mappings:
Note that source type is always IDictionary<string, string>. It is important as this type is used in our AutoMapperBinder. This could be any type that is able to store query string content though.
What changed? Now we only have one line:
Usage is exactly the same as SampleComplexModelBinder with the difference that we pass also generic type:
Using AutoMapper with custom bindings may simplified our work a lot. If we have a lot of different complex object we can register them only by AutoMapper. With this approach we can map nested complex object and even list.