Introduction
HTTP is the backbone of a website's communication. This regulates how clients and servers exchange information. One of the must-have capabilities of a server is to get data from a client's request. In ASP NET Core, every incoming request from the client will be caught by the Kestrel server and transformed into object context, then passed into source code, and finally routed to the endpoint. First, let's look at how to get data from request object context without a model binding mechanism.
Get query string from context object
Without model binding, you must do extra work to do. First, you need to access the IQueryCollection
object from HttpContext
and check if there is any associate key-value pair. If any, it will give you a StringValues
type, which under the hood implements IList<string>
so you need to access a string element from that list, and then you need to perform a type conversation from the string into the appropriate value. This tedious work increases the error-proneness, luckily ASP.NET offers the easy way with Model Binding mechanism.
Model Binding
Model binding is one of the greatest mechanisms in ASP.NET. It is a process of collecting the data from an incoming request (it could be in the form of query string, route data, request body, or request header) and then supplying the values as an action method argument. Hence, you have access directly to data that was sent from the client to perform validation and process it in the business logic layer. Behind the scenes, ASP.NET will take care of the binding process, so it's not ours. The model binding mechanism will automatically perform when requests are routed to match endpoints and right before the execution of the action method.
let's look how to get query string data with model binding
It seems like magic 🎩✨🐇 isn't it?
It is significantly quicker and easier. to extract data from a query with model binding that you wouldn't need to perform a data conversation from a string into an appropriate type. It comes automatically behind the scenes by model binding.
In order to bind successfully, you must make sure the name of the key of the query string matches the identifier of the action method parameter. but you don't have to match the case because it is not case-sensitive. Bonded data is not limited to one source. It still works fine if you place the data in the query string and route data.
Get Query String and Route Data with model binding
So it is great that ASP.NET has these features to make development more intuitive, easy, and fast. However, if you don't understand the behavior of model binding, you will end up confused. Let's say the client makes the following request:
From above, we can see that it has collision data between the query string and route data because they have the same identifier called "movieId". If we look at the above watch window, the movieId gets populated with a value of 89. You might wonder why ASP.NET extracts "movieId" parameter data from route data instead of a query string? It turns out ASP.NET has an order of priority for model binding. Let's take a look at the image below, It starts from the top, which has the highest priority, down to the bottom, which has less priority.
Great, now you have a better understanding of model binding behavior.
But what if you don't want to achieve this behavior?
You can use the [FromQuery]
attribute to tell ASP.NET, "Hey, forget about your order priority. I will state explicitly that I want you to bind the data from the query string instead."
It will populated movieId with value of 22 instead of 89.
here another useful attribute list that you can use to explicitly specify the source of data for action method parameters
[FromRoute]
[FromQuery]
[FromBody]
[FromForm]
Model Binding with Model Class
What happens if the customer provides a lot of data? Of course, you don't want to scatter up the action method arguments; it will clutter your code. Instead, you can create a model class and declare it as an action method parameter. Model binding will automatically map incoming request data to the properties of your model class based on their names.
client send a request with a multipart/form-data
content type
Great, the movie object has been automatically populated based on the data from the request form-data. Sometimes you want more granular control over which properties get populated from incoming request data, to achieve this, you can utilize [Bind]
and [BindNever]
attributes.
-
Bind
Title
value and leave the rest of properties to hold null or default value -
BindNever
Title
property excluded from the binding process hence, it will store a null value, and the rest of the properties still be populated from the binding.
Custom Model Binders
ASP.NET gives you more control over the binding process from requests into action method parameters by creating your own model binding class. so it will override the built-in Model binding mechanism and use your own model binding class. Let's say that the client will send query string data of poster URL and trailer URL and you want to store them into a single value separated by semicolon. First, you need to create a class that implements the IModelBinder
interface and overrides the BindModelAsync
method.
After you create your own model binder class, you need to decorate the parameter of your model parameter in the action method with the ModelBinder
attribute and pass your model as a type on the first argument.
You are successfully using your own custom model binder so you can have granular control over the rule of the binding process.
Conclusion
Model Binding Mechanism in ASP.NET helps us to populate data from requests with a breeze. It will perform automatically, and you don't have to write tedious code that could be error-prone. With the understanding behavior of model binding performed by ASP.NET you know how to handle it if something looks off or does not look as you expect it with the right technique. Even if the model binding by ASP.NET cannot meet your requirements, you can create your custom model binders by yourself and override the built-in model binding mechanism in ASP.NET.
Top comments (1)
Nice