在ASP.Net Core中,若是直接在Middleware中获取RouteData返回的是空值,这是由于RouterMiddleware还没执行。但有些状况下须要获取RouteData,这要怎么作呢?app
public async Task Invoke(HttpContext context) { var routeData = context.GetRouteData(); null }
TemplateMatcher是获取路由值的关键类。使用它能够将URL按路由Template解析成RouteData。因此咱们能够使用它来获取RouteData。async
下面是一个简单的辅助类供参考,若是直接使用可能会有一些性能问题,由于解析路由模板(TemplateParser.Parse(routeTemplate))须要时间,因此应当在实际使用的时候优化它:ide
public class RouteMatcher { public RouteValueDictionary Match(string routeTemplate, string requestPath) { var template = TemplateParser.Parse(routeTemplate); var matcher = new TemplateMatcher(template, GetDefaults(template)); var values = matcher.Match(requestPath); return values; } private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate) { var result = new RouteValueDictionary(); foreach (var parameter in parsedTemplate.Parameters) { if (parameter.DefaultValue != null) { result.Add(parameter.Name, parameter.DefaultValue); } } return result; } }
有了这些,就能够在Middleware里面来解析RouteData了。性能
在解析路由时,应当按照路由的注册的前后顺序来解析,而且在成功解析时退出,这样能够保证和程序匹配时的路由是一致的。而且你应当考虑是否加上使用路由的约束(RouteConstraint)来判断当前的路由模板是否匹配。优化
在纸壳CMS里面,当开启多语言时,用户访问了一个不带语言的地址,应当要自动跳转加上用户对应的语言。因此须要使用Middleware来作跳转,同时须要将用户访问的Url解析成RoteData来判断是否须要跳转。spa
namespace ZKEACMS.MultiLanguage { public class LocalizeRedirectMiddleware { class LocalizeRoute { public Easy.Mvc.Route.RouteDescriptor Descriptor { get; set; } public TemplateMatcher TemplateMatcher { get; set; } } private readonly RequestDelegate _next; private List<LocalizeRoute> _routes; public LocalizeRedirectMiddleware(RequestDelegate next) { _next = next; } public Task Invoke(HttpContext context) { if (IsGetMethod(context) && IsSupportContentType(context)) { IApplicationContextAccessor applicationContextAccessor = context.RequestServices.GetService<IApplicationContextAccessor>(); var setting = applicationContextAccessor.Current.CultureSetting; if (setting.UseUrlCode(context.User.Identity.IsAuthenticated)) { var acitveCultures = context.RequestServices.GetService<ICultureService>().GetActiveCulture(); if (_routes == null) { _routes = context.RequestServices.GetService<IRouteProvider>().GetRoutes().OrderByDescending(m => m.Priority).Select(m => { var template = TemplateParser.Parse(m.Template); return new LocalizeRoute { Descriptor = m, TemplateMatcher = new TemplateMatcher(template, GetDefaults(template)) }; }).ToList(); } foreach (var item in _routes) { var routeData = new RouteValueDictionary(); if (item.TemplateMatcher.TryMatch(context.Request.Path.Value, routeData)) { if(item.Descriptor is LocalizeRouteDescriptor) { object cultureCode; if (routeData.TryGetValue("culture", out cultureCode)) { if (!acitveCultures.Any(m => cultureCode.Equals(m.UrlCode))) { context.Response.Redirect($"/{context.GetUserCulture().UrlCode}{context.Request.GetAbsoluteUrl()}"); return Task.CompletedTask; } } else { context.Response.Redirect($"/{context.GetUserCulture().UrlCode}{context.Request.GetAbsoluteUrl()}"); return Task.CompletedTask; } } break; } } } } return _next(context); } private bool IsGetMethod(HttpContext context) { return string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase); } private bool IsSupportContentType(HttpContext context) { return true; } private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate) { var result = new RouteValueDictionary(); foreach (var parameter in parsedTemplate.Parameters) { if (parameter.DefaultValue != null) { result.Add(parameter.Name, parameter.DefaultValue); } } return result; } } }
对于对于多语言的跳转,微软其实有提供了一个Localization middleware,只不过在纸壳CMS的多语言场景里有点不太适用,因此从新写了这个LocalizeRedirectMiddleware。若是你也有正在考虑多语言的解决方案,能够查看下面的连接:code
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.1ip