Understanding Model Binding in ASP.NET Web API
Before diving in-depth of Model Binding in Web API 2, I would highly recommend you to go ahead and check “Content Negotiation in Web API 2”. The article will give you glimpse over creating Web API projects and how to use POSTMAN for testing your web APIs. For this article, I will consider the same project I created in Content Negotiation and Postman for testing. The mechanism to map the service request and its input data to the correct action method and its parameters is known as Model Binding aka Parameter Binding.
So now, a very genuine question some of you must be thinking “How does the model binder understands, which method to be linked to with the requested URI?” Hmmmm…. A good question!! Let’s see how this is managed.
HOW DOES WEB API BIND THE HTTP VERBS TO THE ACTION METHOD
This is taken care by the WebAPIConfig and HTTP Verbs. The Route config for WebApi tells us the URL parameter it should accept. Observe the RouteTemplate parameter in the below figure. It says that any URL which is decorated with API followed by the controller name, in our case its Products, and also having a facility to provide Id, not mandatory, is a correct URL.
Similarly, when an Action Method is suffixed with HTTP Verb, GET PUT POST DELETE, along with input parameter (non-mandatory) is mapped to the URL
Let us consider the GET method. I requested the URL ‘api/Products’. Ok so now, the model binder first checks if the URL is decorated as required – “Ummm… Yes!! It has an API followed by Controller name. But no ID, ok!! That’s fine. It was anyways optional. I accept the URL. But wait, let me check if there is an input parameter in the request body? No. ok! So there is no input parameter anywhere so this seems to be the GET method. Let me now check in the action method list if I can find any method prefixed with GET and not accepting any input parameter. There it is, the GETPRODUCTS method”. In return, we get back the list of products.
Similarly, it works for other Action methods. But wait, this means I have to always prefix my method name with HTTP Verb? Won’t I be able to ever have a custom name? Let’s see what happens. I changed the GETPRODUCTS to LOADPRODUCTS and called the ‘api/Products’.
We land up getting an error.
So what now? Each HTTP verb is connected to HTTP Method.
So you simple need to decorate your method with the HTTP Method and rename your method as you desire.
Call the method in Postman and you get the product list back
Similarly, you can decorate your action methods with the desired HTTP Method and get the result.
TYPES OF MODEL BINDER
Model Binders are precisely of two types,
Primitive model binder
Complex model binder
Let’s understand them one-by-one.
Primitive Model Binder
If the request is simple, i.e. input parameter are of type int, string, Boolean, GUID, decimal, etc. & is available in the URL, then such kind of request is mapped to primitive model binding.
Data is available as Query String
Complex Model Binder
If the request is complex, i.e. we pass data in request body as an entity with the desired content-type, then such kind of request is mapped by Complex model binder.
Data not available via Query String
DEFAULT MODEL BINDERS
Till now you must have understood what methods use primitive type binding and which methods use complex type binding. I would just note it down though.
Primitive Type Binding
HTTP Methods like GET and DELETE where you are only required to send less quantity of input parameters, uses primitive type binding, by default.
Complex Type Binding
HTTP Methods like POST and PUT where you have to send the send model/entity data to the server, uses complex type binding, by default.
POST and PUT can also use combination of primitive and complex type. Consider you want to update data. So you can pass the Id in query string and the data to be updated in response body.
But what if I don’t want this default behavior? What if I don’t want to pass my parameter value in query string for GET/Delete methods? What if I want to pass few inputs from query string and few from response body? Can I achieve this? Surely, You can. Let’s see how.
FROMURI AND FROMBODY MODEL BINDER
For explaining the FROMURI and FROMBODY, I will consider the PUT method. As I mentioned above, PUT method accepts Complex type model binding or may be a mix of primitive-complex model binding.
In above image, ‘int id’ is the primitive type which accepts data from the URL or Query String whereas ‘Product product’ is complex type which accepts data from Request Body.
So we can decorate ‘int id’ with [FromUri] and ‘Product product’ as [FromBody]. In both the cases, calling the method and passing parameter would be same, the default behavior. Please Note: For the complex type, you need to pass all the properties mentioned in its entity class in the request body irrespective of ‘int id’ parameter. Now, what if I want to accept the primitive type from the body whereas the complex type from the URI? This can be achieved by decoration our method as follows,
In this case, we need to pass the ‘Id’ parameter through Request Body whereas the ‘Product’ as Query String or Route data.
Let’s see if our action method gets the value when we sent the request.
Ooo yes!! Our action method was successful to receive the input. Similarly, you can choose which input value you want the web API to read from as per your application needs. Also, you can decorate [FromUri] and [FromBody] in other HTTP methods, as per requirement.
Model Binding is the most powerful mechanism in Web API 2. It enables the response to receive data as per requester choice. i.e. it may be from the URL either form of Query String or Route data OR even from Request Body. It’s just the requester has to decorate the action method with [FromUri] and [FromBody] as desired.