.Net Core 二級域名綁定到指定的控制器

在說二級域名綁定以前,先說一下.net core中的區域,關於區域這一起在好久以前的博客中,已經提過,詳見《03-dotnet core建立區域[Areas]及後臺搭建》,在這篇博客中,建立區域的時候,都是手動建立的,手動建立區域Areas文件夾,手動添加M-V-C等文件目錄,因爲在最先的VS2017版本中,直接右鍵添加區域的選項竟然沒了,然而在後來的VS版本更新中,這一功能又恢復了,也不知微軟是出於什麼考慮。區域的功能,就不用多說了,至於如何建立如何使用,也很少說,這些都是在MVC4的功能了。今天主要說一下關於二級域名如何綁定到指定的控制器。html

    二級域名也無需多說了吧,好比咱們進入百度,咱們直接輸入www.baidu.com或者輸入baidu.com(重定向到www.baidu.com),會直接進入百度的首頁,而若是咱們輸入的是,news.baidu.com,則直接進入百度新聞,咱們稱news.baidu.com爲二級域名,那輸入不一樣的二級域名會進入不一樣的主頁面,那這是如何實現的呢。關於二級域名綁定其實使用一些代理服務器如nginx等,均可以實現域名綁定,這些咱們都不討論,這裏咱們只討論在.net core 項目中如何配置。nginx

    這裏藉助於一篇博客,園子中早已經有人對路由做了擴展,使其能夠自定義域名綁定控制器,原文地址:《asp.net core mvc中如何把二級域名綁定到特定的控制器上》 。下面附上代碼:二級域名邏輯判斷,基於RouteBase擴展json

[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:    mvc

[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擴展方法中,去掉了對區域的判斷, 這樣也能夠配置非區域的控制器了,代碼以下:app

[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>  

同時也添加了一個對該方法的重載:asp.net

[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文件中,例如:dom

固然在.net core中能夠直接從IConfiguration對象中能夠直接獲取到配置文件下的信息,但我也沒找到能夠直接序列化我爲要的標準的Json格式,就使用了直接讀取文件的方式,藉助Json.Net,又反序列化成我要的實體信息List<SubDomain>,代碼以下:ide

[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

掃描二維碼關注個人公衆號,共同窗習,共同進步!

相關文章
相關標籤/搜索