The importance of request identity

ASP.NET Core

One of the more important aspect of API development is we have to give each request an identity. This is especially important if we are logging each request & response for tracing, caching, or validation.

In case of ASP.NET Core, a request identity could be injected at the scoped level where it will lives through the life-cycle of a request.

To bind the request data, we could use a middleware. Since the class is injected at the scoped level, each access to the class/object would be the same within the request life-cycle.

A class to store the information of a request.

public class RequestIdentity
{
  public string ClientKey { get; set; }

  public RequestIdentity() {}

  public void BindRequestData(string clientKey)
  {
     ClientKey = clientKey;
  } 
}

Using a middleware, we could easily bind the required information into the class. Let's assume the client key is supposedly being included in the header.


public class RequestIdentityInitMiddleware
{
  private readonly RequestDelegate _next;

  public RequestIdentityInitMiddleware(RequestDelegate next)
  {
      _next = next ?? throw new ArgumentNullException(nameof(next));
  }

  public async Task Invoke(RequestIdentity requestIdentity, HttpContext httpContext)
  {
     if(!string.IsNullOrEmpty(httpContext.Request.Headers["CLIENTKEY"].ToString())
     {
         requestIdentity.BindRequestData(httpContext.Request.Headers["CLIENTKEY"].ToString());
     }
     else
     {
         // Throw exception
     }

     await _next.Invoke(httpContext);
   }
}

Finally, we just need to inject the required services and middleware.

// Services
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<RequestIdentity>();

// Middleware
app.UseMiddleware<IgnorePreloadMiddleware>();

ASP.NET MVC

In case you are not developing using .NET Core, it might be a bit different on how a request identity is stored. We will be utilizing the static Current property of System.Web.HttpContext to store our request identity.

Let's say I have a similar class like above called RequestIdentity, but with some slight difference. We will have an interface which defines a method signature for us to get the client key. 

public class RequestIdentity : IGetRequestClientKey
{
  private string clientKey = string.Empty;

  // Private constructor to prevent the init.
  // of this class
  private RequestIdentity() {}

  // We provide a static method to obtain
  // the current RequestIdentity object via
  // HttpContext
  public static RequestIdentity Current
  {
    get
    {
      if(!HttpContext.Current.Items.Contains("RequestIdentity"))
      {
        HttpContext.Current.Items.Add("RequestIdentity", 
                                      new RequestIdentity());
      }

      return (RequestIdentity)HttpContext.Current.Items["RequestIdentity"];
    }
  }

  public void BindRequestData(string clientKey)
  {
    this.clientKey = clientKey;
  } 

  public string GetClientKey => clientKey; 
}

public interface IGetRequestClientKey
{
  string GetClientKey { get; }
}

The HttpContext object is as per request, and we provide a static method to ensure the object RequestIdentity is only obtained only via the HttpContext. The purpose of defining an interface is to simplify unit test, so we do not need to mock HttpContext. Instead, we could mock IGetRequestClientKey.

More information could be obtained here: https://stackoverflow.com/questions/1134442/httpcontext-items-with-asp-net-mvc.

Comments

Popular posts from this blog

ASP.NET Core service locator pattern

Caching and generic query using NHibernate [.NET Core]

Ways to perform eager loading via NHibernate