public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
一、app.UseRouting()
该中间件会检查应用中定义的终结点列表,然后通过匹配 URL 和 HTTP 方法来选择最佳的终结点简单说,该中间件的作用是根据一定规则来选择出终结点1、源码分析
public static IApplicationBuilder UseRouting(this IApplicationBuilder builder)
{
//判空
ArgumentNullException.ThrowIfNull(builder);
//判断RoutingMarkerService 确保是否添加了所有服务
VerifyRoutingServicesAreRegistered(builder);
//VerifyRoutingServicesAreRegistered 内部
//// 必须先执行了 AddRouting
//if (app.ApplicationServices.GetService(typeof(RoutingMarkerService)) == null)
//{
// throw new InvalidOperationException(Resources.FormatUnableToFindServices(
// nameof(IServiceCollection),
// nameof(RoutingServiceCollectionExtensions.AddRouting),
// "ConfigureServices(...)"));
//}
//初始化数据源
if (builder.Properties.TryGetValue(GlobalEndpointRouteBuilderKey, out var obj))
{
endpointRouteBuilder = (IEndpointRouteBuilder)obj!;
//知道在设置全局路由构建器时是否调用UseRouting()
builder.Properties[EndpointRouteBuilder] = endpointRouteBuilder;
}
else
{
endpointRouteBuilder = new DefaultEndpointRouteBuilder(builder);
//EndpointRouteBuilder为字符串常量 __EndpointRouteBuilder
//// builder.Properties["__EndpointRouteBuilder"] = endpointRouteBuilder;
//// 将 endpointRouteBuilder 放入共享字典中
builder.Properties[EndpointRouteBuilder] = endpointRouteBuilder;
}
//DefaultEndpointRouteBuilder构造类内部
//public DefaultEndpointRouteBuilder(IApplicationBuilder applicationBuilder)
//{
// ApplicationBuilder = applicationBuilder ?? throw new ArgumentNullException(nameof(applicationBuilder));
// DataSources = new List<EndpointDataSource>();
//}
// Add UseRouting function to properties so that middleware that can't reference UseRouting directly can call UseRouting via this property
// This is part of the global endpoint route builder concept
builder.Properties.TryAdd(UseRoutingKey, (object)UseRouting);
//操作完成后对此实例引用
return builder.UseMiddleware<EndpointRoutingMiddleware>(endpointRouteBuilder);
}
2、EndpointRoutingMiddleware 中间件
EndpointRoutingMiddleware
中间件先是创建matcher
,然后调用matcher.MatchAsync(httpContext)
去寻找Endpoint,最后通过httpContext.GetEndpoint()
验证了是否已经匹配到了正确的Endpoint
并交个下个中间件继续执行!核心就是将
_endpointDataSource
传递给_matcherFactory
,创建matcher
,然后进行匹配matcher.MatchAsync(httpContext)
。ASP.NET Core默认使用的 matcher 类型是DfaMatcher
,DFA(Deterministic Finite Automaton)是一种被称为“确定有限状态自动机”的算法,可以从候选终结点列表中查找到匹配度最高的那个终结点。二、app.UseAuthorization()
暂时不看三、app.UseEndpoints()
可以向该中间件的终结点列表中添加终结点,并配置这些终结点要执行的委托,该中间件会负责运行由EndpointRoutingMiddleware
中间件选择的终结点所关联的委托。简单说,该中间件用来执行所选择的终结点委托1、源码分析
public static IApplicationBuilder UseEndpoints(this IApplicationBuilder builder, Action<IEndpointRouteBuilder> configure)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(configure);
//所以在调用UseEndpoint之前 必须要先调用UseRouting,否则报错。
//验证路由服务是否注册了
VerifyRoutingServicesAreRegistered(builder);
//验证端点路由中间件是否已注册
// 将 endpointRouteBuilder 从共享字典中取出来,如果没有,则说明之前没有调用 UseRouting
VerifyEndpointRoutingMiddlewareIsRegistered(builder, out var endpointRouteBuilder);
//VerifyEndpointRoutingMiddlewareIsRegistered方法内部
//private static void VerifyEndpointRoutingMiddlewareIsRegistered(IApplicationBuilder app, out DefaultEndpointRouteBuilder endpointRouteBuilder)
//{
// if (!app.Properties.TryGetValue(EndpointRouteBuilder, out var obj))
// {
// var message =
// $"{nameof(EndpointRoutingMiddleware)} matches endpoints setup by {nameof(EndpointMiddleware)} and so must be added to the request " +
// $"execution pipeline before {nameof(EndpointMiddleware)}. " +
// $"Please add {nameof(EndpointRoutingMiddleware)} by calling '{nameof(IApplicationBuilder)}.{nameof(UseRouting)}' inside the call " +
// $"to 'Configure(...)' in the application startup code.";
// throw new InvalidOperationException(message);
// }
// //如果此处转换失败,程序会出错。
// endpointRouteBuilder = (DefaultEndpointRouteBuilder)obj;
//
// //此检查处理在两者之间调用Map或其他分叉管道的情况
// if (!object.ReferenceEquals(app, endpointRouteBuilder.ApplicationBuilder))
// {
// var message =
// $"The {nameof(EndpointRoutingMiddleware)} and {nameof(EndpointMiddleware)} must be added to the same {nameof(IApplicationBuilder)} instance. " +
// $"To use Endpoint Routing with 'Map(...)', make sure to call '{nameof(IApplicationBuilder)}.{nameof(UseRouting)}' before " +
// $"'{nameof(IApplicationBuilder)}.{nameof(UseEndpoints)}' for each branch of the middleware pipeline.";
// throw new InvalidOperationException(message);
// }
//}
configure(endpointRouteBuilder);
//我们正在将数据源注册到一个全局集合中
//可用于发现端点或生成URL。
//每个中间件都有自己的数据源集合,所有这些数据源也
//被添加到全局集合中。
//这里就是填充RouteOptions的EndpointDataSources了。
//UseRouting 和 UseEndpoints 必须添加到同一个 IApplicationBuilder 实例上
var routeOptions = builder.ApplicationServices.GetRequiredService<IOptions<RouteOptions>>();
foreach (var dataSource in endpointRouteBuilder.DataSources)
{
if (!routeOptions.Value.EndpointDataSources.Contains(dataSource))
{
routeOptions.Value.EndpointDataSources.Add(dataSource);
}
}
//操作完成后对此实例引用
return builder.UseMiddleware<EndpointMiddleware>();
}
2、EndpointMiddleware中间件
不理解 就是执行由EndpointRoutingMiddleware中间件附加到当前HttpContext上下文中的终结点。EndpointRoutingMiddleware中间件针对终结点的执行涉及如下所示的RouteOptions类型标识的配置选项。1、EndpointMiddleware 初始化的时候注入了routeOptions。2、当路由匹配到了终结点时,EndpointMiddleware
则是该路由的终端中间件四、三者关系
UseRouing
中间件主要是路由匹配,找到匹配的终结者路由Endpoint
;UseEndpoints
中间件主要针对UseRouting
中间件匹配到的路由进行 委托方法的执行等操作。 UseAuthorization
中间件主要针对 UseRouting
中间件中匹配到的路由进行拦截 做授权验证操作等,通过则执行下一个中间件UseEndpoints()
,具体的关系可以看下面的流程图:在调用UseRouting
之前,你可以注册一些用于修改路由操作的数据,比如UseRewriter
、UseHttpMethodOverride
、UsePathBase
等。在调用UseRouting
和UseEndpoints
之间,可以注册一些用于提前处理路由结果的中间件,如UseAuthentication
、UseAuthorization
、UseCors
等。五、UseEndpoints 配置
MapControllers 添加了对属性路由的控制器支持
MapAreaControllerRoute 将控制器的传统路由添加区域
MapControllerRoute 添加控制器的常规路由
endpoints.MapAreaControllerRoute(
name: "ApiArea", "API",
pattern: "API/{controller=Test}/{action=Index}/{id?}"
);
endpoints.MapAreaControllerRoute(
name: "UapiArea", "UAPI",
pattern: "UAPI/{controller=Test}/{action=Index}/{id?}"
);
endpoints.MapAreaControllerRoute(
name: "WebArea", "Web",
pattern: "Web/{controller=Test}/{action=Index}/{id?}"
);
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
区域的需要在控制器上加 [Area("API")]
[Route("/API/[controller]/[action]")]
ASP.NET Core路由中间件[4]: EndpointRoutingMiddleware和EndpointMiddleware - Artech - 博客园 (cnblogs.com)
https://www.cnblogs.com/artech/p/endpoint-middleware-04.html
重新整理 .net core 实践篇——— UseEndpoints中间件[四十八] - 敖毛毛 - 博客园 (cnblogs.com)
https://www.cnblogs.com/aoximin/p/15649807.html
理解ASP.NET Core - 路由(Routing) - xiaoxiaotank - 博客园 (cnblogs.com)https://www.cnblogs.com/xiaoxiaotank/p/15468491.html
ASP.NET Core框架揭秘[博文汇总-持续更新] - Artech - 博客园 (cnblogs.com)https://www.cnblogs.com/artech/p/inside-asp-net-core-3.html 标签:CORE,nameof,UseEndpoints,builder,endpointRouteBuilder,中间件,UseRouting,路由 From: https://www.cnblogs.com/buzheng11/p/17661680.html