Model Binding Using FromHeader in ASP.NET Core Web API

Model Binding Using FromHeader in ASP.NET Core Web API

In this article, I will discuss How to Implement Model Binding Using FromHeader in ASP.NET Core Web API Application with Examples. Please read our previous article discussing Model Binding Using FromRoute in ASP.NET Core Web API with Examples.

FromHeader Attribute in ASP.NET Core Web API

Model binding in ASP.NET Core Web API is a process that maps data from HTTP requests to action method parameters. When developing APIs, sometimes you need to retrieve data from different parts of an HTTP request, such as the query string, request body, route data, and headers. ASP.NET Core provides various attributes to facilitate this process, and FromHeader is one of them. It is specifically used for mapping data from HTTP headers to action method parameters.

In ASP.NET Core Web API, the FromHeader Attribute binds a method parameter to a request header. This attribute allows you to access the value of a specific HTTP header directly from the action method parameters in your controller. This is useful for reading metadata, authentication tokens, or other information transmitted in HTTP headers.

Example to Understand FromHeader Attribute in ASP.NET Core Web API:

When you decorate a parameter with the [FromHeader] attribute in an action method, ASP.NET Core will attempt to find a header of the same name as the parameter in the incoming HTTP request and bind its value to the parameter.

For a better understanding, please modify the User Controller as follows. We have decorated the Authorization parameter with the FromHeader Attribute. The ASP.NET Core Framework will map this parameter with the incoming HTTP Request’s Authorization header value.

using Microsoft.AspNetCore.Mvc;
namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        [HttpGet]
        public IActionResult GetResource([FromHeader] string Authorization)
        {
            // Implementation
            if(Authorization == null)
            {
                return BadRequest("Authorization Token is Missing");
            }

            return Ok("Request Processed Successfully");
        }
    }
}

If we send the Authorization header value while making the HTTP request, then we will get a 200 OK Status Code; else, if the Authorization header is missing in the HTTP request, then it will return 400 Bad Request. Now, run the application and send an HTTP GET request to the above endpoint (/api/user) without an Authorization header, and you should get the following response. Please change the port number where your application is running:

Example to Understand FromHeader Attribute in ASP.NET Core Web API

Now, if you are wondering why the custom error message that we passed the BadRequest method is not returning in the response body, this is because of the ApiController Attribute, which is decorated at the Controller level. This ApiController Attribute will check the model state. If it is not valid (checking the values of the mandatory parameter, the parameter which is non-nullable), then it will simply return 400 Bad Request without executing the Controller action method. The above response is the default Bad Request response set by the ApiController Attribute.

Now, if you set the Authorization header attribute in the request header, then you will get the 200 OK Status code as shown in the below image:

FromHeader in ASP.NET Core Web API

Giving Different Names to Method Parameters:

If you want to bind a header that has a different name from the parameter, you can specify the header name as an argument to the FromHeader attribute. For a better understanding, please modify the User Controller as follows.

using Microsoft.AspNetCore.Mvc;
namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        [HttpGet]
        public IActionResult GetResource([FromHeader(Name = "Custom-Header")] string customHeader)
        {
            if(customHeader == null)
            {
                return BadRequest("Custom-Header is Missing");
            }

            return Ok("Request Processed Successfully");
        }
    }
}

In the above example, the GetResource method expects a custom header named Custom-Header in the incoming HTTP request. The FromHeader attribute specifies that the customHeader parameter should be populated with the value of this header. Now, run the application and access the above endpoint (api/user) with a GET HTTP Request, and it should work as expected, as shown in the below image:

Giving Different Names to Method Parameters

How Does FromHeader Attribute Work in ASP.NET Core Web API?

In ASP.NET Core Web API, model binding refers to the process of mapping request data to action method parameters. The FromHeader attribute tells the model binder to look for a value in the HTTP request’s header collection with a name matching the name of the parameter or property it is applied to. If a matching header is found, its value is assigned to the parameter or property.

Binding FromHeader to Complex Type in ASP.NET Core Web API

While FromHeader is typically used with simple types, you can also use it with complex types by specifying headers for each property of the complex type. However, this requires a custom model binder because ASP.NET Core automatically will not map the header values to model properties.

Imagine an application where user preferences are passed in the request header. These preferences might include the user’s preferred language and theme, which the API needs to process to return personalized content.

Define the Model

First, define a simple model class that corresponds to the data you expect in the HTTP header. So, create a class file named UserPreferences.cs and then copy and paste the following code:

namespace ModelBinding.Models
{
    public class UserPreferences
    {
        public string Language { get; set; }
        public string Theme { get; set; }
    }
}
Implement Custom Model Binding

ASP.NET Core doesn’t automatically bind data from headers to model properties, so you need to implement a custom model binder. So, create a class file named HeaderModelBinder.cs and copy and paste the following code. The following HeaderModelBinder class serves as a custom model binder designed to map data from HTTP request headers to a specific model class, in this case, UserPreferences.

using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace ModelBinding.Models
{
    public class HeaderModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            var headers = bindingContext.HttpContext.Request.Headers;
            var model = new UserPreferences
            {
                Language = headers["Language"],
                Theme = headers["Theme"]
            };

            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;
        }
    }
}
In the above example:
  • Public Class Declaration: The HeaderModelBinder is defined as a public class, making it accessible to other parts of the application.
  • Implements IModelBinder Interface: By implementing the IModelBinder interface, this class agrees to fulfill a contract that requires the implementation of the BindModelAsync method. This method is where the logic for binding data from the request to a model resides.
  • Method Signature: The BindModelAsync method is asynchronous, indicated by returning a Task. It’s responsible for the actual binding process.
  • Parameter – ModelBindingContext bindingContext: The method takes a single parameter, ModelBindingContext, which provides context for the model binding operation. This context includes information about the HTTP request, the model type, and other metadata necessary for binding.
  • Null Check: The method starts by ensuring that the bindingContext parameter is not null. If it is, an ArgumentNullException is thrown. This is a defensive programming practice to ensure that the method has all the necessary information to proceed.
  • Accessing Request Headers: This statement (var headers = bindingContext.HttpContext.Request.Headers;) retrieves the collection of headers from the HTTP request through the bindingContext. It demonstrates how model binders can access request data.
  • Model Instantiation and Population: A new instance of the UserPreferences model is created, and its properties are populated using values from the request headers. The headers are accessed by name, which should match the expected headers in the HTTP request.
  • Setting the Binding Result: This statement (bindingContext.Result = ModelBindingResult.Success(model);) is crucial as it signals the completion of the model binding process. The ModelBindingResult.Success method is called with the populated model instance, indicating successful binding. This result is then assigned to the Result property of the bindingContext, making the bound model available to the action method that will use it.
  • Completing the Task: Task.CompletedTask is returned to signify that the method has completed its execution.
Creating the Custom Model Binder Provider:

To use the HeaderModelBinder, you need to instruct ASP.NET Core to use it for the UserPreferences type. This can be done with a custom model binder provider. So, create a class file named HeaderModelBinderProvider.cs and copy and paste the following code. The following HeaderModelBinderProvider class is used for implementing custom model binding in ASP.NET Core. This class is responsible for providing an instance of the HeaderModelBinder whenever a specific model type (in our example, UserPreferences) needs to be bound from the request headers.

using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace ModelBinding.Models
{
    public class HeaderModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Metadata.ModelType == typeof(UserPreferences))
            {
                return new HeaderModelBinder();
            }

            return null;
        }
    }
}

The following is the explanation of the above class:

  • Public Class Declaration: Declares the HeaderModelBinderProvider as a public class, making it accessible throughout the application.
  • Implements IModelBinderProvider Interface: By implementing the IModelBinderProvider interface, the class agrees to implement the GetBinder method, which is used by the ASP.NET Core framework to determine which model binder to use for a given model.
  • Method Signature: The GetBinder method returns an instance of IModelBinder and takes a single parameter, ModelBinderProviderContext. This context provides information about the model and binding scenario, which can be used to decide whether to return a specific model binder.
  • Parameter – ModelBinderProviderContext context: This parameter provides access to the context in which the model binder provider is being asked to provide a binder. This includes the type of the model, metadata about the model, and other relevant details.
  • Null Check: The method begins by verifying that the context parameter is not null, throwing an ArgumentNullException if it is. This ensures that the method has the necessary context to make decisions.
  • Conditional Binder Provision: The method then checks if the model type being bound is UserPreferences. It does this by comparing the model type from the ModelBinderProviderContext (context.Metadata.ModelType) to the UserPreferences type. If they match, it instantiates and returns a new instance of HeaderModelBinder, indicating that this binder should be used for binding instances of UserPreferences from the request headers.
  • Default Return Value: If the model type does not match UserPreferences, the method returns null. Returning null indicates to the ASP.NET Core framework that this provider does not have a suitable model binder for the current model, and the framework should continue searching through the remaining model binder providers for an appropriate binder.
Register Custom HeaderModelBinderProvider:

Then, add this provider to the AddControllers options in the Program.cs class file as follows. Please make sure to include the namespace in the Program.cs class file where you defined the HeaderModelBinderProvider class.

builder.Services.AddControllers(options =>
{
    options.ModelBinderProviders.Insert(0, new HeaderModelBinderProvider());
});
In the above code,
  • services.AddControllers(): This call adds MVC (Model-View-Controller) services to the application’s services container, which are necessary for building Web API applications. It sets up the essentials for handling HTTP requests with controllers.
  • options =>: This lambda expression is used to configure options for MVC services. The options parameter represents an object of type MvcOptions, which provides several properties and methods to configure MVC behavior.
  • options.ModelBinderProviders.Insert(0, new HeaderModelBinderProvider());:
      • options.ModelBinderProviders: This property is a collection of IModelBinderProvider instances. Each provider in this collection is responsible for providing model binders that can bind incoming HTTP request data to action method parameters. ASP.NET Core iterates through this collection to find an appropriate model binder for each parameter.
      • .Insert(0, new HeaderModelBinderProvider());: This method call inserts a new instance of HeaderModelBinderProvider at the beginning (index 0) of the ModelBinderProviders collection. The significance of inserting at the beginning is to ensure that your custom model binder provider is evaluated before the built-in providers. This is crucial when you want your custom logic to take precedence over the default model binding behavior.
          • 0: The index position where the new model binder provider should be inserted. By inserting at index 0, you ensure that this provider is the first to be considered when the framework is looking for a model binder for a given type.
          • new HeaderModelBinderProvider(): This creates an instance of your custom model binder provider, HeaderModelBinderProvider, which you’ve defined to handle specific model binding scenarios, such as binding from HTTP headers.
Use the Model in an Action Method

Finally, you can use the UserPreferences model in your controller action methods. The framework will use your custom model binder to populate the model from the request headers. So, modify the User Controller as follows:

using Microsoft.AspNetCore.Mvc;
using ModelBinding.Models;
namespace ModelBinding.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        [HttpGet]
        public IActionResult GetResource([ModelBinder] UserPreferences userPreferences)
        {
            // Use the userPreferences object as needed
            return Ok(new { Message = "User Preferences Received", Preferences = userPreferences });
        }
    }
}

Note: The [ModelBinder] attribute allows customization and control over the model binding process for specific parameters within an action method. It is useful in scenarios where you need to bind data from a source that is not automatically handled by the default model binders or when you want to apply a specific model binder to a particular action parameter.

With the above changes in place, run the application and issue an HTTP GET Request to the above endpoint using Language and Theme custom headers in the request, and you should get the response as expected, as shown in the below image:

Binding FromHeader to Complex Type in ASP.NET Core Web API

Point to Consider:
  • Case Sensitivity: Header names are case-insensitive. Therefore, the case of the header name specified in the FromHeader attribute doesn’t need to match the case of the header in the HTTP request.
  • Optional Headers: If the header specified by the FromHeader attribute is not present in the request, the parameter will be null (for reference types) or the default value (for value types). You can make your action method logic handle such cases accordingly.
  • Complex Types: While FromHeader is typically used with simple types like string or int, binding complex types from a single header can be challenging and is generally not recommended. Headers are better suited for straightforward, scalar values.
  • Error Handling: If there’s an error during the binding process (e.g., a format issue), ASP.NET Core might not call your action method, depending on your API’s configuration regarding model validation errors.
When to Use FromHeader Model Binding in ASP.NET Core Web API?

The FromHeader model binding attribute is used to bind parameter values directly from HTTP headers. This approach is useful in specific scenarios where data is passed as part of the HTTP request headers rather than in the body or URL. Here are some scenarios where you might use FromHeader model binding:

  • Authentication Tokens: When using token-based authentication, such as JWT (JSON Web Tokens), clients typically pass tokens in the request headers. You can use FromHeader to extract these tokens directly in your action method parameters.
  • Versioning: API versioning can be implemented through headers to specify which version of the API the client intends to use. By using FromHeader, you can capture the version information directly and route the request to the appropriate logic based on the API version requested.
  • Localization: For global applications, clients might pass the preferred language or locale in the headers. You can use FromHeader to capture this information and localize the response based on the client’s preferences.
  • Custom Metadata: Sometimes, applications might require additional metadata for processing requests, which doesn’t naturally fit in the body or URL. Examples include request IDs for tracing, client-specific flags, or feature toggles. FromHeader can be used to capture such metadata efficiently.

In the next article, I will discuss Model Binding Using FromBody in ASP.NET Core Web API with Examples. In this article, I try to explain Model Binding Using FromHeader in ASP.NET Core Web API with Examples. I hope you enjoy this article, “Model Binding Using FromHeader in ASP.NET Core Web API.”

Leave a Reply

Your email address will not be published. Required fields are marked *