一、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. bzoj 5334 数学计算

    bzoj 5334 数学计算 开始想直接模拟过程做,但模数 \(M\) 不一定为质数,若没有逆元就 \(fAKe\) 掉了. 注意到操作 \(2\) 是删除对应的操作 \(1\) ,相当于只有 \(1 ...

  2. BZOJ1131 POI2008 Sta 【树形DP】

    BZOJ1131 POI2008 Sta Description 给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 Input 给出一个数字N,代表有N个点.N<=10 ...

  3. 在制作跨平台的 NuGet 工具包时,如何将工具(exe/dll)的所有依赖一并放入包中

    NuGet 提供了工具类型的包支持,生成一个基于 .NET Core 的 dll 或者基于 .NET Framework 的 exe 之后,你几乎可以对项目做任何事情.但是,默认情况下,NuGet 不 ...

  4. flex 伸缩布局

    伸缩布局 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便.CSS3在布局方面做了非常大的改进,使得我们对块级元素 ...

  5. C++中const使用注意要点(二)

    当const修饰类的成员变量 1.const修饰类的非静态成员时必须在构造函数初始化列表上初始化: 在构造函数内会提示表达式必须是可修改的左值,因为在构造函数内并不是初始化,仅仅是赋值,而const类 ...

  6. SPUtils

    public class SPUtils { /** * 保存在手机里的SP文件名 */ public static final String FILE_NAME = "my_sp" ...

  7. 科普Spark,Spark是什么,如何使用Spark

    科普Spark,Spark是什么,如何使用Spark 1.Spark基于什么算法的分布式计算(很简单) 2.Spark与MapReduce不同在什么地方 3.Spark为什么比Hadoop灵活 4.S ...

  8. Centos6-7安装Python3.5以及SSL的编译安装,识别https

    Python3中无法导入ssl模块的解决办法 如果你发现在python3脚本运行过程中发现涉及到ssl模块都无法运行的情况下.那么需要进行如下步骤 第一步: yum install openssl o ...

  9. 第六章 通过Service访问Pod(上)

    不应该直接使用Pod的ID地址作为对外提供服务的接口,应为一旦Pod重启,IP地址就变化了,解决方案是使用Service. 6.1 创建Service K8s service从逻辑上代表了一组Pod, ...

  10. Code blocks调试教程

    特别声明:本教程已转移至百度经验:https://jingyan.baidu.com/article/6b182309939a87ba58e159bf.html 一.题外话 之前一直想用Code bl ...