循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)
系列目录
本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi
一、概述
本篇介绍如何使用中间件(Middleware)。
二、初步演练
先写几个中间件
public class DemoAMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public DemoAMiddleware(RequestDelegate next, ILogger<DemoAMiddleware> logger)
{
_next = next;
_logger = logger;
} public async Task Invoke(HttpContext context)
{
_logger.LogInformation("(1) DemoAMiddleware.Invoke front");
await _next(context);
_logger.LogInformation("[1] DemoAMiddleware:Invoke back");
}
} public class DemoBMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public DemoBMiddleware(RequestDelegate next, ILogger<DemoBMiddleware> logger)
{
_next = next;
_logger = logger;
} public async Task Invoke(HttpContext context)
{ _logger.LogInformation("(2) DemoBMiddleware.Invoke part1");
await _next(context);
_logger.LogInformation("[2] DemoBMiddleware:Invoke part2");
}
} public class RequestRecordMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public RequestRecordMiddleware(RequestDelegate next, ILogger<RequestRecordMiddleware> logger)
{
_next = next;
_logger = logger;
} public async Task Invoke(HttpContext context)
{
_logger.LogInformation("(3) RequestRecordMiddleware.Invoke"); String URL = context.Request.Path.ToString();
_logger.LogInformation($"URL : {URL}"); await _next(context); _logger.LogInformation("[3] RequestRecordMiddleware:Invoke next");
_logger.LogInformation($"StatusCode : {context.Response.StatusCode}");
}
}
以上中间件前两个没有做什么正经工作,就打印一些日志信息,第三个干了一点工作,它打印了用户输入的url,同时打印了返回给客户端的状态码。
要使中间件工作,需要启用中间件。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseUnifyException(); app.UseMiddleware<DemoAMiddleware>();
app.UseMiddleware<DemoBMiddleware>();
app.UseMiddleware<RequestRecordMiddleware>(); app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
通过扩展方法,我们对中间件的启用代码进行改造:
public static class RequestRecordMiddlewareExtensions
{
public static IApplicationBuilder UseRequestRecord(this IApplicationBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException("builder is null");
} return builder.UseMiddleware<RequestRecordMiddleware>();
}
}
此时启用代码由:app.UseMiddleware<RequestRecordMiddleware>();
可以修改为: app.UseRequestRecord();
实现效果没有变化。可见下面代码都是中间件的使用。
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
我的理解,中间件类似车间流水线上的工人,操作的零件就是HttpContext,每个人负责两道工序,我把它们定义为“前道工序”和“后道工序”,通过代码 _next(context); 把两道工序隔离开,处理的顺序需要特别注意,按照中间件注册的顺序依次处理“前道工序”,处理完成后,再按相反的顺序处理“后道工序”,如果某个中间件没有调用_next(context),那么就不会调用后续的中间件,所以中间件启用的顺序是需要特别考虑的。
以上代码中三个中间件输出到控制台的信息顺序如下:
(1)
(2)
(3)
【3】
【2】
【1】
个人认为,“前道工序”应重点处理Request,“后道工序”应重点处理Response。
三、做一个类似MVC的中间件
我们做一个中间件,让其返回一些内容给客户端:
public class MyMvcMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public MyMvcMiddleware(RequestDelegate next, ILogger<DemoAMiddleware> logger)
{
_next = next;
_logger = logger;
} public async Task Invoke(HttpContext context)
{ var str = "hello,world!";
await context.Response.WriteAsync(str);
}
}
这个中间件只是返回固定的字符串,我们还可以调用某个Controller的提供的方法。
public class MyMvcMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger; public MyMvcMiddleware(RequestDelegate next, ILogger<DemoAMiddleware> logger)
{
_next = next;
_logger = logger;
} public async Task Invoke(HttpContext context)
{
var obj = context.RequestServices.GetRequiredService<ArticleController>().GetArticleList();
var str = JsonConvert.SerializeObject(obj);
await context.Response.WriteAsync(str);
}
}
ArticleController的定义如下:
public class ArticleController : Controller
{
private readonly SalesContext _context;
private readonly ILogger _logger;
private readonly IMemoryCache _cache; public ArticleController(SalesContext context, ILogger<ArticleController> logger, IMemoryCache memoryCache)
{
_context = context;
_logger = logger;
_cache = memoryCache;
} [HttpGet]
public ResultObject GetArticleList()
{
_logger.LogInformation("==GetArticleList=="); List<Article> articles = _context.Articles
.AsNoTracking()
.ToList(); return new ResultObject
{
result = articles
};
}
}
要在中间件中通过依赖使用该Controller,需要将其注册到DI容器:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ArticleController>();
}
以上中间件实现了一个文章信息查询的功能,如果在此中间件内先判断路径,再根据不同的路径调用不同的Contorller提供的服务,就可以形成一个简单的MVC中间件了。
四、中间件的用途
中间件的使用体现了AOP(面向切片)的编程思想,在不修改现有代码的情况下,通过增加一些中间件实现一些特定逻辑,可以做的事情很多,比如:
URL重写
缓存处理
异常处理
用户认证
五、中间件的注册顺序
前文提到中间件的注册顺序是比较重要的,建议的顺序如下:
1. 异常/错误处理
2. 静态文件服务器
3. 身份验证
4. MVC
循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)的更多相关文章
- 循序渐进学.Net Core Web Api开发系列【0】:序言与目录
一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...
- 循序渐进学.Net Core Web Api开发系列【16】:应用安全续-加密与解密
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 应用安全除 ...
- 循序渐进学.Net Core Web Api开发系列【15】:应用安全
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍W ...
- 循序渐进学.Net Core Web Api开发系列【14】:异常处理
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...
- 循序渐进学.Net Core Web Api开发系列【12】:缓存
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...
- 循序渐进学.Net Core Web Api开发系列【11】:依赖注入
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...
- 循序渐进学.Net Core Web Api开发系列【10】:使用日志
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇介 ...
- 循序渐进学.Net Core Web Api开发系列【9】:常用的数据库操作
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇描述一 ...
- 循序渐进学.Net Core Web Api开发系列【8】:访问数据库(基本功能)
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇讨论如 ...
随机推荐
- Python远程连接模块-Telnet
Python远程连接模块-Telnet 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 虽然现在主流的python版本还是2.7,相信2020年python程序员都会偏向Python ...
- MySQL的备份和恢复-基于LVM快照的备份(lvm-snapshot)
MySQL的备份和恢复-基于LVM快照的备份(lvm-snapshot) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是快照卷 如上图所示,原卷和快照卷可以不一样大,因为 ...
- bzoj千题计划204:bzoj2813: 奇妙的Fibonacci
http://www.lydsy.com/JudgeOnline/problem.php?id=2813 若j能整除i,则f[j]能整除f[i] 题目就变成了求约数个数和.约数的平方和 http:// ...
- mysql统计一个字段的多种状态
假如我有下面的表:ID Item status updatetime author1 a 1 2014-01-0 ...
- 一组数字,从1到n,从中减少了3个数,顺序打乱,放在n-3的数组里,找出丢失数字
曾经看到有这样一个JS题:有一组数字,从1到n,从中减少了3个数,顺序也被打乱,放在一个n-3的数组里请找出丢失的数字,最好能有程序,最好算法比较快假设n=10000 下面我也来贴一个算法. func ...
- [转] 解决RegexKitLite编译报错
本文永久地址为http://www.cnblogs.com/ChenYilong/p/3984254.html ,转载请注明出处. 在编译RegexKitLite的时候,报错如下: Undefined ...
- 训练赛第二场E题 Cottage Village
题目大意:在一条X轴上,有若干个正方形,并且保证这些正方形的中心都在X轴上,然后输入n个正方形的中心的X坐标,和正方形的边长,现在要再插入一个正方形,要求是,新插入的正方形至少要有一条边与原来的正方形 ...
- HDU 3787 A+B 模拟题
解题报告:就是输入两个用逗号隔开的数字,求出这两个数字的和,并且用正常的方式输出来.直接写一个函数将一个包含逗号的数字转换成十进制的数返回就行了.这里推荐一个函数atoi(),参数是char*型的,然 ...
- 日期控件-my97DatePicker用法
网上资料,用法,只能选最近30天等等:http://jingyan.baidu.com/article/e6c8503c7244bae54f1a18c7.html
- [转]CMake cache
CMakeCache.txt 可以将其想象成一个配置文件(在Unix环境下,我们可以认为它等价于传递给configure的参数). CMakeLists.txt 中通过 set(... CACHE . ...