Explain the implementation method of factory based middleware activation in ASP. NET Core in detail

  • 2021-11-14 05:26:08
  • OfStack

IMiddlewareFactory/IMiddleware are extension points for middleware activation.

The UseMiddleware extension method checks whether the registered type of the middleware implements IMiddleware. If so, the IMiddleware implementation is resolved using the IMiddlewareFactory instance registered in the container instead of using convention-based middleware activation logic. Middleware is registered as a scope or transient service in the application's service container.

Advantages:

Activated by client request (injection of scoped services) Make middleware strongly typed

IMiddleware is activated on a client request (connection), so the scope service can be injected into the middleware constructor.

IMiddleware

IMiddleware defines the middleware of the application's request pipeline. The InvokeAsync (HttpContext, RequestDelegate) method processes the request and returns Task executed on behalf of the middleware.

Middleware activated using conventions:


public class ConventionalMiddleware
{
 private readonly RequestDelegate _next;

 public ConventionalMiddleware(RequestDelegate next)
 {
  _next = next;
 }

 public async Task InvokeAsync(HttpContext context, AppDbContext db)
 {
  var keyValue = context.Request.Query["key"];

  if (!string.IsNullOrWhiteSpace(keyValue))
  {
   db.Add(new Request()
    {
     DT = DateTime.UtcNow, 
     MiddlewareActivation = "ConventionalMiddleware", 
     Value = keyValue
    });

   await db.SaveChangesAsync();
  }

  await _next(context);
 }
}

Middleware activated using MiddlewareFactory:


public class FactoryActivatedMiddleware : IMiddleware
{
 private readonly AppDbContext _db;

 public FactoryActivatedMiddleware(AppDbContext db)
 {
  _db = db;
 }

 public async Task InvokeAsync(HttpContext context, RequestDelegate next)
 {
  var keyValue = context.Request.Query["key"];

  if (!string.IsNullOrWhiteSpace(keyValue))
  {
   _db.Add(new Request()
    {
     DT = DateTime.UtcNow, 
     MiddlewareActivation = "FactoryActivatedMiddleware", 
     Value = keyValue
    });

   await _db.SaveChangesAsync();
  }

  await next(context);
 }
}

The program creates extensions for the middleware:


public static class MiddlewareExtensions
{
 public static IApplicationBuilder UseConventionalMiddleware(
  this IApplicationBuilder builder)
 {
  return builder.UseMiddleware<ConventionalMiddleware>();
 }

 public static IApplicationBuilder UseFactoryActivatedMiddleware(
  this IApplicationBuilder builder)
 {
  return builder.UseMiddleware<FactoryActivatedMiddleware>();
 }
}

Unable to pass objects to factory-activated middleware through UseMiddleware:


public static IApplicationBuilder UseFactoryActivatedMiddleware(
 this IApplicationBuilder builder, bool option)
{
 // Passing 'option' as an argument throws a NotSupportedException at runtime.
 return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Add factory-activated middleware to the Startup.ConfigureServices In the built-in container of:


public void ConfigureServices(IServiceCollection services)
{
 services.AddDbContext<AppDbContext>(options =>
  options.UseInMemoryDatabase("InMemoryDb"));

 services.AddTransient<FactoryActivatedMiddleware>();

 services.AddRazorPages();
}

Both middleware are in Startup.Configure Register in the request processing pipeline of:


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
 if (env.IsDevelopment())
 {
  app.UseDeveloperExceptionPage();
 }
 else
 {
  app.UseExceptionHandler("/Error");
 }

 app.UseConventionalMiddleware();
 app.UseFactoryActivatedMiddleware();

 app.UseStaticFiles();
 app.UseRouting();

 app.UseEndpoints(endpoints =>
 {
  endpoints.MapRazorPages();
 });
}

IMiddlewareFactory

IMiddlewareFactory provides a way to create middleware. The middleware factory implementation is registered as a scoped service in the container.

The default implementation of IMiddlewareFactory (that is, MiddlewareFactory) can be found in the Microsoft. AspNetCore. Http package.


Related articles: