zoukankan      html  css  js  c++  java
  • .Net Core 二级域名绑定到指定的控制器

    在说二级域名绑定之前,先说一下.net core中的区域,关于区域这一块儿在很久之前的博客中,已经提过,详见《03-dotnet core创建区域[Areas]及后台搭建》,在这篇博客中,创建区域的时候,都是手动创建的,手动创建区域Areas文件夹,手动添加M-V-C等文件目录,由于在最早的VS2017版本中,直接右键添加区域的选项居然没了,然而在后来的VS版本更新中,这一功能又恢复了,也不知微软是出于什么考虑。区域的功能,就不用多说了,至于如何创建如何使用,也不多说,这些都是在MVC4的功能了。今天主要说一下关于二级域名如何绑定到指定的控制器。

        二级域名也无需多说了吧,比如我们进入百度,我们直接输入www.baidu.com或者输入baidu.com(重定向到www.baidu.com),会直接进入百度的首页,而如果我们输入的是,news.baidu.com,则直接进入百度新闻,我们称news.baidu.com为二级域名,那输入不同的二级域名会进入不同的主页面,那这是如何实现的呢。关于二级域名绑定其实使用一些代理服务器如nginx等,都可以实现域名绑定,这些我们都不讨论,这里我们只讨论在.net core 项目中如何配置。

        这里借助于一篇博客,园子中早已经有人对路由作了扩展,使其可以自定义域名绑定控制器,原文地址:《asp.net core mvc中如何把二级域名绑定到特定的控制器上》 。下面附上代码:二级域名逻辑判断,基于RouteBase扩展

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">public class SubDomainRouter : RouteBase  
    2.   {  
    3.       private readonly IRouter _target;  
    4.       private readonly string _subDomain;  
    5.       public SubDomainRouter(  
    6.          IRouter target,  
    7.          string subDomain,//当前路由规则绑定的二级域名  
    8.          string routeTemplate,  
    9.          RouteValueDictionary defaults,  
    10.          RouteValueDictionary constrains,  
    11.          IInlineConstraintResolver inlineConstraintResolver)  
    12.          : base(routeTemplate,  
    13.                 subDomain,  
    14.                 inlineConstraintResolver,  
    15.                 defaults,  
    16.                 constrains,  
    17.                 new RouteValueDictionary(null))  
    18.       {  
    19.           if (target == null)  
    20.           {  
    21.               throw new ArgumentNullException(nameof(target));  
    22.           }  
    23.           if (subDomain == null)  
    24.           {  
    25.               throw new ArgumentNullException(nameof(subDomain));  
    26.           }  
    27.           _subDomain = subDomain;  
    28.           _target = target;  
    29.       }  
    30.       public override Task RouteAsync(RouteContext context)  
    31.       {  
    32.           string domain = context.HttpContext.Request.Host.Host;//获取当前请求域名,然后跟_subDomain比较,如果不想等,直接忽略  
    33.             
    34.           if (string.IsNullOrEmpty(domain) || string.Compare(_subDomain, domain) != 0)  
    35.           {  
    36.               return Task.CompletedTask;  
    37.           }  
    38.         
    39.      //如果域名匹配,再去验证访问路径是否匹配  
    40.    
    41.           return base.RouteAsync(context);  
    42.              
    43.       }  
    44.    
    45.       protected override Task OnRouteMatched(RouteContext context)  
    46.       {  
    47.           context.RouteData.Routers.Add(_target);  
    48.           return _target.RouteAsync(context);  
    49.       }  
    50.    
    51.       protected override VirtualPathData OnVirtualPathGenerated(VirtualPathContext context)  
    52.       {  
    53.           return _target.GetVirtualPath(context);  
    54.       }  
    55.   }</span>  

    如何把域名绑定到指定的控制器上,代码如下:

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">public static class RouteBuilderExtensions  
    2.     {  
    3.         public static IRouteBuilder MapDomainRoute(  
    4.             this IRouteBuilder routeBuilder,string domain,string area,string controller)  
    5.         {  
    6.             if(string.IsNullOrEmpty(area)||string.IsNullOrEmpty(controller))  
    7.             {  
    8.                 throw new ArgumentNullException("area or controller can not be null");  
    9.             }  
    10.             var inlineConstraintResolver = routeBuilder  
    11.                 .ServiceProvider  
    12.                 .GetRequiredService<IInlineConstraintResolver>();  
    13.    
    14.                 string template = "";  
    15.    
    16.                     RouteValueDictionary defaults = new RouteValueDictionary();  
    17.                     RouteValueDictionary constrains = new RouteValueDictionary();  
    18.                     constrains.Add("area", area);  
    19.                     defaults.Add("area", area);  
    20.                     constrains.Add("controller", controller);  
    21.                     defaults.Add("controller", string.IsNullOrEmpty(controller) ? "home" : controller);  
    22.                     defaults.Add("action", "index");  
    23.                        
    24.                     template += "{action}/{id?}";//路径规则中不再包含控制器信息,但是上面通过constrains限定了查找时所要求的控制器名称  
    25.                     routeBuilder.Routes.Add(new SubDomainRouter(routeBuilder.DefaultHandler, domain, template, defaults, constrains, inlineConstraintResolver));  
    26.    
    27.                
    28.             return routeBuilder;  
    29.         }  
    30. }</span>  

    使用方法:

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">routes.MapDomainRoute("xxx.domain.com","areaname","controllername");</span>  

    以上代码为原博客中的代码,使用起来也很方便,只需要传值域名,区域名,控制器名,就可以实现我们想要的结果。下面我对以上代码稍作了修改,通过配置文件配置域名和控制器的绑定。新建一个关于域名、区域、控制器名的Model:    

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">/// 域名信息实体类  
    2. /// <summary>  
    3. /// 域名信息实体类  
    4. /// </summary>  
    5. public class SubDomain  
    6. {  
    7.     /// 域名  
    8.     /// <summary>  
    9.     /// 域名  
    10.     /// </summary>  
    11.     public string Domain { get; set; }  
    12.   
    13.     /// 区域名  
    14.     /// <summary>  
    15.     /// 区域名  
    16.     /// </summary>  
    17.     public string AreaName { get; set; }  
    18.   
    19.     /// 控制器名  
    20.     /// <summary>  
    21.     /// 控制器名  
    22.     /// </summary>  
    23.     public string Controller { get; set; }  
    24. }</span>  

    另外在MapDomainRoute扩展方法中,去掉了对区域的判断, 这样也可以配置非区域的控制器了,代码如下:

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">public static IRouteBuilder MapDomainRoute(  
    2.            this IRouteBuilder routeBuilder, string domain, string area, string controller)  
    3.         {  
    4.             try  
    5.             {  
    6.                 <span style="background-color:rgb(255,204,0);">if (string.IsNullOrEmpty(domain))  
    7.                 {  
    8.                     throw new ArgumentNullException("domain can not be null");  
    9.                 }  
    10.                 //string.IsNullOrEmpty(area) || //去掉该判断,不限制仅限区域使用配置  
    11.                 if (string.IsNullOrEmpty(controller))  
    12.                 {  
    13.                     throw new ArgumentNullException("controller can not be null");  
    14.                 }</span>  
    15.                 var inlineConstraintResolver = routeBuilder  
    16.                     .ServiceProvider  
    17.                     .GetRequiredService<IInlineConstraintResolver>();  
    18.   
    19.                 string template = "";  
    20.   
    21.                 RouteValueDictionary defaults = new RouteValueDictionary();  
    22.                 RouteValueDictionary constrains = new RouteValueDictionary();  
    23.                 constrains.Add("area", area);  
    24.                 defaults.Add("area", area);  
    25.                 constrains.Add("controller", controller);  
    26.                 defaults.Add("controller", string.IsNullOrEmpty(controller) ? "Home" : controller);  
    27.                 defaults.Add("action", "index");  
    28.   
    29.                 template += "{action}/{id?}";//路径规则中不再包含控制器信息,但是上面通过constrains限定了查找时所要求的控制器名称  
    30.                 routeBuilder.Routes.Add(new SubDomainRouter(routeBuilder.DefaultHandler, domain, template, defaults, constrains, inlineConstraintResolver));  
    31.                 return routeBuilder;  
    32.             }  
    33.             catch (Exception ex)  
    34.             {  
    35.                 throw ex;  
    36.             }  
    37.         }</span>  

    同时也添加了一个对该方法的重载:

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">public static void MapDomainRoute(this IRouteBuilder routeBuilder, List<SubDomain> listDomains)  
    2.         {  
    3.             try  
    4.             {  
    5.                 if (listDomains == null || listDomains.Count <= 0)  
    6.                 {  
    7.                     return;  
    8.                 }  
    9.   
    10.                 foreach (SubDomain domain in listDomains)  
    11.                 {  
    12.                     MapDomainRoute(routeBuilder, domain.Domain, domain.AreaName, domain.Controller);  
    13.                 }  
    14.             }  
    15.             catch (Exception ex)  
    16.             {  
    17.                 throw ex;  
    18.             }  
    19.         }</span>  

    将域名路由信息配置到appsetting.json文件中,例如:

    当然在.net core中可以直接从IConfiguration对象中可以直接获取到配置文件下的信息,但我也没找到可以直接序列化我为要的标准的Json格式,就使用了直接读取文件的方式,借助Json.Net,又反序列化成我要的实体信息List<SubDomain>,代码如下:

    [csharp] view plain copy
     
    1. <span style="font-size:14px;">//获取域名路由配置规则信息  
    2. var jsonDomain = JObject.Parse(File.ReadAllText("appsettings.json"))["SubDomains"];  
    3. if (jsonDomain != null)  
    4. {  
    5.       var infos = JsonConvert.DeserializeObject<List<SubDomain>>(jsonDomain.ToString());  
    6.       routes.MapDomainRoute(infos);  
    7. }</span>  

    这样也就可以直接通过配置文件去修改配置了,效果展示:

    https://www.allenchoi.net

    https://blog.allenchoi.net

    https://admin.allenchoi.net

    以上就实现了我们想要的结果。后面内容应该会涉及微服务内容了,我会结合微软的示例项目eShop,应用到自己的项目中。另外,微软官方出了一本电子书《.NET微服务:容器化.NET应用架构指南》,大家可以免费下载,下载地址:https://aka.ms/microservicesebook

    原文中涉及到的博客地址(尊重原创):http://www.cnblogs.com/dxp909/p/6994354.html

    扫描二维码关注我的公众号,共同学习,共同进步!

  • 相关阅读:
    2.5 进程控制之wait函数
    2.4 进程控制之僵尸进程和孤儿进程
    九、IIC驱动原理分析
    2.3 进程控制之exec函数族
    8.2 USB键盘驱动编写和测试
    1. tty终端接收数据原理
    第3章 MySQL常用增,删,改,查,用户授权,备份,等操作
    Linux命令总结--top命令
    Linux--LNMP
    Linux命令总结-ps pstree pgrep命令
  • 原文地址:https://www.cnblogs.com/Allen0910/p/8570765.html
Copyright © 2011-2022 走看看