Introduction to ASP. NET Core middleware for Distributed Session and core Middleware

Source: Internet
Author: User
Tags hosting

Introduction to ASP. NET Core middleware for Distributed Session and core Middleware

1.1. Middleware principles

1.1.1. What is middleware?

Middleware is a piece of code used to process requests and responses. Generally, multiple middleware links to form a pipeline, and each middleware determines whether to call the next middleware.

1.1.2. Middleware Execution Process

An example is provided to demonstrate the execution process of the middleware (three middleware: logging, permission verification, and routing): when a request enters the application, the middleware that executes the log record is executed, it records the request attributes and calls the next middleware permission verification in the chain. If the permission verification passes, the control is passed to the next middleware. If the permission verification fails, it sets the 401 HTTP code and returns the response, the response is passed to the Log Middleware for return.

1.1.3. Middleware Configuration

Middleware configuration is mainly usedRun,MapAndUseMethod Configuration; simple middleware can be done directly using the anonymous method, as shown in the following code:

app.Run(async (context,next) =>    {      await context.Response.WriteAsync("environment " + env);      await next();    });

To reuse middleware, You Need To encapsulate it into a class for calling.

1.2. Dependency injection Middleware

In actual projects, middleware often needs to call methods of other objects. Therefore, you need to create dependencies between objects. Because ASP. NET Core has a built-in dependency injection system, you can create more elegant code when writing programs.

First, you must register the class in the IOC container.StartupClassConfigureServicesMethod,ConfigureServicesThe method will beConfigureMethod. So that all dependencies are ready when middleware is used.

There is a Greeter class:

public class Greeter : IGreeter{  public string Greet()  {    return "Hello from Greeter!";  }}public interface IGreeter{  string Greet();}

Step 1:ConfigureServicesMethod

public void ConfigureServices(IServiceCollection services){  services.AddTransient<IGreeter, Greeter>();}

Here I use AddTransient for registration. This method creates a new instance of this class in each request. You can select other methods: AddSingleton, AddScoped, or simple Add (all used before the scenes ). The entire DI system is described in the official document.

After registering dependencies, you can use them.IApplicationBuilderThe instance can beConfigureThere isRequestServicesAttribute is used to obtainGreeterInstance. Because you have registered thisIGreeterTherefore, the middleware and the specificGreeterImplementation.

app.Use(async (ctx, next) =>  {    IGreeter greeter = ctx.RequestServices.GetService<IGreeter>();    await ctx.Response.WriteAsync(greeter.Greet());    await next();  });

IfGreeterA class has a parameterized constructor, and its dependency must also be registered in it.ConfigureServices.

Middleware can easily solve dependencies. You can add other parameters to the middleware constructor:

public class MyMiddleware{  private readonly RequestDelegate _next;  private readonly IGreeter _greeter;  public MyMiddleware(RequestDelegate next, IGreeter greeter)  {    _next = next;    greeter = greeter;  }  public async Task Invoke(HttpContext context)  {    await context.Response.WriteAsync(_greeter.Greet());    await _next(context);  }}

Alternatively, you can add this dependency to the Invoke method:

public async Task Invoke(HttpContext context, IGreeter greeter){  await context.Response.WriteAsync(greeter.Greet());  await _next(context);}

If the DI system knows the types of these parameters, they will be automatically parsed when the class is instantiated. Very easy!

1.3. Cookies and session Middleware

1.3.1. Session

HTTP is a stateless protocol. The Web server regards every request as an independent request. The user values in the previous request are not saved.

Session status is a feature provided by ASP. NET Core. It stores user data when users access the network server through applications. The Session state is obtained through a browser request and the Session data is saved to the cache.

ASP. NET Core maintains the Session status through cookies containing the Session ID. Each request carries this Session ID.

InMicrosoft.AspNetCore.SessionThe middleware provided in the package is used to manage the Session status. To enable Session middleware, you must perform the following operations in the Startup class:

  1. Enable the memory cache using any service that implements the IDistributedCache interface,
  2. Set AddSession callback. Because AddSession is implemented in the Microsoft. AspNetCore. Session package, you must add the Microsoft. AspNetCore. Session package to Nuget.
  3. UseSession callback

The sample code is as follows:

Using Microsoft. aspNetCore. builder; using Microsoft. extensions. dependencyInjection; using System; public class Startup {public void ConfigureServices (IServiceCollection services) {services. addMvc (); // Add a memory cache service. addDistributedMemoryCache (); services. addSession (options => {// set the 10-second Session expiration time to test options. idleTimeout = TimeSpan. fromSeconds (10); options. cookie. httpOnly = true ;});} public void Configure (IApplicationBuilder app) {app. useSession (); app. useMvcWithDefaultRoute ();}}

In the above CodeIdleTimeoutThis attribute is used to determine how long the user has not discarded the Session. This attribute has nothing to do with Cookie timeout. Each request through Session middleware resets the timeout time.

1.3.2. Save the Session to Redis.

The distributed Session method is officially provided by Redis and SQL Server. However, the efficiency of SQL Server is far less efficient than that of Redis in obtaining values using key/value. Therefore, I use Redis as an example to implement distributed sessions.

Prepare Redis

Currently, Redis does not support windows, so we have prepared a linux operating system when installing Redis. The system here is ubuntu 16.04. For download and installation methods, refer to the official example.

After the installation is successful, start the Redis service. If the following information is displayed, it indicates that Redis is successfully started:

Related Configuration

First, use the Nuget installation package Microsoft. Extensions. Caching. Redis. After the installation is successful, you can see it in the app. csproj file.

Add app. UseSession () in the Configure method, and then add the Redis service to ConfigureServices.

Public void ConfigureServices (IServiceCollection services) {services. addDistributedRedisCache (options => {options. configuration = "127.0.0.1"; // multiple redis servers: {RedisIP }:{ Redis port}, {RedisIP }:{ Redis port} options. instanceName = "sampleInstance" ;}); services. addMvc (); services. addSession ();}

In the above code, I only use one Redis server for testing. In actual projects, multiple Redis servers are required. The configuration method is as follows:Options. Configuration = "address 1: Port, address 2: Port ";,The default port 6379 is used instead of the port.

Complete code

Startup. cs

using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Caching.Redis;using Microsoft.Extensions.Caching.Distributed;namespace app{    public class Startup{        public Startup(IConfiguration configuration)        {            Configuration = configuration;        }    public IConfiguration Configuration { get; }    public void ConfigureServices(IServiceCollection services){                 services.AddDistributedRedisCache(options =>{                options.Configuration = "127.0.0.1";                options.InstanceName = "sampleInstance";            });            services.AddMvc();            services.AddSession();        }    public void Configure(IApplicationBuilder app, IHostingEnvironment env){            if (env.IsDevelopment())      {                app.UseDeveloperExceptionPage();            }            else            {                app.UseExceptionHandler("/Home/Error");            }      app.UseSession();      app.UseStaticFiles();      app.UseMvc(routes =>{                routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");            });        }    }}

HomeControler. cs

public class HomeController : Controller  {      public IActionResult Index()      {          HttpContext.Session.Set("apptest",Encoding.UTF8.GetBytes("apptestvalue"));    return View();      }  public IActionResult ShowRedis()      {          byte[] temp;    if(HttpContext.Session.TryGetValue("apptest",out temp))    {              ViewData["Redis"]=Encoding.UTF8.GetString(temp);          }          return View();      }}

The Index page only sets the value for the Session: "apptestvalue". The ShowRedis page displays the Session value.

ShowRedis. cshtml

Redis Session Value:ViewData["Redis"]

Demo result

Now on the run page, go directly to the ShowRedis page. The Session value is blank.

After you click SetSessionValue, return to the ShowRedis page again, and the Session value is displayed.

The apptestvalue indicates that the Session value has been stored in Redis. How can we prove that the apptestvalue value is obtained from Redis? Next we will prove it to you.

1.3.3. Distributed sessions

The Session has been saved to Redis, but it is unclear whether the value is actually saved to Redis or in the project memory; so here we can share sessions in two non-applications (or two different machines), that is, implementing distributed sessions. distributed represents different applications on different machines, but there is often one of the following embarrassing situations, even if each HTTP request carries the same cookie value.

The cause of this problem is the ASP.. NET Core applications have different keys, so there is no way to obtain the Session data saved by the previous application. To solve this problem ,. the NET Core team provides Microsoft. aspNetCore. dataProtection. azureStorage and Microsoft. aspNetCore. dataProtection. the Redis package saves the key to Azure or Redis. Save the key to Redis.

Use the PersistKeysToRedis overload method provided by the Microsoft. AspNetCore. DataProtection. Redis package to save the key to Redis. So here we need to add AddDataProtection () in the ConfigureServices Method ()

var redis = ConnectionMultiplexer.Connect("127.0.0.1:6379");  services.AddDataProtection()    .SetApplicationName("session_application_name")    .PersistKeysToRedis(redis, "DataProtection-Keys");

The following shows how to implement distributed sessions.

Procedure

Create two projects at the same time: app1 and app2

AddMicrosoft.AspNetCore.DataProtection.RedisAndStackExchange. Redis. StrongName package

On the same machine, ASP. NET Core uses port 5000 by default when it is started. Because app1 is occupied, set the Start port of app2 to 5001.

Complete code

App1 Project

Startup. cs

using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Caching.Redis;using Microsoft.Extensions.Caching.Distributed;namespace app1{    public class Startup{        public Startup(IConfiguration configuration)        {            Configuration = configuration;        }    public IConfiguration Configuration { get; }    public void ConfigureServices(IServiceCollection services){      var redis = ConnectionMultiplexer.Connect("127.0.0.1:6379");      services.AddDataProtection()        .SetApplicationName("session_application_name")        .PersistKeysToRedis(redis, "DataProtection-Keys");           services.AddDistributedRedisCache(options =>{                options.Configuration = "127.0.0.1";                options.InstanceName = "sampleInstance";            });            services.AddMvc();            services.AddSession();        }    public void Configure(IApplicationBuilder app, IHostingEnvironment env){            if (env.IsDevelopment())      {                app.UseDeveloperExceptionPage();            }            else            {                app.UseExceptionHandler("/Home/Error");            }      app.UseSession();      app.UseStaticFiles();      app.UseMvc(routes =>{                routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");            });        }    }}

HomeControler. cs

public class HomeController : Controller  {      public IActionResult Index()      {          HttpContext.Session.Set("app1test",Encoding.UTF8.GetBytes("app1testvalue"));    return View();      }  public IActionResult ShowRedis()      {          byte[] temp;    if(HttpContext.Session.TryGetValue("app1test",out temp))    {              ViewData["Redis"]=Encoding.UTF8.GetString(temp);          }          return View();      }}

ShowRedis. cshtml

Redis Session Value:ViewData["Redis"]

App2 Project

Startup. cs
The configuration is the same as that of app1.

HomeControler. cs

public class HomeController : Controller  {      public IActionResult Index()      {          byte[] temp;    if(HttpContext.Session.TryGetValue("app1test",out temp))    {              ViewData["Redis"]=Encoding.UTF8.GetString(temp);          }     return View();      }}

Index. cshtml

ViewData["Redis"]

Running Effect

App1 Project

The ShowRedis page is displayed for the first time. The Session value is blank.

Click SetSessionValue and return to the ShowRedis page:

App2 project, directly access: http: // localhost: 5001 in the browser

The above is an example of using Redis to implement distributed Session.

1.4. Summary

This section describes the running principle and configuration process of middleware, and the configuration of object dependencies between middleware and Session configuration issues that are frequently used in time projects. The actual code shows how to use middleware to implement distributed sessions.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.