专栏首页ZKEASOFT.Net Core在Middleware中解析RouteData

.Net Core在Middleware中解析RouteData

在ASP.Net Core中,如果直接在Middleware中获取RouteData返回的是空值,这是因为RouterMiddleware还没执行。但有些情况下需要获取RouteData,这要怎么做呢?

public async Task Invoke(HttpContext context)
{
    var routeData = context.GetRouteData()
}

TemplateMatcher

TemplateMatcher是获取路由值的关键类。使用它可以将URL按路由Template解析成RouteData。所以我们可以使用它来获取RouteData。

下面是一个简单的辅助类供参考,如果直接使用可能会有一些性能问题,因为解析路由模板(TemplateParser.Parse(routeTemplate))需要时间,所以应当在实际使用的时候优化它:

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来判断是否需要跳转。

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。如果你也有正在考虑多语言的解决方案,可以查看下面的链接:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.1

原文链接:http://www.zkea.net/codesnippet/detail/middleware-routedata.html

原文链接:http://www.zkea.net/codesnippet/detail/middleware-routedata.html

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 会HTML/CSS就可以轻松创建网站

    网站其本质就是HTML + CSS 外加一些JavaScript构成的。所以基本上只要你会一些前端,就可以开始花样搭网站了。

    Mr. Wei
  • 纸壳CMS的插件加载机制

    纸壳CMS是基于插件化设计的,可以通过扩展插件来实现不同的功能。如何通过插件来扩展,可以参考这篇文章:

    Mr. Wei
  • 在Linux安装ASP.Net Core的运行时(Runtime)

    在部署的时候,如果您不想在您的Linux服务器上安装.Net Core SDK,您可以只安装Runtime,接下来我们看看该如何安装运行时Runtime。

    Mr. Wei
  • ASP.NET Core ActionFilter引发的一个EF异常

    最近在使用ASP.NET Core的时候出现了一个奇怪的问题。在一个Controller上使用了一个ActionFilter之后经常出现EF报错。

    kklldog
  • .Net Core 权限验证与授权(AuthorizeFilter、ActionFilterAttribute)

    在.Net Core 中使用AuthorizeFilter或者ActionFilterAttribute来实现登录权限验证和授权

    小世界的野孩子
  • Unity NavMesh 动态烘焙绘制与随机取点

    最初的Unity导航系统很不完善,只能静态烘焙场景图的可行走区域,而且必须在本地保存场景的NavMesh数据,难以运行时动态计算;这使得鲜有开发者愿意再尝试Un...

    汐夜koshio
  • JS 变量作用域导致的一个坑

    路过君
  • EntityFramework 外键值映射

    如果在 EF OnModelCreating 中配置了实体外键映射,也就是 SQL Server 中的 ForeignKey,那么我们在添加实体的时候,主实体的...

    逸鹏
  • 你必须了解的反射——反射来实现实体验证

    开发工作中,都会需要针对传入的参数进行验证,特别是针对实体进行验证,确保传入的参数格式正确。这里做了一个非常简单的组件进行验证。抛砖引玉,让大家深入思考下反射的...

    itmifen
  • 你必须了解的反射——反射来实现实体验证

    日常开发,都是通过API进行前后端的系统对接,对API参数的验证是一个使用率非常高的功能,如果能非常简便的的进行参数验证,能降低代码量,提升工作效率。

    itmifen

扫码关注云+社区

领取腾讯云代金券