一、ASP.NET Core 中间件简介
中间件是一种装配到应用程序管道以处理请求和响应的软件。 每个组件可进行以下操作:
选择是否将请求传递到管道中的下一个组件。
可在调用管道中的下一个组件前后执行工作。
中间件在请求过程中执行顺序示意图:
二、ASP.NET Core中间件开发和使用
1、新建项目、项目基础功能配置
1.1 新建asp.net core web 应用程序
1.2 将 Properties/launchSettings.json 文件中两处端口号 都改为5000,一个是vs(iis)运行时的端口号,一个是直接命令行(dotnet run)运行时的端口号
1.3 Huanent.Logging.File包用来记录日志
安装nuget包:Huanent.Logging.File(依赖项:Microsoft.Extensions.Logging.Console) 用来记录文本日志和console日志
(源码在:https://github.com/huanent/Huanent.Logging)
在根目录加配置文件:appsettings.json,内容:
{ "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } }, "File": { "LogLevel": { "Default": "Information" } } } }
修改 Startup.cs,方法Configure 加参数 ILoggerFactory loggerFactory,然后在方法内部加代码:
loggerFactory.AddConsole(minLevel: LogLevel.Information);//启用控制台输出log中间件
修改Program.cs,在 .Build() 前面,加一行代码:
.ConfigureLogging(builder => builder.AddFile())//启用文本日志
2、开发中间件示例
2.1 记录请求者IP中间件开发(带输入参数)
中间件类:RequestIPMiddleware.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; namespace MiddleWareTest { /// <summary> /// 模拟记录请求者IP、请求Path中间件 /// </summary> public class RequestIPMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly RequestIPOptions _option; public RequestIPMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<RequestIPOptions> options) { _next = next; _logger = loggerFactory.CreateLogger<RequestIPMiddleware>(); if (options != null) { _option = options.Value; } } public async Task Invoke(HttpContext context) { if (context.Request.Path.HasValue && context.Request.Path.Value != "/favicon.ico") { var ip = context.Connection.RemoteIpAddress.ToString(); if (_option == null || _option.LogType == 0 || (ip != "127.0.0.1" && ip != "::1")) _logger.LogInformation("User IP:{0},path:{1}", ip, context.Request.Path); } await _next.Invoke(context); } } public static class RequestIpExtensions { public static IApplicationBuilder UseRequestIP(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException(nameof(app)); } return app.UseMiddleware<RequestIPMiddleware>(); } public static IApplicationBuilder UseRequestIP(this IApplicationBuilder app, RequestIPOptions options) { if (app == null) { throw new ArgumentNullException(nameof(app)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } return app.UseMiddleware<RequestIPMiddleware>(Options.Create(options)); } } }
参数类:RequestIPOptions.cs
using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace MiddleWareTest { public class RequestIPOptions : IOptions<RequestIPOptions> { /// <summary> /// 记录类型,0:默认全部,1:非local请求 /// </summary> public int LogType { get; set; } RequestIPOptions IOptions<RequestIPOptions>.Value { get { return this; } } } }
2.2 权限验证中间件开发
MyAuthMiddleware.cs
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; namespace MiddleWareTest { /// <summary> /// 模拟权限验证中间件 /// </summary> public class MyAuthMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public MyAuthMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) { _next = next; _logger = loggerFactory.CreateLogger<MyAuthMiddleware>(); } public async Task Invoke(HttpContext context) { if (context.Request.Path.HasValue) { if(context.Request.Path.Value == "/favicon.ico") { return; } //这里模拟用户无权限访问 if (context.Request.Path.Value == "/Forbidden") { _logger.LogInformation("禁止访问"); context.Response.StatusCode = (int)HttpStatusCode.Forbidden;//可以直接返回状态码 //context.Response.Redirect("/403.html");//直接跳转到提示页 return; } //这里模拟用户请求报错 else if (context.Request.Path.Value == "/InternalServerError") { _logger.LogInformation("服务器错误"); context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;//可以直接返回状态码 //context.Response.Redirect("/500.html");//直接跳转到提示页 return; } else { _logger.LogInformation("权限正常"); } //验证通过,走正常流程(不阻碍正常流程) } await _next.Invoke(context); } } public static class MyAuthExtensions { public static IApplicationBuilder UseMyAuth(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException(nameof(app)); &nb