一、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. java project 项目在 linux 下面部署方法

    1.前提是安装好了响应的开发和部署环境,例如jdk. 2.在Linux下运行可执行Jar包,首先准备jar包,一般的编译工具Eclipse,jbuilder都提供export功能,可以生成jar包. ...

  2. BZOJ1833 ZJOI2010 count 数字计数 【数位DP】

    BZOJ1833 ZJOI2010 count 数字计数 Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包 ...

  3. 为什么委托的减法(- 或 -=)可能出现非预期的结果?(Delegate Subtraction Has Unpredictable Result)

    当我们为一个委托写 -= 的时候,ReSharper 会提示“Delegate Subtraction Has Unpredictable Result”,即“委托的减法可能出现非预期的结果”.然而在 ...

  4. python redis的基本使用

    1.redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sor ...

  5. @EnableAutoConfiguration注解原理

    前言 Spring Boot中引入了自动配置,让开发者利用起来更加的简便.快捷.比如内嵌的tomcat端口默认配置是8080,这些都属于Spring Boot自动配置的范畴,当然其自动配置相当多. s ...

  6. webstorm配置scss的小结

    1)安装ruby 2)安装sass 3)配置webstorm 打开webstrom ->file->setting->Tools->file watcher 添加scss pr ...

  7. 题目1413:神秘元素 ——lis的元素是否唯一

    求序列的最长子序列中不可分割元素的数目.不可分割元素,肯定属于某一个最长子序列,首先做的就是把属于最长子序列的数提取出来,减小查找范围.怎么提取?可以用LIS(最长递增子序列)和LDS(最长递减子序列 ...

  8. 【备忘录】CentOS服务器mysql忘记root密码恢复

    mysql的root忘记,现无法操作数据库 停止mysql服务service  mysql stop 然后使用如下的参数启动mysql, --skip-grant-tables会跳过mysql的授权 ...

  9. debian修改连接数限制

    golang写的socket做压力测试的时候,提示too many open files,解决方法如下 sudo gvim /etc/security/limits.conf 添加 * - nofil ...

  10. bzoj2184: 任意图的匹配

    Description 每天都要考,每天都要讲,大家注意力都集中不起来了,每天听解题报告时都有人交头接耳(也包括我,呵呵).这样做大大的影响的学习效率(可能吧).于是,有些好奇心重的同学就开始研究,怎 ...