自從微軟發(fā)布 ASP.NET MVC and routing engine (System.Web.Routing)以來(lái),就設(shè)法讓我們明白你完全能控制URL和routing,只要與你的application path相結(jié)合進(jìn)行擴(kuò)展,任何問題都迎刃而解。如果你需要在所處的域或者子域處理數(shù)據(jù)標(biāo)記的話,強(qiáng)制使用Default。
遺憾的是,ASP.NET MVC是基于虛擬目錄的,在實(shí)際項(xiàng)目卻有各種各樣的需求方案。
自從微軟發(fā)布 ASP.NET MVC 和routing engine (System.Web.Routing)以來(lái),就設(shè)法讓我們明白你完全能控制URL和routing,只要與你的application path相結(jié)合進(jìn)行擴(kuò)展,任何問題都迎刃而解。如果你需要在所處的域或者子域處理數(shù)據(jù)標(biāo)記的話,強(qiáng)制使用Default。
遺憾的是,ASP.NET MVC是基于虛擬目錄的,在實(shí)際項(xiàng)目卻有各種各樣的需求方案。
例如:
1:應(yīng)用程序是多語(yǔ)言的,像cn.example.com應(yīng)該被匹配到“www.{language}example.com”路由上。
2:應(yīng)用程序是多用戶的,像username.example.com應(yīng)該被匹配到“www.{clientname}.example.com”路由上。
3:應(yīng)用程序是多子域的,像mobile.example.com應(yīng)該被匹配到"www.{controller}.example.com/{action}....” 。
坐下來(lái),深呼吸,開始我們ASP.NET MVC的神奇之旅吧。
定義routes
下面是我們定義簡(jiǎn)單的route,不帶任何controller控制的route:
![]()
Code
routes.Add("DomainRoute", new DomainRoute(
"home.example.com", // Domain with parameters
"{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
));
另一個(gè)例子是用我們的controller控制域名:
![]()
Code
routes.Add("DomainRoute", new DomainRoute(
"{controller}.example.com", // Domain with parameters< br /> "{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
));
打算用controller 和action完全控制域名?
![]()
Code
routes.Add("DomainRoute", new DomainRoute(
"{controller}-{action}.example.com", // Domain with parameters
"{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
));
接下來(lái)是多語(yǔ)言route:
![]()
Code
routes.Add("DomainRoute", new DomainRoute(
"{language}.example.com", // Domain with parameters
"{controller}/{action}/{id}", // URL with parameters
new { language = "en", controller = "Home", action = "Index", id = "" } // Parameter defaults
));
HtmlHelper 擴(kuò)展方法
因?yàn)槲覀儾幌M械腢RL所產(chǎn)生HtmlHelper ActionLink要使用full URLs,第一件事我們會(huì)添加一些新的ActionLink,其中載有boolean flag是否要full URLs或沒有。利用這些,現(xiàn)在您可以添加一個(gè)鏈接到一個(gè)Action如下:
<%= Html.ActionLink("About", "About", "Home", true)%>
跟你以往的習(xí)慣沒有什么不同,不是嗎?
以下是一小段代碼:
![]()
Code
public static class LinkExtensions
{
public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, bool requireAbsoluteUrl)
{
return htmlHelper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary(), requireAbsoluteUrl);
}
// more of these
public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool requireAbsoluteUrl)
{
if (requireAbsoluteUrl)
{
HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = RouteTable.Routes.GetRouteData(currentContext);
routeData.Values["controller"] = controllerName;
routeData.Values["action"] = actionName;
DomainRoute domainRoute = routeData.Route as DomainRoute;
if (domainRoute != null)
{
DomainData domainData = domainRoute.GetDomainData(new RequestContext(currentContext, routeData), routeData.Values);
return htmlHelper.ActionLink(linkText, actionName, controllerName, domainData.Protocol, domainData.HostName, domainData.Fragment, routeData.Values, null);
}
}
return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
}
}
在這沒什么特別的:有許多的擴(kuò)展方法,把擴(kuò)展的URL加到域名上。這是一個(gè)預(yù)設(shè)ActionLink helpers,我的精神食糧來(lái)了DomainRoute class(詳見:Dark Magic)
Dark magic
瞥眼之間,您可能已經(jīng)看到了我的DomainRoute類代碼段。這個(gè)類實(shí)際上是提取子域,并增加了象征性支持域部分的傳入的URL,
我們將擴(kuò)展基類,它已經(jīng)給了我們一些屬性和方法,但是我們得重寫他們!
![]()
Code
public class DomainRoute : Route
{
//
public string Domain { get; set; }
//
public override RouteData GetRouteData(HttpContextBase httpContext)
{
// 構(gòu)造regex
domainRegex = CreateRegex(Domain);
pathRegex = CreateRegex(Url);
// 請(qǐng)求信息
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);
// Route 數(shù)據(jù)
RouteData data = null;
if (domainMatch.Success && pathMatch.Success)
{
data = new RouteData(this, RouteHandler);
// 添加默認(rèn)選項(xiàng)
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)
{
// 獲得主機(jī)名
string hostname = Domain;
foreach (KeyValuePair<string, object> pair in values)
{
hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
}
// Return 域名數(shù)據(jù)
return new DomainData
{
Protocol = "http",
HostName = hostname,
Fragment = ""
};
}
// ![]()
}
哇,這是一串按照我們定義的route轉(zhuǎn)換傳入請(qǐng)求的URL到tokens的代碼,我們這樣做是轉(zhuǎn)換{controller}和按照regex然后再嘗試匹配route規(guī)則,在我們的DomainRoute class里還有其他的helper方法,需要更多的功能可以自己研究擴(kuò)展。
附代碼:附件
(如果要在使用Visual Studio開發(fā)Web服務(wù)器,務(wù)必添加把二級(jí)域名添加到hosts文件)(貌似本地測(cè)試不用)
原文地址:http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
其實(shí)有的人為什么要這么麻煩用這種方式,URL重寫或者二級(jí)域名直接綁定都可以。但是既然微軟給url rouring,就應(yīng)該能做到。