Skip links
features of net core

Features of .NET Core

In this article, we will go through for how to model binding in dot net core.

If you look with older version of mvc, model binding process is based on model binder and value providers, the matched binder would have access to the request which will extracted data from request. The DefaultModelBinder class was used along with value providers that extracted data from the query string, form data, route values and even from the parsed JSON body.

In asp.net core, there is single framework which is merged by web api and mvc. you might be wondering how does model binding merge in dot net core. Answer is, There are value providers for route values, query string values and form values. Binders based on value providers can get data from any of these, but won’t be able to get data from other sources like the body for example.

Binding with Attributes

Attributes on action parameters can be used to override the default binding behaviour:

  • Override binding behaviour
    • [BindRequired]: add model state error if binding fails
    • [BindNever]: ignore the binding of parameter
  • Override binding source
    • [FromHeader]: use HTTP header
    • [FromQuery]: use URL query string
    • [FromRoute]: use routing values
    • [FromForm]: use form values (via HTTP POST)
    • [FromServices]: inject value using dependency injection
    • [FromBody]: use HTTP request body, based on configured formatter (e.g. JSON, XML). Only one action parameter can have this attribute.
  • Supply custom binding
    • [ModelBinder]: provide custom model binder

Custom model binder 

Here we will see one scenario :

I want to bind a Guid parameter to my ASP.NET MVC Core API:

[FromHeader] Guid id

but it’s always null. If I change the parameter to a string and parse the Guid from the string manually it works, so I think it’s not detecting Guid as a convertable type.

And answer is, basically ASP Core only supports binding header values to strings and collections of strings! (whereas binding from route values, query string and body supports any complex type)

for achieve this we can create custom model binder as below :

public Task BindModelAsync(ModelBindingContext bindingContext)
{

if (bindingContext.ModelType != typeof(Guid)) return Task.CompletedTask;
if (!bindingContext.BindingSource.CanAcceptDataFrom(BindingSource.Header)) return Task.CompletedTask;

var headerName = bindingContext.ModelName;
var stringValue = bindingContext.HttpContext.Request.Headers[headerName];
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, stringValue, stringValue);

// Attempt to parse the guid
if (Guid.TryParse(stringValue, out var valueAsGuid)){
bindingContext.Result = ModelBindingResult.Success(valueAsGuid);
}

return Task.CompletedTask;
}

And which would be used like below in controller :

public IActionResult SampleAction([FromHeader(Name="my-guid")][ModelBinder(BinderType=typeof(GuidHeaderModelBinder))]Guid foo)
{
return Json(new { foo });
}