MVC项目不同域之间的UrlRouting
一、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&degree=0&pageSize=20&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°ree=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的更多相关文章
- Mvc中域的添加和不同域之间的跳转
一.在新添加的域中中的 AreaRegistration中作如下设置: 二.在原来的Global.asax中设置: 三.不同域之间的跳转 @Url.Action("Index", ...
- MVC项目实践,在三层架构下实现SportsStore-06,实现购物车
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- 基于MVC4+EasyUI的Web开发框架经验总结(15)--在MVC项目中使用RDLC报表
RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章<DevExpress的XtraReport和微软RDL ...
- 1.2 认识ASP.NET MVC项目结构
1.开发环境 操作系统:xp.vista.windows 7.windows 8.windows server 2003|2008|2008R2|2012: 集成开发环境IDE: Vsiual Stu ...
- 在MVC项目中使用RDLC报表
原文地址:http://www.cnblogs.com/wuhuacong/p/4109833.html RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用 ...
- spring mvc的跨域解决方案
什么是跨域 一句话:同一个ip.同一个网络协议.同一个端口,三者都满足就是同一个域,否则就是跨域. 为什么非得跨域 基于两个方面: a. web应用本身是部署在不同的服务器上 b.基于开发的角度 -- ...
- 在已有的Asp.net MVC项目中引入Taurus.MVC
Taurus.MVC是一个优秀的框架,如果要应用到已有的Asp.net MVC项目中,需要修改一下. 1.前提约定: 走Taurus.MVC必须指定后缀.如.api 2.原项目修改如下: web.co ...
- .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI
作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...
- 使用JavaConfig和注解方式实现零xml配置的Spring MVC项目
1. 引言 Spring MVC是Spring框架重要组成部分,是一款非常优秀的Web框架.Spring MVC以DispatcherServlet为核心,通过可配置化的方式去处理各种web请求. 在 ...
随机推荐
- 每天一个linux命令(文件操作):【转载】locate命令
locate 让使用者可以很快速的搜寻档案系统内是否有指定的档案.其方法是先建立一个包括系统内所有档案名称及路径的数据库,之后当寻找时就只需查询这个数据库,而不必实际深入档案系统之中了.在一般的 di ...
- Java并发--深入剖析ThreadLocal
想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码 ...
- hadoop入门手册4:Hadoop【2.7.1】初级入门之命令:文件系统shell1
问题导读1.Hadoop文件系统shell与Linux shell有哪些相似之处?2.如何改变文件所属组?3.如何改变hdfs的文件权限?4.如何查找hdfs文件,并且不区分大小写? 概述文件系统 ( ...
- Django 资源文件配置
staticfiles: 这是一个静态资源管理的app,django.contrib.staticfiles.老的版本中,静态资源管理一直是一个问题,部分app发布的时候 需要带上静态资源,在部署的时 ...
- 《DSP using MATLAB》示例Example 6.9
代码: % All-Pole IIR filter to Lattice structure filter a = [1, 13/24, 5/8, 1/3]; K = dir2latc(a) % To ...
- 网络流量监控分析工具 Ntopng 安装
官方说明:http://packages.ntop.org/ http://packages.ntop.org/centos-stable/ http://packages.ntop.o ...
- 执行npm install报错:npm ERR! code EINTEGRITY
命令行执行npm install报错如下: D:\frontend\viewsdev>npm install npm ERR! code EINTEGRITY npm ERR! sha512-8 ...
- 老齐python-基础7(文件操作、迭代)
在python3中,没有file这个内建类型了(python2中,file是默认类型) 1.读文件 创建文件,130.txt 并在里面输入 learn python http://qiwsir.git ...
- Eclipse中创建新的Spring Boot项目
本文转载自:http://blog.csdn.net/clementad/article/details/51334064 简单几步,在Eclipse中创建一个新的spring Boot项目: 1.E ...
- Clustershell集群管理
在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...