JKL JKL - 3 months ago 20
C# Question

How can we have Middleware like architecture in ASP.NET Core for our application?

I want to know how can I have middleware architecture like asp.net core in my application ?

Which pattern needs for this goal ?

Is there any reference for designing like this for adding new features and ... ?

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();

app.UseIdentity();

// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}


With very simple Configure method we can add new features to application How they implement something like this ?

Answer

The first thing I would do is read Middleware - Asp.Net Documentation

This will help understand how middleware is used and the pracitices to follow to implement your own custom middleware.

taken directly from docs

Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline. Request delegates are used to build the request pipeline. The request delegates handle each HTTP request.

Now as this states it allows the components to handle the requests and responses. The middle ware is executed in the order it is added to the application middleware collection.

app.UseStaticFiles(); adds the middlware to handle static files (images, css, scripts etc).

Now say you wish to add your own handling in the pipeline you can create a middleware class as a sample below.

public class GenericMiddleware
{
    public GenericMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    readonly RequestDelegate _next;

    public async Task Invoke(HttpContext context, IHostingEnvironment hostingEnviroment)
    {
        //do something

        await _next.Invoke(context);
    }
}

There are a few interesting points here. First off the constructor takes a RequestDelegate which is essentially (but not exactly) the next middleware object that will be invoked.

Next we implement our own Invoke method. This method should take the HttpContext as a paramater and will also allow for additional dependencies to be injected from the IoC container (in my example the IHostingEnvironment instance).

This method then executes the code it needs to execute and then calls await _next.Invoke(context); which executes the RequestDelegate to call the next middleware class.

Now to add this to the application middle ware you can simply call

app.UseMiddleware<GenericMiddleware>(); in your Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) method in the startup.cs file.

Or create a simple extension method as.

public static class GenericMiddlewareExtensions
{
    public static IApplicationBuilder UseGenericMiddleware(this IApplicationBuilder app)
    {
        app.UseMiddleware<GenericMiddleware>();
        return app;
    }
}

Which is then called app.UseGenericMiddleware();

Now how and why you implement your own middleware is up to you. However as stated it is up to the middleware to call the next RequestDelegate if it doesnt then it stops the request.

Here is an example in one of my projects that checks to see if the database is installed. If it isnt redirects the request back to the installation page.

public class InstallationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public InstallationMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<InstallationMiddleware>();
    }

    public async Task Invoke(HttpContext context)
    {
        _logger.LogInformation("Handling request: " + context.Request.Path);
        if (context != null && !DatabaseHelper.IsDatabaseInstalled())
        {
            if (!context.Request.Path.ToString().ToLowerInvariant().StartsWith("/installation"))
            {
                context.Response.Redirect("/installation");
                return;
            }
        }

        await _next.Invoke(context);
        _logger.LogInformation("Finished handling request.");
    }
}

As you can see if !DatabaseHelper.IsDatabaseInstalled() we redirect the response but dont invoke the _next RequestDelegate.

Again the documentation speaks for itself.