在說二級域名綁定以前,先說一下.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
- <span style="font-size:14px;">public class SubDomainRouter : RouteBase
- {
- private readonly IRouter _target;
- private readonly string _subDomain;
- public SubDomainRouter(
- IRouter target,
- string subDomain,
- string routeTemplate,
- RouteValueDictionary defaults,
- RouteValueDictionary constrains,
- IInlineConstraintResolver inlineConstraintResolver)
- : base(routeTemplate,
- subDomain,
- inlineConstraintResolver,
- defaults,
- constrains,
- new RouteValueDictionary(null))
- {
- if (target == null)
- {
- throw new ArgumentNullException(nameof(target));
- }
- if (subDomain == null)
- {
- throw new ArgumentNullException(nameof(subDomain));
- }
- _subDomain = subDomain;
- _target = target;
- }
- public override Task RouteAsync(RouteContext context)
- {
- string domain = context.HttpContext.Request.Host.Host;
-
- if (string.IsNullOrEmpty(domain) || string.Compare(_subDomain, domain) != 0)
- {
- return Task.CompletedTask;
- }
-
-
-
- return base.RouteAsync(context);
-
- }
-
- protected override Task OnRouteMatched(RouteContext context)
- {
- context.RouteData.Routers.Add(_target);
- return _target.RouteAsync(context);
- }
-
- protected override VirtualPathData OnVirtualPathGenerated(VirtualPathContext context)
- {
- return _target.GetVirtualPath(context);
- }
- }</span>
如何把域名綁定到指定的控制器上,代碼以下:服務器
- <span style="font-size:14px;">public static class RouteBuilderExtensions
- {
- public static IRouteBuilder MapDomainRoute(
- this IRouteBuilder routeBuilder,string domain,string area,string controller)
- {
- if(string.IsNullOrEmpty(area)||string.IsNullOrEmpty(controller))
- {
- throw new ArgumentNullException("area or controller can not be null");
- }
- var inlineConstraintResolver = routeBuilder
- .ServiceProvider
- .GetRequiredService<IInlineConstraintResolver>();
-
- string template = "";
-
- RouteValueDictionary defaults = new RouteValueDictionary();
- RouteValueDictionary constrains = new RouteValueDictionary();
- constrains.Add("area", area);
- defaults.Add("area", area);
- constrains.Add("controller", controller);
- defaults.Add("controller", string.IsNullOrEmpty(controller) ? "home" : controller);
- defaults.Add("action", "index");
-
- template += "{action}/{id?}";
- routeBuilder.Routes.Add(new SubDomainRouter(routeBuilder.DefaultHandler, domain, template, defaults, constrains, inlineConstraintResolver));
-
-
- return routeBuilder;
- }
- }</span>
使用方法:架構
- <span style="font-size:14px;">routes.MapDomainRoute("xxx.domain.com","areaname","controllername");</span>
以上代碼爲原博客中的代碼,使用起來也很方便,只須要傳值域名,區域名,控制器名,就能夠實現咱們想要的結果。下面我對以上代碼稍做了修改,經過配置文件配置域名和控制器的綁定。新建一個關於域名、區域、控制器名的Model: mvc
- <span style="font-size:14px;">
- public class SubDomain
- {
-
-
-
-
- public string Domain { get; set; }
-
-
-
-
-
- public string AreaName { get; set; }
-
-
-
-
-
- public string Controller { get; set; }
- }</span>
另外在MapDomainRoute擴展方法中,去掉了對區域的判斷, 這樣也能夠配置非區域的控制器了,代碼以下:app
- <span style="font-size:14px;">public static IRouteBuilder MapDomainRoute(
- this IRouteBuilder routeBuilder, string domain, string area, string controller)
- {
- try
- {
- <span style="background-color:rgb(255,204,0);">if (string.IsNullOrEmpty(domain))
- {
- throw new ArgumentNullException("domain can not be null");
- }
-
- if (string.IsNullOrEmpty(controller))
- {
- throw new ArgumentNullException("controller can not be null");
- }</span>
- var inlineConstraintResolver = routeBuilder
- .ServiceProvider
- .GetRequiredService<IInlineConstraintResolver>();
-
- string template = "";
-
- RouteValueDictionary defaults = new RouteValueDictionary();
- RouteValueDictionary constrains = new RouteValueDictionary();
- constrains.Add("area", area);
- defaults.Add("area", area);
- constrains.Add("controller", controller);
- defaults.Add("controller", string.IsNullOrEmpty(controller) ? "Home" : controller);
- defaults.Add("action", "index");
-
- template += "{action}/{id?}";
- routeBuilder.Routes.Add(new SubDomainRouter(routeBuilder.DefaultHandler, domain, template, defaults, constrains, inlineConstraintResolver));
- return routeBuilder;
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }</span>
同時也添加了一個對該方法的重載:asp.net
- <span style="font-size:14px;">public static void MapDomainRoute(this IRouteBuilder routeBuilder, List<SubDomain> listDomains)
- {
- try
- {
- if (listDomains == null || listDomains.Count <= 0)
- {
- return;
- }
-
- foreach (SubDomain domain in listDomains)
- {
- MapDomainRoute(routeBuilder, domain.Domain, domain.AreaName, domain.Controller);
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }</span>
將域名路由信息配置到appsetting.json文件中,例如:dom
固然在.net core中能夠直接從IConfiguration對象中能夠直接獲取到配置文件下的信息,但我也沒找到能夠直接序列化我爲要的標準的Json格式,就使用了直接讀取文件的方式,藉助Json.Net,又反序列化成我要的實體信息List<SubDomain>,代碼以下:ide
- <span style="font-size:14px;">
- var jsonDomain = JObject.Parse(File.ReadAllText("appsettings.json"))["SubDomains"];
- if (jsonDomain != null)
- {
- var infos = JsonConvert.DeserializeObject<List<SubDomain>>(jsonDomain.ToString());
- routes.MapDomainRoute(infos);
- }</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
掃描二維碼關注個人公衆號,共同窗習,共同進步!