先来看下面两个个url,对比一下:

  1. http://xxx.yyy.com/Admin/UserManager.aspx
  2. http://xxx.yyy.com/Admin/DeleteUser/1001

   对于第1个Url,假设它与服务器上的文件有直接的关系,那么服务器在接受客户端请求并将对应的文件传送给客户端。我们大概可以猜到它是对用户管理的一个页面,它的物理文件UserManager.aspx在网站根目录下面的Admin文件夹中。而第2个url,在不知道Mvc路由以及Url重写时,很难猜到这个Url背后具体有些什么,前提条件是基于.Net框架开发的Web项目。 那么在这里,我们引入Asp.Net Mvc Url路由这个概念,也正是本文所要阐述的主题,Url路由模块是负责映射从浏览器请求到特定的控制器动作。

  基于上面提到的Url路由以及其作用,我们就大概能猜到第2个Url背后有些啥了。 自然而然的Admin就是控制器了,DeleteUser是控制器里面的动作及Action了,1001就是Action的参数。到这里我们对Url路由有一个简单的认识,那么接着看下面一组url,假设Home是控制器,Index是控制器里面的Action,至于1001或者2345这类数据我们暂且约定为参数:

  1. http://xxx.yyy.com
  2. http://xxx.yyy.com/Home/1001
  3. http://xxx.yyy.com/Index/1001
  4. http://xxx.yyy.com/Home/Index/1001/2345
  5. http://xxx.yyy.com/System/Home/Index/1001

按照约定,从上面的几组Url中可以看出,有的缺控制器,有的缺Action,有的带有好几个参数,有的又莫名的多出了控制器、Action、参数之外的东西,那么他们能正确的访问吗?

  注册路由

  在vs2012里面新建一个asp.net mvc4 web 应用程序项目,可以在项目的根目录下App_Start里面看到RouteConfig文件,在这个文件里面就可以添加url路由了。在文件里面可以看到MapRoute 这个方法,它是RouteCollection的扩展方法,并且含有多个重载,下面看看MapRoute方法的参数,这里选参数最多的那个:

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces);

从上面的代码片段大概可以看出该方法含有路由名称、路由的Url、默认值、约束、首先查找路由所在的命名空间,该方法是返回对映射路由的引用。不过在RouteConfig文件中我们可以看到添加路由的代码:

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

稍微分析一下这段代码可以知道,在路由集合里面添加了一个名为"Default"的路由,并且有一个默认的路由指向,指向名称为Home的控制器,并且Action为Index,可以明显的看到这里 "id = UrlParameter.Optional" 的写法,它的意思就是说Action的参数可以不需要用户来指定,可以缺省。

  多个参数如何传递

  之前在一个QQ群里面见到一兄弟在问,类似这样的Url“http://xxx.yyy.com/Home/Index/1001/2345/tauruswu”在路由里面怎么配置?其实这个也很简单,我们只需要将路由配置、以及Action稍作调整。

routes.MapRoute(
  name: "Default",
url: "{controller}/{action}/{id}/{*catchall}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

这个是调整之后的路由配置,只需要在Url后面再加上"{*catchall}"即可,那么Action调整之后如下

public ActionResult Index(string id,string catchall)
{
  ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。";   return View();
}

在Action里面定义了一个参数"catchall"用来接收Url中除了Id之外其他所有的参数值,那么上面那个Url中接收的参数就是“2345/tauruswu”,这样看起来好不好了,不过我觉得怪怪的,有没有更好的解决方法了?Url有必要写成那么长吗?这个问题在后续文章中会涉及到。

  你也许会犯的错误

  不知各位兄弟在刚刚接触MVC的时候,有没有碰到过这样的问题,如下图

那么这个错误是如何引起的了?代码是这么写的

namespace MvcDebug.Controllers
{
public class HomeController : Controller
{
public ActionResult Index(string id,string catchall)
{
ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。"; return View();
}
}
} namespace MvcDebug.Controllers.Tauruswu
{
public class HomeController : Controller
{
public ActionResult Index(string id, string catchall)
{
ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。"; return View();
}
}
}

我们再看英文提示大概就是说匹配出了多个控制器为"Home"的类型,在它的提示中也告诉了我们解决方法,说在MapRoute方法中使用"namespaces"这个参数,我们先将这个放在一边,将抛出这个错误的源码给找出来,具体的源码在DefaultControllerFactory这个类中,看类名就能猜出它的作用是什么了。

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
{
  // Once the master list of controllers has been created we can quickly index into it
  ControllerTypeCache.EnsureInitialized(BuildManager);   ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
  switch (matchingTypes.Count)
  {
    case :
  // no matching types
  return null;    case :
  // single matching type
  return matchingTypes.First();   default:
  // multiple matching types
  throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
  }
}

上面粗体标出的代码,因为我们在路由中没有配置“namespaces”这个参数,这段代码的意思就是通过控制器名称获取所匹配的控制器类型集合,当获取到集合数据之后就开始Case了,很明显,这里集合的数目是2,自然就抛错了。

  问题出来了,该如何解决?在错误提示中说要用到“namespaces”这个参数,我们能不能告诉MVC解析引擎,在解析控制器名称时,能不能对某些命名空间进行优先处理,事实上是可以的,只需要在配置路由的地方稍微调整一下

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}/{*catchall}",
  defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  namespaces: new[] { "MvcDebug.Controllers.Tauruswu" }
);

上面标粗的代码的意思是说优先解析“MvcDebug.Controllers.Tauruswu”这个命名空间里面的控制器。

  路由约束

  对于路由约束,我个人觉得这个可能在实际开发中用的不是很多,既然MapRoute方法提供了constraints这个参数及约束,那么在某些特定的场合肯定能发挥它的作用。在MVC中提供了三种路由约束方案,分别是: 1)正则表达式 ,2)http方法 ,3)自定义约束 。下面我们分别介绍下这三种约束的使用方法。

  1)正则表达式 ,在路由配置中,我们做了这样的规则,只匹配Controller名称以H开头的

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}/{*catchall}",
  defaults: new { controller = "Demo", action = "Index", id = UrlParameter.Optional },
  constraints: new { controller = "^H.*" },
  namespaces: new[] { "MvcDebug.Controllers.Tauruswu" }
);

  2) http方法 ,我们将路由配置稍作修改

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}/{*catchall}",
  defaults: new { controller = "Demo", action = "Index", id = UrlParameter.Optional },
  constraints: new { httpMethod = new HttpMethodConstraint("POST"), },
  namespaces: new[] { "MvcDebug.Controllers.Tauruswu" }
);

然后在对应的Action上面打个标记

[HttpGet]
public ActionResult Index()
{
  ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。";   return View();
}

你们说这样行不行了?

  3) 自定义约束,如果说上面两种需求还是不能满足你,那么我们可以自定义约束。我们翻看HttpMethodConstraint这个类,可以看到它是继承IRouteConstraint这个接口,其定义是

public interface IRouteConstraint
{
  bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
}

里面只有一个布尔类型的方法,关于这个例子,是从网上借鉴过来的,如下

public class CustomConstraint : IRouteConstraint
{
  private string requiredAgent;   public CustomConstraint(string agentArgs)
  {
    this.requiredAgent = agentArgs;
  }   public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
  {
    return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(requiredAgent);
  } }

这段代码的意思就是检查客户端请求的UserAgent属性值,看它是否含有一个被传递给构造函数的值。那么我们将路由作如下修改

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}/{*catchall}",
  defaults: new { controller = "Demo", action = "Index", id = UrlParameter.Optional },
  constraints: new { customConstraint = new CustomConstraint("IE"), },
  namespaces: new[] { "MvcDebug.Controllers.Tauruswu" }
);

很显然,这个只能在IE游览器下面游览。

  如何创建自定义路由处理程序

  在翻阅MapRoute方法源码的时候,看到了这么一段

Route route = new Route(url, new MvcRouteHandler())
{
  Defaults = CreateRouteValueDictionary(defaults),
  Constraints = CreateRouteValueDictionary(constraints),
  DataTokens = new RouteValueDictionary()
}; .....
routes.Add(name, route);

在Route实例化的时候,它是用到了“MvcRouteHandler“这个类,该类继承”IRouteHandler“接口,如果我们不用系统里面已经定义好的路由处理方案,我们要自己来实现一套?改怎么下手,此时只需要继承”IRouteHandler“这个接口并实现”GetHttpHandler“方法即可。

  最后在添加路由时,像这样操作

routes.Add(new Route("DemoUrl",new DemoRouteHandler());

当我们在游览器里面请求/DemoUrl这个地址时,就会用到我们自定义的处理程序,在实际开发当中,如果真的要用到自定义路由处理程序,那么我们就要实现很多原本框架所实现的空能,虽然这给我们带来了很大的扩展空间,但是又不可控。

  总结

  Url路由系统是通过请求地址进行解析从而得到以目标Controller/Action名称为核心的路由数据,Url路由系统是建立在Asp.net 之上,我们在调试System.Web.Routing的源码时候可以得知。在这里我们由浅入深的了解了路由系统,接下来我们会讲到控制器以及Action,也是最为核心的东西。

Asp.Net MVC4 之Url路由的更多相关文章

  1. 【转】Asp.Net MVC4 之Url路由

    MVC4常见路由的处理方式 //直接方法重载+匿名对象 routes.MapRoute( name: "Default", url: "{controller}/{act ...

  2. Asp.Net MVC2.0 Url 路由入门---实例篇

    本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...

  3. Asp.Net MVC2.0 Url 路由入门---实例篇 【转】

    本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...

  4. ASP.NET MVC4学习笔记路由系统概念与应用篇

    一.概念 1.路由是计算机网络中的一个技术概念,表示把数据包从一个网段转发至另一网段.ASP.NET中的路由系统作用类似,其作用是把请求Url映射到相应的"资源"上,资源可以是一段 ...

  5. ASP.NET MVC 的URL路由介绍

    在这个教程中,向你介绍每个ASP.NET MVC一个重要的特点叫做URL路由.URL路由模块是负责映射从浏览器请求到特定的控制器动作. 在教程的第一部分,你将学习标准路由表如何映射到控制器的动作.在教 ...

  6. ASP.NET MVC4学习笔记路由系统实现

    一.路由实现 路由系统实际是一个实现了ASP.NET IHttpModule接口的模块,通过注册HttpApplication的PostResolveRequestCache 事件对Url路由处理.总 ...

  7. ASP.NET MVC4实现URL伪静态

    1.在Web.config添加节点配置: <system.webServer> <modules runAllManagedModulesForAllRequests="t ...

  8. ASP.NET MVC5(一)—— URL路由

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

  9. IIS 7.5 + asp.net MVC4 设置路由处理URL请求

    使用asp.net MVC4开发的网站,在本地的VS012环境下运行,一切正常.但当发布到Windows 2008 R2(IIS7.5 + Framework4.5)上时,访问相关网页时,出现有下面的 ...

随机推荐

  1. bzoj2956: 模积和(数论)

    先算出无限制的情况,再减去i==j的情况. 无限制的情况很好算,有限制的情况需要将式子拆开. 注意最后的地方要用平方和公式,模数+1是6的倍数,于是逆元就是(模数+1)/6 #include<i ...

  2. Linux基础-----------nginx安装和nginx web、nginx反向代理、nfs 服务

    作业一:nginx服务1)二进制安装nginx包 yum install epel-release -y 先安装epel-release 再查看yum源中已经安装上了epel相关文件 中间省去了一些安 ...

  3. 《剑指offer》— JavaScript(11)二进制中1的个数

    二进制中1的个数 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路一 用1和n进行位运算,结果为1则n的二进制最右边一位为1,否则为0: 将n二进制形式右移1位,继续与 ...

  4. centos 前端环境搭建

    Node.js 安装 wget 下载安装 yum -y install gcc make gcc-c++ openssl-devel wget node v6.11.0 下载 wget https:/ ...

  5. 【转】解决virt-manager启动管理器出错:unsupported format character

    来源:http://blog.csdn.net/z_yttt/article/details/71192144 经验证OK.   今天打开virt-manager出错,报错信息如下: 启动管理器出错: ...

  6. APP的数据采集与埋点方式分析

    前言: 神策数据写过几篇分析APP前后端埋点的文章,原文在此: https://sensorsdata.cn/blog/shu-ju-jie-ru-yu-mai-dian/ http://www.wo ...

  7. libuv移植到android

    编译环境是linux + ndk,你要先添加好NDK路径的环境变量,然后进入libuv目录执行以下两句完成编译. $ source ./android-configure $NDK gyp $ mak ...

  8. HDU 3977 斐波那契循环节

    这类型的题目其实没什么意思..知道怎么做后,就有固定套路了..而且感觉这东西要出的很难的话,有这种方法解常数会比较大吧..所以一般最多套一些比较简单的直接可以暴力求循环节的题目了.. /** @Dat ...

  9. PHP扩展--XHProf优化PHP程序

    简介 XHProf 是一个轻量级的分层性能测量分析器. 在数据收集阶段,它跟踪调用次数与测量数据,展示程序动态调用的弧线图. 它在报告.后期处理阶段计算了独占的性能度量,例如运行经过的时间.CPU 计 ...

  10. 理解 CSS 中的伪元素 :before 和 :after

    CSS 的主要目的是给 HTML 元素添加样式,然而,在一些案例中给文档添加额外的元素是多余的或是不可能的.事实上 CSS 中有一个特性允许我们添加额外元素而不扰乱文档本身,这就是“伪元素”. 你一定 ...