Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 503
JKL Avatar asked Aug 17 '16 04:08

JKL


People also ask

How many types of middleware are there in .NET Core?

net core applications, then you need to configure it within the Configure() method of the Startup class by calling the Use* methods on the IApplicationBuilder object. As you can see in the above image, the Configure() method sets up the request processing pipeline with just three middleware components are as follows.

How can we configure the pipeline for middleware in ASP.NET Core?

Configuring the Request Pipeline To start using any Middleware, we need to add it to the Request pipeline. This is done in the Configure method of the startup class. The Configure method gets the instance of IApplicationBuilder, using which we can register our Middleware.

Why do we need custom middleware in .NET Core?

Each middleware component in ASP.NET Core Application can perform some operations before and after calling the next component using the next method. A middleware component in ASP.NET Core Application can also decide not to call the next middleware component which is called short-circuiting the request pipeline.


2 Answers

I've made a simple prototype implementation for a project I'm working on that has nothing to do with ASP.NET Core so people that don't understand its architecture or its implementation might have easier time grasp the concept.

The design pattern at play here is called the Chain of Responsibility pattern.

So the first thing we need is to define the delegate for the application:

public delegate void InputDelegate(char key);

Then we need something to consume it so here is a very simple event/main loop implementation:

internal class TerminalHost
{
    private InputDelegate _inputDelegate;

    public TerminalHost()
    {
        // Initializes the first delegate to be invoked in the chain.
        _inputDelegate = Console.Write;
    }

    internal void Start()
    {
        CancellationTokenSource tokenSource = new CancellationTokenSource();

        while (!tokenSource.IsCancellationRequested) {
            ConsoleKeyInfo keyInfo = Console.ReadKey();

            _inputDelegate(keyInfo.KeyChar);
        }
    }

    /// <summary>
    /// Adds the middleware to the invocation chain. 
    /// </summary>
    /// <param name="middleware"> The middleware to be invoked. </param>
    /// <remarks>
    /// The middleware function takes an instance of delegate that was previously invoked as an input and returns the currently invoked delegate instance as an output.
    /// </remarks>
    internal void Use(Func<InputDelegate, InputDelegate> middleware)
    {
        // Keeps a reference to the currently invoked delegate instance.
        _inputDelegate = middleware(_inputDelegate);
    }
}

And finally, we need to create an instance of the TerminalHost class and call the Use method so this would be something like this:

class Program
{
    static void Main(string[] args)
    {
        TerminalHost terminal = new TerminalHost();

        terminal.Use(next => ch => {
            Console.WriteLine(ch);

            next(ch);
        });

        terminal.Start();
    }
}

I hope it make sense and that it's helpful to someone out there! :)

like image 70
Eyal Alon Avatar answered Nov 10 '22 00:11

Eyal Alon


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.

like image 20
Nico Avatar answered Nov 10 '22 01:11

Nico