一、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