自从微软发布 MVC 和routing engine (System.Web.Routing)以来,就设法让我们明白你完全能控制URL和routing,只要与你的application path相结合进行扩展,任何问题都迎刃而解。如果你需要在所处的域或者子域处理数据标记的话,强制使用Default。
遗憾的是, MVC是基于虚拟目录的,在实际项目却有各种各样的需求方案。
例如:
1:应用程序是多语言的,像应该被匹配到“www.{language}”路由上。
2:应用程序是多用户的,像应该被匹配到“www.{clientname}.”路由上。
3:应用程序是多子域的,像应该被匹配到"www.{controller}./{action}....” 。
坐下来,深呼吸,开始我们 MVC的神奇之旅吧。
定义routes
下面是我们定义简单的route,不带任何controller控制的route:
routes.Add("DomainRoute",newDomainRoute(
"",//Domainwithparameters
"{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
));
另一个例子是用我们的controller控制域名:
routes.Add("DomainRoute",newDomainRoute(
"{controller}.",//Domainwithparameters<br/>"{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
));
打算用controller 和action完全控制域名?
routes.Add("DomainRoute",newDomainRoute(
"{controller}-{action}.",//Domainwithparameters
"{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
));
接下来是多语言route:
routes.Add("DomainRoute",newDomainRoute(
"{language}.",//Domainwithparameters
"{controller}/{action}/{id}",//URLwithparameters
new{language="en",controller="Home",action="Index",id=""}//Parameterdefaults
));
HtmlHelper 扩展方法
因为我们不希望所有的URL所产生HtmlHelper ActionLink要使用full URLs,第一件事我们会添加一些新的ActionLink,其中载有boolean flag是否要full URLs或没有。利用这些,现在您可以添加一个链接到一个Action如下:
<%=Html.ActionLink("About","About","Home",true)%>
跟你以往的习惯没有什么不同,不是吗?
以下是一小段代码:
publicstaticclassLinkExtensions
{
publicstaticstringActionLink(thisHtmlHelperhtmlHelper,stringlinkText,stringactionName,stringcontrollerName,boolrequireAbsoluteUrl)
{
returnhtmlHelper.ActionLink(linkText,actionName,controllerName,newRouteValueDictionary(),newRouteValueDictionary(),requireAbsoluteUrl);
}
//moreofthese
publicstaticstringActionLink(thisHtmlHelperhtmlHelper,stringlinkText,stringactionName,stringcontrollerName,RouteValueDictionaryrouteValues,IDictionary<string,object>htmlAttributes,boolrequireAbsoluteUrl)
{
if(requireAbsoluteUrl)
{
HttpContextBasecurrentContext=newHttpContextWrapper(HttpContext.Current);
RouteDatarouteData=RouteTable.Routes.GetRouteData(currentContext);
routeData.Values["controller"]=controllerName;
routeData.Values["action"]=actionName;
DomainRoutedomainRoute=routeData.RouteasDomainRoute;
if(domainRoute!=null)
{
DomainDatadomainData=domainRoute.GetDomainData(newRequestContext(currentContext,routeData),routeData.Values);
returnhtmlHelper.ActionLink(linkText,actionName,controllerName,domainData.Protocol,domainData.HostName,domainData.Fragment,routeData.Values,null);
}
}
returnhtmlHelper.ActionLink(linkText,actionName,controllerName,routeValues,htmlAttributes);
}
}
在这没什么特别的:有许多的扩展方法,把扩展的URL加到域名上。这是一个预设ActionLink helpers,我的精神食粮来了DomainRouteclass(详见:Dark Magic)
Dark magic
瞥眼之间,您可能已经看到了我的DomainRoute类代码段。这个类实际上是提取子域,并增加了象征性支持域部分的传入的URL,
我们将扩展基类,它已经给了我们一些属性和方法,但是我们得重写他们!
publicclassDomainRoute:Route
{
//
publicstringDomain{get;set;}
//
publicoverrideRouteDataGetRouteData(HttpContextBasehttpContext)
{
//构造regex
domainRegex=CreateRegex(Domain);
pathRegex=CreateRegex(Url);
//请求信息
stringrequestDomain=httpContext.Request.Headers["host"];
if(!string.IsNullOrEmpty(requestDomain))
{
if(requestDomain.IndexOf(":")>0)
{
requestDomain=requestDomain.Substring(0,requestDomain.IndexOf(":"));
}
}
else
{
requestDomain=httpContext.Request.Url.Host;
}
stringrequestPath=httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2)+httpContext.Request.PathInfo;
//匹配域名和路由
MatchdomainMatch=domainRegex.Match(requestDomain);
MatchpathMatch=pathRegex.Match(requestPath);
//Route数据
RouteDatadata=null;
if(domainMatch.Success&&pathMatch.Success)
{
data=newRouteData(this,RouteHandler);
//添加默认选项
if(Defaults!=null)
{
foreach(KeyValuePair<string,object>iteminDefaults)
{
data.Values[item.Key]=item.Value;
}
}
//匹配域名路由
for(inti=1;i<domainMatch.Groups.Count;i++)
{
Groupgroup=domainMatch.Groups[i];
if(group.Success)
{
stringkey=domainRegex.GroupNameFromNumber(i);
if(!string.IsNullOrEmpty(key)&&!char.IsNumber(key,0))
{
if(!string.IsNullOrEmpty(group.Value))
{
data.Values[key]=group.Value;
}
}
}
}
//匹配域名路径
for(inti=1;i<pathMatch.Groups.Count;i++)
{
Groupgroup=pathMatch.Groups[i];
if(group.Success)
{
stringkey=pathRegex.GroupNameFromNumber(i);
if(!string.IsNullOrEmpty(key)&&!char.IsNumber(key,0))
{
if(!string.IsNullOrEmpty(group.Value))
{
data.Values[key]=group.Value;
}
}
}
}
}
returndata;
}
publicoverrideVirtualPathDataGetVirtualPath(RequestContextrequestContext,RouteValueDictionaryvalues)
{
returnbase.GetVirtualPath(requestContext,RemoveDomainTokens(values));
}
publicDomainDataGetDomainData(RequestContextrequestContext,RouteValueDictionaryvalues)
{
//获得主机名
stringhostname=Domain;
foreach(KeyValuePair<string,object>pairinvalues)
{
hostname=hostname.Replace("{"+pair.Key+"}",pair.Value.ToString());
}
//Return域名数据
returnnewDomainData
{
Protocol="http",
HostName=hostname,
Fragment=""
};
}
//
}
哇,这是一串按照我们定义的route转换传入请求的URL到tokens的代码,我们这样做是转换{controller}和按照regex然后再尝试匹配route规则,在我们的DomainRouteclass里还有其他的helper方法,需要更多的功能可以自己研究扩展。
附代码:附件
(如果要在使用Visual Studio开发Web服务器,务必添加把二级域名添加到hosts文件)(貌似本地测试不用)
原文地址:http://blog.maartenballiauw.be/post//05/20/ASPNET-MVC-Domain-Routing.aspx
其实有的人为什么要这么麻烦用这种方式,URL重写或者二级域名直接绑定都可以。但是既然微软给url rouring,就应该能做到。