asp.net core 系列 15 中间件
一.概述
中间件(也叫中间件组件)是一种装配到应用管道以处理请求和响应的软件。 每个组件:(1)选择是否将请求传递到管道中的下一个组件;(2)可以在管道中的下一个组件之前和之后执行工作。
请求委托用于生成请求管道。 请求委托会处理每个 HTTP 请求。使用以下方法配置请求委托:Run, Map, Use扩展方法。可以将单个请求委托作为匿名方法(称为内联中间件in-line middleware) 或者可以在可重用类中定义。这些可重用的类和内联匿名方法是中间件,也称为中间件组件。请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。
(1) Run
//将终端中间件委托添加到应用程序的请求管道中。
public static class RunExtensions
{
public static void Run(this IApplicationBuilder app, RequestDelegate handler);
}
(2) Map
// 根据给定请求路径的匹配对请求管道进行分支。
public static class MapExtensions
{
public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);
}
(3) Use
// 提供配置应用程序请求的机制
public interface IApplicationBuilder
{
//....
// 将中间件委托添加到应用程序的请求管道中。
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
}
1.1 使用 IApplicationBuilder 创建中间件管道
在Startup. Configure方法中,使用IApplicationBuilder来创建中间件管理。每一个use开头的扩展方法将一个中间件添加到IApplicationBuilder请求管道中。使用Use扩展方法来配置请求委托。每个use的中间件类似如下声明:
public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app )
public static IApplicationBuilder Use[Middleware] (this IApplicationBuilder app , Action<T>)
ASP.NET Core 请求管道包含一系列请求委托,依次调用。 下图演示了这一概念。 沿黑色箭头执行。
在Startup. Configure代码中,一系列use请求委托中间件如下所示:
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
委托可以决定不将请求传递给下一个委托(中间件),这就是对请求管道进行短路。通常需要短路,因为这样可以避免不必要的工作。
下面示例 是一个最简单的 ASP.NET core 应用程序,用run方法配置请求委托,设置单个委托处理处理所有请求。此案例不包括实际的请求管道。相反,调用单个匿名函数以响应每个 HTTP 请求。并用委托终止了管道。
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
下面示例用Use方法将多个请求委托链接在一起,next
参数表示管道中的下一个委托。 可通过不调用 next 参数使管道短路。
app.Use(async (context, next) =>
{
//调用下一个委托(app.run)
await next.Invoke();
}); app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
1.2 中间件顺序
向 Startup.Configure
方法添加中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此排序对于安全性、性能和功能至关重要。以下 Startup.Configure
方法将为常见应用方案添加中间件组件:
(1) 异常/错误处理
(2) HTTP 严格传输安全协议
(3) HTTPS 重定向
(4) 静态文件服务器
(5) Cookie 策略实施
(6) 身份验证
(7) 会话
(8) MVC
public void Configure(IApplicationBuilder app)
{
if (env.IsDevelopment())
{
// When the app runs in the Development environment:
// Use the Developer Exception Page to report app runtime errors.
// Use the Database Error Page to report database runtime errors.
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
// When the app doesn't run in the Development environment:
// Enable the Exception Handler Middleware to catch exceptions
// thrown in the following middlewares.
// Use the HTTP Strict Transport Security Protocol (HSTS)
// Middleware.
app.UseExceptionHandler("/Error");
app.UseHsts();
} // Use HTTPS Redirection Middleware to redirect HTTP requests to HTTPS.
app.UseHttpsRedirection(); // Return static files and end the pipeline.
app.UseStaticFiles(); // Use Cookie Policy Middleware to conform to EU General Data
// Protection Regulation (GDPR) regulations.
app.UseCookiePolicy(); // Authenticate before the user accesses secure resources.
app.UseAuthentication(); // If the app uses session state, call Session Middleware after Cookie
// Policy Middleware and before MVC Middleware.
app.UseSession(); // Add MVC to the request pipeline.
app.UseMvc();
}
(1) UseExceptionHandler 是添加到管道的第一个中间件组件。 该异常处理程序中间件可捕获稍后调用中发生的任何异常。
(2) UseStaticFiles 静态文件中间件,应该在管道的早期调用。这样它就可以处理请求和短路,而不需要遍历其余组件。静态文件中间件不提供授权检查。 它提供的任何文件,包括wwwroot下的文件,都是公开可访问的。
(3) UseAuthentication 身份验证中间件。未经身份验证的请求不会短路,但只有在特定的Razor页面或MVC控制器操作之后,才会发生授权(和拒绝)。
1.3 Use、Run 和 Map
配置 HTTP 管道可以使用Use、Run 和 Map,但各方法针对构建的中间件作用不同:
(1) Use[Middleware]中间件负责调用管道中的下一个中间件,也可使管道短路(即不调用 next
请求委托)。
(2) Run[Middleware]是一种约定,一些中间件组件可能会公开在管道末端运行的Run[Middleware]方法。
(3) Map扩展用作约定来创建管道分支, Map*创建请求管道分支是基于给定请求路径的匹配项。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Map("/Map1",HandleMapTest1);
app.Map("/Map2", HandleMapTest2);
//其它请求地址
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
});
} private static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
} private static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
Map 还支持嵌套,下面的示例中,请求访问/level1/level2a 和 /level1/level2b时进行不同逻辑处理:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
1.4 MapWhen
MapWhen 基于url给定谓词的结果创建请求管道分支。 Func<HttpContext, bool> 类型的任何谓词均可用于将请求映射到管道的新分支。 在以下示例中,谓词用于检测查询字符串变量 branch 是否存在,如果存在使用新分支(HandleBranch)。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch); //非匹配branch其它请求地址
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
});
} private static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync("Map Test 1");
});
}
二. 编写中间件
上面演示在请求管道中使用use,map,run方法,来委托处理每个 HTTP 请求就是中间件。通常中间件会封装在类中,并且通过扩展方法公开。下面示例是如何编写一个中间件组件。处理逻辑是该中间件通过查询字符串设置当前请求的区域性。
/// <summary>
/// 自定义中间件实现类
/// </summary>
public class RequestCultureMiddleware
{
//using Microsoft.AspNetCore.Http
private readonly RequestDelegate _next;
/// <summary>
/// 程序启动时调用
/// </summary>
/// <param name="next"></param>
public RequestCultureMiddleware(RequestDelegate next)
{
this._next = next;
}
/// <summary>
///每个页面请求时自动调用,方法按约定命名,必需是Invoke或InvokeAsync
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext context)
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
//using System.Globalization;
var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture; }
// Call the next delegate/middleware in the pipeline
await _next(context);
}
} /// <summary>
/// 通过扩展方法公开中间件
/// </summary>
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder)
{
//在管道中添加一个use的中间件
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
public void Configure(IApplicationBuilder app)
{
//调用中间件
app.UseRequestCulture(); app.Run(async (context) =>
{
await ResponseAsync(context);
}); } private async Task ResponseAsync(HttpContext context)
{
context.Response.ContentType = "text/html; charset=utf-8";
await context.Response.WriteAsync(
//打印当前显示的语言
$"Hello { CultureInfo.CurrentCulture.DisplayName }"
);
}
2.1 请求依赖项
由于中间件是在应用启动时构造的(实例),而不是在每个请求时的,因此在每个请求过程中,中间件构造函数使用的作用域生命周期服务,不会在每个请求期间与其他依赖注入类型共享。如果必须在中间件和其他类型之间共享一个范围服务,请将这些服务添加到 Invoke
方法的签名。 Invoke
方法可接受由 DI 填充的参数:
public class CustomMiddleware
{
private readonly RequestDelegate _next; public CustomMiddleware(RequestDelegate next)
{
_next = next;
} // IMyScopedService is injected into Invoke
public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
{
svc.MyProperty = ;
await _next(httpContext);
}
}
参考文献:
官方文档:ASP.NET Core 中间件
asp.net core 系列 15 中间件的更多相关文章
- ASP.NET Core系列:中间件
1. 概述 ASP.NET Core中的中间件是嵌入到应用管道中用于处理请求和响应的一段代码. 2. 使用 IApplicationBuilder 创建中间件管道 2.1 匿名函数 使用Run, Ma ...
- asp.net core 系列之中间件进阶篇-编写自定义中间件(middleware)
中间件是被用到管道(pipeline)上来处理请求(request)和响应的(response). asp.net core 本身提供了一些内置的中间件,但是有一些场景,你可能会需要写一些自定义的中间 ...
- asp.net core 系列之中间件基础篇(middleware)
中间件是一种插入到管道上进行处理请求和响应的软件:每个中间件组件具有下面的功能: 选择是否把请求传递到管道上的下一个组件 可以在下一个组件的之前和之后做处理工作 请求委托(request delega ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 【asp.net core 系列】15 自定义Identity
0. 前言 在之前的文章中简单介绍了一下asp.net core中的Identity,这篇文章将继续针对Identity进行进一步的展开. 1. 给Identity添加额外的信息 在<[asp. ...
- 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)
黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...
- Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)
Ajax跨域问题及解决方案 目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...
- asp.net core 系列 18 web服务器实现
一. ASP.NET Core Module 在介绍ASP.NET Core Web实现之前,先来了解下ASP.NET Core Module.该模块是插入 IIS 管道的本机 IIS 模块(本机是指 ...
随机推荐
- 20175305张天钰Java结对编程四则运算(二)
Java结对编程四则运算(二) 一.题目描述及要求 Git提交粒度不要太粗,建议一个文件/一个类/一个函数/一个功能/一个bug修复都进行提交,不能一天提交一次,更不能一周一次,参考Commit Me ...
- JDK解压版制作
今天上 甲骨文 的官网,想下载一个 解压版的 jdk 1.8 结果发现: 没有解压版,只有exe版本.于是就搜索制作方法. 具体就是,双击exe版本,在最后关头要安装的时候, 重点来了! 跟他皮一下 ...
- event、fly.js、购物车特效
先总结下区别: #鼠标相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条. event.clientX.event.clientY #鼠标相对于document文档区域的x ...
- linux系统,关于Python多版本共存
http://www.cnblogs.com/Yiutto/p/5962906.html 给个地址直接看八~
- Linux之环境搭建(一)
四大系统比较 Mac OS是苹果机专用系统,是基于Unix内核的图形化操作系统,因此Unix相当于父亲,Linux和Mac OS是对兄弟. CentOS是从Redhat源代码编译重新发布版.CentO ...
- Python数据模型及Pythonic编程
Python作为一种多范式语言,它的很多语言特性都能从其他语言上找到参照,但是Python依然形成了一套自己的“Python 风格”(Pythonic).这种Pythonic风格完全体现在 Pytho ...
- centos7 安装python3.7.11 笔记
安装python依赖包yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-deve ...
- 初次部署django+gunicorn+nginx
初次部署django+gunicorn+nginx 博客详细地址 https://www.cnblogs.com/nanrou/p/7026802.html 写在前面,这只是我所遇到的情况,如果有 ...
- Android SQLite数据库升级,怎么做(事物更改)
SQLiteOpenHelper // 如果数据库文件不存在,只有onCreate()被调用(该方法在创建数据库时被调用一次) public abstract void onCreate(SQLite ...
- HTML入门14
HTML表单 这块部分开始强调表单也是用的比较多的部分,好好补漏啊啊啊啊 表单用来做交互,处理所有方面结构到样式,到自定义小部件. form元素,严禁嵌套表单,表单嵌套会使得表单得行为不可预知,引入f ...