[转载]ASP.NET MVC 实现二级域名

[转载]ASP.NET MVC 实现二级域名 – 大陆响尾蛇 – 博客园.

自从微软发布 ASP.NET MVC 和routing engine (System.Web.Routing)以来,就设法让我们明白你完全能控制URL和routing,只要与你的application path相结合进行扩展,任何问题都迎刃而解。如果你需要在所处的域或者子域处理数据标记的话,强制使用Default。

遗憾的是,ASP.NET MVC是基于虚拟目录的,在实际项目却有各种各样的需求方案。

例如:

1:应用程序是多语言的,像cn.example.com应该被匹配到“www.{language}example.com”路由上。

2:应用程序是多用户的,像username.example.com应该被匹配到“www.{clientname}.example.com”路由上。

3:应用程序是多子域的,像mobile.example.com应该被匹配到”www.{controller}.example.com/{action}….” 。

坐下来,深呼吸,开始我们ASP.NET MVC的神奇之旅吧。

定义routes

下面是我们定义简单的route,不带任何controller控制的route:


routes.Add(DomainRoute, new DomainRoute(
home.example.com, // Domain with parameters
{action}/{id}, // URL with parameters
new { controller = Home, action = Index, id = “” } // Parameter defaults
));

另一个例子是用我们的controller控制域名:


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完全控制域名?


routes.Add(DomainRoute, new DomainRoute(
{controller}-{action}.example.com, // Domain with parameters
{id}, // URL with parameters
new { controller = Home, action = Index, id = “” } // Parameter defaults
));

接下来是多语言route:


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 扩展方法

因为我们不希望所有的URL所产生HtmlHelper ActionLink要使用full URLs,第一件事我们会添加一些新的ActionLink,其中载有boolean flag是否要full URLs或没有。利用这些,现在您可以添加一个链接到一个Action如下:

<%= Html.ActionLink(About, About, Home, true)%>

跟你以往的习惯没有什么不同,不是吗?
以下是一小段代码:


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);
}
}

在这没什么特别的:有许多的扩展方法,把扩展的URL加到域名上。这是一个预设ActionLink helpers,我的精神食粮来了DomainRoute class(详见:Dark Magic)

Dark magic

瞥眼之间,您可能已经看到了我的DomainRoute类代码段。这个类实际上是提取子域,并增加了象征性支持域部分的传入的URL,

我们将扩展基类,它已经给了我们一些属性和方法,但是我们得重写他们!


public class DomainRoute : Route
{
//

public string Domain { get; set; }

//

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);

// Route 数据

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
= “”
};
}

//
}

哇,这是一串按照我们定义的route转换传入请求的URL到tokens的代码,我们这样做是转换{controller}和按照regex然后再尝试匹配route规则,在我们的DomainRoute class里还有其他的helper方法,需要更多的功能可以自己研究扩展。

附代码:附件
(如果要在使用Visual Studio开发Web服务器,务必添加把二级域名添加到hosts文件)(貌似本地测试不用)
原文地址:http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
其实有的人为什么要这么麻烦用这种方式,URL重写或者二级域名直接绑定都可以。但是既然微软给url rouring,就应该能做到。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏