之前我就想做二级域名指向同一个IP同一个程序无非是在路由匹配规则上做文章也就是对Url的重写的一种思路。我用了半天时间上网查阅了相关资料并做了Demo测试是完全
以的,在这分享给大家...
假如网站主域名是:www.abc.com
实现二级域名是: tianjin.abc.com , shanxi.abc.com 这个样子。
首先定义DomainData、DomainRoute类
public class DomainRoute : Route { private Regex domainRegex; private Regex pathRegex; public string Domain { get; set; } public DomainRoute(string domain, string url, RouteValueDictionary defaults) : base(url, defaults, new MvcRouteHandler()) { Domain = domain; } public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { Domain = domain; } public DomainRoute(string domain, string url, object defaults) : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler()) { Domain = domain; } public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler) : base(url, new RouteValueDictionary(defaults), routeHandler) { Domain = domain; } public override RouteData GetRouteData(HttpContextBase httpContext) { // 构造 regex domainRegex = CreateRegex(Domain); pathRegex = CreateRegex(Url); // 请求信息 string requestDomain = httpContext.Request.Headers["host"]; if (!string.IsNullOrEmpty(requestDomain)) { if (requestDomain.IndexOf(":") > 0) { requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":")); } } else { requestDomain = httpContext.Request.Url.Host; } string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; // 匹配域名和路由 Match domainMatch = domainRegex.Match(requestDomain); Match pathMatch = pathRegex.Match(requestPath); // 路由数据 RouteData data = null; if (domainMatch.Success && pathMatch.Success) { data = new RouteData(this, RouteHandler); // 添加默认选项 if (Defaults != null) { foreach (KeyValuePair<string, object> item in Defaults) { data.Values[item.Key] = item.Value; } } // 匹配域名路由 for (int i = 1; i < domainMatch.Groups.Count; i++) { Group group = domainMatch.Groups[i]; if (group.Success) { string key = domainRegex.GroupNameFromNumber(i); if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0)) { if (!string.IsNullOrEmpty(group.Value)) { data.Values[key] = group.Value; } } } } // 匹配域名路径 for (int i = 1; i < pathMatch.Groups.Count; i++) { Group group = pathMatch.Groups[i]; if (group.Success) { string key = pathRegex.GroupNameFromNumber(i); if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0)) { if (!string.IsNullOrEmpty(group.Value)) { data.Values[key] = group.Value; } } } } } return data; } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { return base.GetVirtualPath(requestContext, RemoveDomainTokens(values)); } public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values) { // 获得主机名 string hostname = Domain; foreach (KeyValuePair<string, object> pair in values) { hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString()); } // Return 域名数据 return new DomainData { Protocol = "http", HostName = hostname, Fragment = "" }; } private Regex CreateRegex(string source) { // 替换 source = source.Replace("/", @"\/?"); source = source.Replace(".", @"\.?"); source = source.Replace("-", @"\-?"); source = source.Replace("{", @"(?<"); source = source.Replace("}", @">([a-zA-Z0-9_]*))"); return new Regex("^" + source + "$"); } private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values) { 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_]*})*-?\.?\/?"); Match tokenMatch = tokenRegex.Match(Domain); for (int i = 0; i < tokenMatch.Groups.Count; i++) { Group group = tokenMatch.Groups[i]; if (group.Success) { string key = group.Value.Replace("{", "").Replace("}", ""); if (values.ContainsKey(key)) values.Remove(key); } } return values; } } public class DomainData { public string Protocol { get; set; } public string HostName { get; set; } public string Fragment { get; set; } }如果项目是MVC4.0那么就打开App_Start 文件夹下面的RouteConfig.cs路由配置文件,如果是MVC3.0项目则添加路由,Global.asax 文件默认的MVC 路由的代码
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }修改后的路由如下:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.Add( "@DomainRoute", new DomainRoute( "abc.com", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional } )); routes.Add( "wwwDomainRoute", new DomainRoute( "www.abc.com", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional } )); routes.Add( "DomainRoute", new DomainRoute( "{CityNameUrl}.abc.com", "{controller}/{action}/{id}", new { CityNameUrl = "", controller = "Home", action = "City", id = "" } )); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }当然这个路由解析匹配顺序是按照你们的需求去修改,但是路由匹配规则是从上到下的找符合的一条进行匹配,如果匹配到则不继续往下走,还需要说明一点, 我的域名是在万网注册的。所以还需要在域名解析那一块添加一条泛解析规则:
然后再程序中获取tianjin.abc.com 获取前缀名称tianjin这个动态参数的方法是:
var cityName = RouteData.Values["CityNameUrl"]; 就可以得到,
以上为个人学习总结,如有错误,欢迎指正!!共同学习研究!!!
参考地址:http://www.cnblogs.com/wenthink/archive/2013/04/10/MvcDynamicSecondaryDomain.html
http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
转自:http://www.liguoqing.net/static/2014/12/15/50.html,感谢