一、DomainAction,方便生成不同域下的url

1、新建3个MVC项目,一个公用类库WebCore

Demo.WebApplication0

  绑定域名 www.demo.com demo.com t0.demo.com

Demo.WebApplication1(可不用建)

  绑定域名 t1.demo.com

Demo.WebApplication2(可不用建)

  绑定域名 t2.demo.com

Demo.WebCore

2、项目Demo.WebApplication0新增一个学生的Controller

     public class StudentController : Controller
{
public ActionResult Search(int gender, int degree, int pageSize, int page)
{
return Content(string.Format("查找学生,筛选条件。性别:{0},学历:{1},每页学生数量:{2},页码:{3}"
, (gender == ? "男" : (gender == ? "女" : "不限"))
,degree, pageSize, page
));
//return View();
} }

3、域名枚举

     public enum DemoDomain
{
/// <summary>
/// www.demo.com
/// demo.com
/// t0.demo.com
/// </summary>
T0, /// <summary>
/// t1.demo.com
/// </summary>
T1, /// <summary>
/// t2.demo.com
/// </summary>
T2, /// <summary>
/// demo.com
/// </summary>
Default, }

4、System.Web.Mvc.UrlHelper的静态扩展类DemoUrlExtensions

     public static class DemoUrlExtensions
{
public static string DomainAction(this UrlHelper urlHelper, string actionName, string controllerName)
{
return urlHelper.DomainAction(actionName, controllerName, DemoDomain.Default);
} public static string DomainAction(this UrlHelper urlHelper, string actionName, string controllerName, object routeValues)
{
return urlHelper.DomainAction(actionName, controllerName, routeValues, DemoDomain.Default);
} public static string DomainAction(this UrlHelper urlHelper, string actionName, string controllerName, DemoDomain Domain)
{
return urlHelper.DomainAction(actionName, controllerName, new { }, Domain);
} public static string DomainAction(this UrlHelper urlHelper, string actionName, string controllerName, object routeValues, DemoDomain Domain)
{
return DomainAction(urlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), Domain);
} public static string DomainAction(this UrlHelper urlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, DemoDomain Domain)
{
string subDomain = string.Empty;
string HostName = string.Empty;
switch (Domain)
{
case DemoDomain.Default:
subDomain = string.Empty;
break;
case DemoDomain.T0:
subDomain = "t0";
break;
case DemoDomain.T1:
subDomain = "t1";
break;
case DemoDomain.T2:
subDomain = "t2";
break;
default:
subDomain = string.Empty;
break;
} if (!string.IsNullOrEmpty(subDomain))
{
HostName = subDomain + ".demo.com";
}
else
{
HostName = "www.demo.com";
}
//核心的一行
string url = urlHelper.Action(actionName, controllerName, routeValues, "http", HostName);
if (url.Contains('?'))
{
url = url.TrimEnd('/');
}
else
{
if (url.EndsWith(".html/"))
{
url = url.TrimEnd('/');
}
}
return url;
} }

5、修改Home/Index内容

 <div>
<a href="@Url.DomainAction("Index","Home", DemoDomain.T1)">我要去t1.demo.com</a>
<a href="@Url.DomainAction("Index","Home", DemoDomain.T2)">我要去t2.demo.com</a>
<a href="@Url.DomainAction("Index", "Home", new { from = "www" }, DemoDomain.T2)">我要去t2.demo.com,我要带参数,表示我是从www过来的</a> <a href="@Url.DomainAction("Search", "Student", new { gender = 1, degree = 0, pageSize = 20, page = 1 }, DemoDomain.T0)">查找性别男的学生</a> </div>

对应的html源码

 <div>
<a href="http://t1.demo.com/">我要去t1.demo.com</a>
<a href="http://t2.demo.com/">我要去t2.demo.com</a>
<a href="http://t2.demo.com/?from=www">我要去t2.demo.com,我要带参数,表示我是从www过来的</a> <a href="http://t0.demo.com/Student/Search?gender=1&amp;degree=0&amp;pageSize=20&amp;page=1">查找性别男的学生</a> </div>

二、注册路由,SEO优化

现在已经能做到

@Url.DomainAction("Search", "Student", new { gender = , degree = , pageSize = , page =  }, DemoDomain.T0)

对应的Url为

http://t0.demo.com/Student/Search?gender=1&degree=0&pageSize=20&page=1

,但这个链接不利于SEO,理想的情况可能是这样(请把t0当成student)

http://t0.demo.com/Search/1-0-20-1.html

定义路由

 public class DomainRoute : Route
{
private static 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_]*})*-?\.?\/?", RegexOptions.Compiled);
private static Dictionary<string, Regex> domainRegDic = new Dictionary<string, Regex>();
private static Dictionary<string, Regex> pathRegDic = new Dictionary<string, Regex>(); /// <summary>
///
/// </summary>
public Regex PathRegex
{
get
{
if (!pathRegDic.Keys.Contains(Url))
{
switch (Url)
{
case WebCoreConsts.URL_T0_SearchStudent:
pathRegDic[Url] = new Regex(ConvertToPattern("search/{gender}-{degree}-{pagesize}-{page}.html"), RegexOptions.Compiled | RegexOptions.IgnoreCase);
break;
default:
pathRegDic[Url] = CreateRegex(Url);
break;
}
}
return pathRegDic[Url];
}
} /// <summary>
///
/// </summary>
public Regex DomainRegex
{
get
{
if (!domainRegDic.Keys.Contains(Domain))
{ domainRegDic[Domain] = CreateRegex(Domain);
}
return domainRegDic[Domain];
} } 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;
} //new
public DomainRoute(string domain, string url, object defaults, object constraints)
: base(url, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), 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)
{
// 请求信息
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)
{ VirtualPathData pathData = base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
if (pathData != null && !string.IsNullOrEmpty(pathData.VirtualPath))
{
if (pathData.VirtualPath.EndsWith(".html/"))
{
pathData.VirtualPath = pathData.VirtualPath.TrimEnd('/');
}
else if (!pathData.VirtualPath.EndsWith("/") && !pathData.VirtualPath.EndsWith(".html"))
{
pathData.VirtualPath = pathData.VirtualPath + "/";
}
}
return pathData;
} private Regex CreateRegex(string source)
{
try
{
string src = source;
// 替换
source = source.Replace("/", @"\/?");
source = source.Replace(".", @"\.?");
source = source.Replace("-", @"\-?");
source = source.Replace("{", @"(?<");
source = source.Replace("}", @">([a-zA-Z0-9_]*))");
return new Regex("^" + source + "$", RegexOptions.Compiled);
}
catch (Exception ex)
{
//AppLogger.Error("创建正则出错:" + source + " 详情:" + ex.Message);
}
return new Regex("^" + source + "$", RegexOptions.Compiled);
} private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
{ 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;
} private static string ConvertToPattern(string source)
{
try
{
string src = source;
// 替换
source = source.Replace("/", @"\/?");
source = source.Replace(".", @"\.?");
source = source.Replace("-", @"\-?");
source = source.Replace("{", @"(?<");
source = source.Replace("}", @">([a-zA-Z0-9_]*))");
return "^" + source + "$";
}
catch (Exception ex)
{
}
return source;
} }

注册路由

             routes.LowercaseUrls = true;

             routes.Add("T0StudentSearchDomainRoute", new DomainRoute(
"t0.demo.com", // Domain with parameters
WebCoreConsts.URL_T0_SearchStudent, // URL with parameters
new { controller = "Student", action = "Search" }
//, new { }
));

可能还需要在web.config的system.webServer项中增加一行配置,否则.html不会进入路由,会直接映射成本地路径

    <modules runAllManagedModulesForAllRequests="true" />

这时候

    <a href="@Url.DomainAction("Search", "Student", new { gender = 1, degree = 0, pageSize = 20, page = 1 }, DemoDomain.T0)" target="_blank">查找性别男的学生</a>

就会对应成

    <a href="http://t0.demo.com/search/1-0-20-1.html" target="_blank">查找性别男的学生</a>

  附:源码下载

MVC项目不同域之间的UrlRouting的更多相关文章

  1. Mvc中域的添加和不同域之间的跳转

    一.在新添加的域中中的 AreaRegistration中作如下设置: 二.在原来的Global.asax中设置: 三.不同域之间的跳转 @Url.Action("Index", ...

  2. MVC项目实践,在三层架构下实现SportsStore-06,实现购物车

    SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...

  3. 基于MVC4+EasyUI的Web开发框架经验总结(15)--在MVC项目中使用RDLC报表

    RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章<DevExpress的XtraReport和微软RDL ...

  4. 1.2 认识ASP.NET MVC项目结构

    1.开发环境 操作系统:xp.vista.windows 7.windows 8.windows server 2003|2008|2008R2|2012: 集成开发环境IDE: Vsiual Stu ...

  5. 在MVC项目中使用RDLC报表

    原文地址:http://www.cnblogs.com/wuhuacong/p/4109833.html RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用 ...

  6. spring mvc的跨域解决方案

    什么是跨域 一句话:同一个ip.同一个网络协议.同一个端口,三者都满足就是同一个域,否则就是跨域. 为什么非得跨域 基于两个方面: a. web应用本身是部署在不同的服务器上 b.基于开发的角度 -- ...

  7. 在已有的Asp.net MVC项目中引入Taurus.MVC

    Taurus.MVC是一个优秀的框架,如果要应用到已有的Asp.net MVC项目中,需要修改一下. 1.前提约定: 走Taurus.MVC必须指定后缀.如.api 2.原项目修改如下: web.co ...

  8. .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI

    作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...

  9. 使用JavaConfig和注解方式实现零xml配置的Spring MVC项目

    1. 引言 Spring MVC是Spring框架重要组成部分,是一款非常优秀的Web框架.Spring MVC以DispatcherServlet为核心,通过可配置化的方式去处理各种web请求. 在 ...

随机推荐

  1. getServletContext()方法详解

    javax.servlet.ServletContext接口 一个servlet上下文是servlet引擎提供用来服务于Web应用的接口.Servlet上下文具有名字(它属于Web应用的名字)唯一映射 ...

  2. copy, retain, assign , readonly , readwrite,strong,weak,nonatomic整理

    copy:建立一个索引计数为1的对象,然后释放旧对象 对NSString对NSString 它指出,在赋值时使用传入值的一份拷贝.拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议 ...

  3. 呵呵sql

    INSERT  INTO fnd_document_folder_structure_t (folder_name,parent_folder_id,company_type_id,inv_flag, ...

  4. spring 自动扫描组件

    在Spring2.5中,有4种类型的组件自动扫描注释类型 @Component – 指示自动扫描组件. @Repository – 表示在持久层DAO组件. @Service – 表示在业务层服务组件 ...

  5. 【Oracle】OGG单向复制配置

    实验环境: 源端: Ip:192.168.40.10 DataBase:Oracle 11.2.0.1.0 ORCL OS:OEL5.6 OGG:fbo_ggs_Linux_x86_ora11g_32 ...

  6. 从wiresharp看tcp三次握手

    我们知道,传输层是OSI模型中用户进行数据传输的分层,目前仅有TCP和UDP两种协议可用.TCP为了进行传输控制,引入了三次握手机制,以确保通信连接的建立.道理很简单,我们跟别人打电话聊天时,对方拿起 ...

  7. Bash命令查找本机公网IP

    用Bash命令查找本机公网IP wget -qO - http://ipecho.net/plain; echo

  8. DP 过河卒

    棋盘上A点有一个过河卒,需要走到目标B点.卒行走的规则:可以向下.或者向右.同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点.因此称之为“马拦过河卒”. 棋盘用坐标 ...

  9. Spring Cloud 服务网关Zuul

    Spring Cloud 服务网关Zuul 服务网关是分布式架构中不可缺少的组成部分,是外部网络和内部服务之间的屏障,例如权限控制之类的逻辑应该在这里实现,而不是放在每个服务单元. Spring Cl ...

  10. (转)Linq DataTable的修改和查询

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...