MVC路由学习:自定义路由参数(用户看不到参数名),重新定义路由规则
MVC路由:由于路由global中注册了,在程序第一次运行时,在MVC会自动生成路由,类似于字典的格式缓存下来,但路由生成的规则又是怎样的呢?
路由生成规则是:
1》更具你定义的的顺序查找路由规则,如果有匹配的,就会生成路由,生成一条后,不会继续查找下去,结束第一条路由的生成,从而接着一样的方法第二第三条生成
2》那是怎么查找路由的呢?我们来看下面代码来解释:
routes.MapRoute( name: "Test", url: "{controller}/{action}/{param1}", defaults: new { controller = "Test", action = "Index", param1 = UrlParameter.Optional, }, constraints: new { controller = "^Test.*", action = new ActionConstraints(),// "^transfer.*", param1 = @"\d+", } );
1》在这里假设我们当前路由是在顺序的第一,一开始在读取路由规则,都是先读这条,如果你的constraints规则不适应才会寻找下一跳生成路由,如果符合,就会直接生成路由,接着重新遍历这规则,生成下一跳路由
一,项目有需求将项目地址中的参数名不显示给用户看
在MVC定义一个方法:
public ActionResult GetUserInfo(string Name, string Grade) { ViewBag.Name = Name; ViewBag.Grade = Grade; return View(); }
根据一般请求路径,我们请求的地址为:http://localhost:17273/Home/GetUserInfo?Name=1&Grade=1&Course=1,如果需要不显示参数名,将地址改成这种http://localhost:17273/Home/GetUserInfo/1/1/1形式,而此时我们需要添加路由规则
1>找到MVC的路由文件RouteConfig.cs
2>在文件中添加一条路由,如下
routes.MapRoute( name: "Querylll", url: "{controller}/{action}/{Name}/{Grade}/{Course}", defaults: new { controller = "Home", action = "Index", Name = UrlParameter.Optional, Course = UrlParameter.Optional }, namespaces: new string[] { "RouteDemo.Controllers" } );
UrlParameter.Optional的定义是允许不传,造成结果是:http://localhost:17273/Home/GetUserInfo/1/1这条路由也是可以寻到该页面
3>我们定义一个新的方法测试以上结论如下:
public ActionResult GetList(string Name, string Grade, string Course) { ViewBag.Name = Name; ViewBag.Grade = Grade; ViewBag.Course = Course; return View(); }
PS:但我们需要注意的一点就是:如果你需要第三个字(Course)不为空值,我们必须要传Grade,因为根据路由规则,我们是通过URL的位置匹配参数
4>那我们使用实体接受是否可以?如下:
public ActionResult GetListModel(UserName u) { ViewBag.Name = u.Name; ViewBag.Grade = u.Grade; ViewBag.Course = u.Course; return View(); } public class UserName { public string Name { get; set; } public string Grade { get; set; } public string Course { get; set; } }
PS:实体的定义也需要符合参数循序和规则
二,到此时,就有疑问了,如果我们的参数明会变化,那我们不就需要N条路由?这明显不合理,那以上路由就需要改进了,如下
routes.MapRoute( name: "Query", url: "{controller}/{action}/{param}/{param1}/{param2}", defaults: new { controller = "Home", action = "Index", param = UrlParameter.Optional, param1 = UrlParameter.Optional, param2 = UrlParameter.Optional }, namespaces: new string[] { "RouteDemo.Controllers" } );
调用和获取的方法:
public ActionResult GetListModel(UserName u) { u.Name = isNull("param") ? u.Name : QueryString("param").ToString(); u.Grade = isNull("param1") ? u.Grade : QueryString("param1").ToString(); u.Course = isNull("param2") ? u.Course : QueryString("param2").ToString(); ViewBag.Name = u.Name; ViewBag.Grade = u.Grade; ViewBag.Course = u.Course; return View(); } public object QueryString(string paramname) { return System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values[paramname]; } public bool isNull(string param) { return QueryString(param) == null ? true : false; }
PS,这条路由解决了参数定义的顺序问题和参数名字变化等需求问题,若同一个方法有五个参数,但是当被调用时,传如参数可能是1个,2个等情况
三,那如果我们要写一个路由,只能是某一个控制器,并且是该控制器下某些方法可用,这是路由该怎么定义?如下代码:
routes.MapRoute( name: "Test", url: "{controller}/{action}/{param1}/{param2}/{param3}/{param4}", defaults: new { controller = "Test", action = "Index", param1 = UrlParameter.Optional, param2 = UrlParameter.Optional, param3 = UrlParameter.Optional, param4 = UrlParameter.Optional, }, constraints: new { controller = "^Test.*", action = new ActionConstraints(),// "^Test.*", } );
我们需要在constrationts定义controllers的默认值即可,action我们就需要使用正则来判断,如下代码
public class ActionConstraints : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { string val = values[parameterName].ToString(); if (Regex.IsMatch(val, "^Test.*", RegexOptions.IgnoreCase) || Regex.IsMatch(val, "^Index.*", RegexOptions.IgnoreCase)) { return true; } return false; } }
^Test.表示当action前缀为Test都返回true,则可以使用这条路由
PS:如果想以上这种路由没有定义controllers规则,属于主路由,主路由不可以定义在从路由之前,这样如果生成匹配了主路由,从路由就不会生成,则你定义的规则就不会被实现
四,一个基于属性的路由配置工具使用博客AttributeRouting,可以给特定的action定义路由特定的规则:AttributeRouting
[GET("test/ddd/{a}/{b}")] public ActionResult TestRouting(string a, string b) { ViewBag.Name = a; ViewBag.Grade = b; return View(); }