zoukankan      html  css  js  c++  java
  • ASP.NET MVC动态二级域名及ASP.NET管道机制

    ASP.NET MVC动态二级域名及ASP.NET管道机制

    动态二级域名的实现:

    应用场景:目前产品要实现SaaS功能,因为工作需要实现二级域名:www.{CompanyUrl}.xxx.com

    假设产品主域名入口为:www.xxx.com

    当a公司租户登录时:www.a.xxx.com

    当b公司租户登录时: www.b.xxx.com

    首先想到的是对Url的重写:(网上有关于UrlRewrite的实现。在ASP.NET中这也是常用的手法。)

    Route简介:ASP.NET路由可以不用映射到网站特定文件的URL.由于该 URL 不必映射到文件,因此可以使用对用户操作进行描述因而更易于被用户理解的 URL。.NET Framework 3.5 SP1已经包含了ASP.NET Routing引擎。现在微软已经在ASP.NET WebForms 4.0中增加了对Routing引擎更好的支持,它使用表达式构造器进行双向Routing。

    MVC 应用程序中的典型 URL 模式——来自MSDN

    MVC 应用程序中用于路由的 URL 模式通常包括 {controller} 和 {action} 占位符。

    当收到请求时,会将其路由到 UrlRoutingModule 对象,然后路由到 MvcHandler HTTP 处理程序。 MvcHandler HTTP 处理程序通过向 URL 中的控制器值添加后缀“Controller”以确定将处理请求的控制器的类型名称,来确定要调用的控制器。URL 中的操作值确定要调用的操作方法。

    MVC项目中添加路由,Global.asax 文件默认的MVC 路由的代码。

    默认配置:

    View Code
    1         public static void RegisterRoutes(RouteCollection routes)
     2         {
     3             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     4 
     5             routes.MapRoute(
     6                 "Default", // Route name
     7                 "{controller}/{action}/{id}", // URL with parameters
     8                 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
     9             );
    10 
    11         }
    12         protected void Application_Start()
    13         {
    14             AreaRegistration.RegisterAllAreas();
    15 
    16             RegisterGlobalFilters(GlobalFilters.Filters);
    17             RegisterRoutes(RouteTable.Routes);
    18         }

    涉及类参考

    说明
    Route 表示 Web 窗体或 MVC 应用程序中的路由。
    RouteBase 用作表示 ASP.NET 路由的所有类的基类。
    RouteTable 存储应用程序的路由。
    RouteData 包含所请求路由的值。
    RequestContext 包含有关对应于路由的 HTTP 请求的信息。
    RouteValueDictionary 提供用于存储路由 ConstraintsDefaults 和 DataTokens 对象的方法。
    VirtualPathData 提供用于从路由信息生成 URL 的方法。

    因为目前采用的是ASP.NET MVC 3进而可以利用扩展Route的方式实现。

    首先定义DomainData、DomainRoute类

    代码如下:

    DomainRoute类:

    View Code
    1     public class DomainRoute : Route
      2     {
      3         private Regex domainRegex;
      4         private Regex pathRegex;
      5 
      6         public string Domain { get; set; }
      7 
      8         public DomainRoute(string domain, string url, RouteValueDictionary defaults)
      9             : base(url, defaults, new MvcRouteHandler())
     10         {
     11             Domain = domain;
     12         }
     13 
     14         public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
     15             : base(url, defaults, routeHandler)
     16         {
     17             Domain = domain;
     18         }
     19 
     20         public DomainRoute(string domain, string url, object defaults)
     21             : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
     22         {
     23             Domain = domain;
     24         }
     25 
     26         public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler)
     27             : base(url, new RouteValueDictionary(defaults), routeHandler)
     28         {
     29             Domain = domain;
     30         }
     31 
     32         public override RouteData GetRouteData(HttpContextBase httpContext)
     33         {
     34             // 构造 regex
     35             domainRegex = CreateRegex(Domain);
     36             pathRegex = CreateRegex(Url);
     37 
     38             // 请求信息
     39             string requestDomain = httpContext.Request.Headers["host"];
     40             if (!string.IsNullOrEmpty(requestDomain))
     41             {
     42                 if (requestDomain.IndexOf(":") > 0)
     43                 {
     44                     requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
     45                 }
     46             }
     47             else
     48             {
     49                 requestDomain = httpContext.Request.Url.Host;
     50             }
     51             string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
     52 
     53             // 匹配域名和路由
     54             Match domainMatch = domainRegex.Match(requestDomain);
     55             Match pathMatch = pathRegex.Match(requestPath);
     56 
     57             // 路由数据
     58             RouteData data = null;
     59             if (domainMatch.Success && pathMatch.Success)
     60             {
     61                 data = new RouteData(this, RouteHandler);
     62 
     63                 // 添加默认选项
     64                 if (Defaults != null)
     65                 {
     66                     foreach (KeyValuePair<string, object> item in Defaults)
     67                     {
     68                         data.Values[item.Key] = item.Value;
     69                     }
     70                 }
     71 
     72                 // 匹配域名路由
     73                 for (int i = 1; i < domainMatch.Groups.Count; i++)
     74                 {
     75                     Group group = domainMatch.Groups[i];
     76                     if (group.Success)
     77                     {
     78                         string key = domainRegex.GroupNameFromNumber(i);
     79 
     80                         if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
     81                         {
     82                             if (!string.IsNullOrEmpty(group.Value))
     83                             {
     84                                 data.Values[key] = group.Value;
     85                             }
     86                         }
     87                     }
     88                 }
     89 
     90                 // 匹配域名路径
     91                 for (int i = 1; i < pathMatch.Groups.Count; i++)
     92                 {
     93                     Group group = pathMatch.Groups[i];
     94                     if (group.Success)
     95                     {
     96                         string key = pathRegex.GroupNameFromNumber(i);
     97 
     98                         if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
     99                         {
    100                             if (!string.IsNullOrEmpty(group.Value))
    101                             {
    102                                 data.Values[key] = group.Value;
    103                             }
    104                         }
    105                     }
    106                 }
    107             }
    108 
    109             return data;
    110         }
    111 
    112         public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    113         {
    114             return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
    115         }
    116 
    117         public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
    118         {
    119             // 获得主机名
    120             string hostname = Domain;
    121             foreach (KeyValuePair<string, object> pair in values)
    122             {
    123                 hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
    124             }
    125 
    126             // Return 域名数据
    127             return new DomainData
    128             {
    129                 Protocol = "http",
    130                 HostName = hostname,
    131                 Fragment = ""
    132             };
    133         }
    134 
    135         private Regex CreateRegex(string source)
    136         {
    137             // 替换
    138             source = source.Replace("/", @"\/?");
    139             source = source.Replace(".", @"\.?");
    140             source = source.Replace("-", @"\-?");
    141             source = source.Replace("{", @"(?<");
    142             source = source.Replace("}", @">([a-zA-Z0-9_]*))");
    143 
    144             return new Regex("^" + source + "$");
    145         }
    146 
    147         private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
    148         {
    149             Regex tokenRegex = new Regex(@"({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?");
    150             Match tokenMatch = tokenRegex.Match(Domain);
    151             for (int i = 0; i < tokenMatch.Groups.Count; i++)
    152             {
    153                 Group group = tokenMatch.Groups[i];
    154                 if (group.Success)
    155                 {
    156                     string key = group.Value.Replace("{", "").Replace("}", "");
    157                     if (values.ContainsKey(key))
    158                         values.Remove(key);
    159                 }
    160             }
    161 
    162             return values;
    163         }
    164     }
    165     public class DomainData
    166     {
    167         public string Protocol { get; set; }
    168         public string HostName { get; set; }
    169         public string Fragment { get; set; }
    170     }

    DomainData 类:

    View Code
    1 public class DomainData
    2     {
    3         public string Protocol { get; set; }
    4         public string HostName { get; set; }
    5         public string Fragment { get; set; }
    6     }

    然后在Global中配置路由

       1:  routes.Add("DomainRoute", new DomainRoute( 
       2:  "www.{companyUrl}.wenthink.com",     // Domain with parameters 
       3:  "{controller}/{action}/{id}",    // URL with parameters 
       4:  new { companyUrl= "", controller = "Home", action = "Login", id = "" }  // Parameter defaults 
       5:  ));

    效果图:

    a 公司用户登录时:

    QQ截图20130410014512 QQ截图20130410014425

    b公司用户登录时:

    QQ截图20130410014602 QQ截图20130410014709

    当用户尝试错误时:可自定义提示页面

    QQ截图20130410014804

    基础支持:域名支持泛解析

    然后要做的是:配置DNS服务,也就是让你的域名支持泛解析 眨眼 (Windows Server 才会有,其他的Windows系统可以尝试修改Host文件,便于测试)

    Step By Step

    1 2
    3 4
    5 6
    7 8
    9 10
    反向查询区域11 创建反向区域12
    13 14
    绑定指针  
    15 16

    完成上面的操作,基本可以实现DNS的泛解析了.当然如果没有绑定域名的话,只能修改Host文件来进行操作;

    本机测试的情况下需要把Host文件中添加当前IP地址 所映射的域名,如本文中的wenthink.com

    备注:以上解决了域名访问的问题,但是会存在Session跨域访问的丢失的现象.本例中采用了CrossDomainCookie的方式解决.当然不是唯一的解决方案. 方法很简单,这里就不多说明了,需要的可以自己Google一下 :-)

    参考资料:http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx

                http://www.cnblogs.com/cyq1162/archive/2010/10/15/1851773.html

    以上为个人学习摘要,如有错误,欢迎指正!!

    下期:ASP.NET管道机制及IIS的工作原理浅析.

    上个草图先 :-P

    我们每个人都是梦想家,当离开家了,就只剩梦想了。。。 道路,或许坎坷,但你终会到达!!!
     
  • 相关阅读:
    如何把git上的小程序项目跑起来
    异常好用的六种vue组件通信方式
    2021.8.10面试总结
    高频面试题总结
    21年8.6面试总结
    2021.8.4上海微创软件(主react)电话面试
    promis封装各种请求
    各个框架解决跨域问题
    华人运通(主vue)前端研发初级工程师
    css常用命名
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3012294.html
Copyright © 2011-2022 走看看