zoukankan      html  css  js  c++  java
  • asp.net MVC URL路由入门指南

    asp.net MVC 的URL路由是一个非常强大的功能,而且有个优点:强大单不复杂。然而,目前我在网上看到的相关资料,却都仅仅提供一些示例,仅通过这些示例,初学者基本上不可能明白为什么要这么配置,更不用说灵活运用了。
    这篇文章将采取循序渐进的方式,来解释MVC URL路由的配置方法,使初学者能够完全掌握MVC URL路由的配置方法。
    阅读本文的用户必须有如下基础:
    1、熟悉C#;
    2、能够通过Visual Studio建立asp.net MVC项目;
    3、能够在MVC项目中创建Model、Controller、Action和View。
    4、对url的结构有明确的认识。

    基于上述几点,本文的读者应该是熟悉Asp.net web开发的MVC初学者。如果阅读中发现有理解困难的地方,请自行补充上述知识。

    本文使用Asp.net MVC4作为示例。
    一、默认路由
    项目的默认路由如下:
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    这条路由实际上是使用命名参数的方式调用routes这个对象的MapRoute方法。上述的代码也可以这么写:
    routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
    这个方法有三个参数:name、url和defaults。
    name这个参数表示本条路由信息的名称,必须为唯一,如果有重复,则网站启动时会出现以下错误:


    图片1:路由名称重复

    URL表示本条路由信息的URL模板。这里引入一个术语:URL模板。

    "{controller}/{action}/{id}"这个URL模板表示url由三部分组成:controller、action和id,每一部分之间用斜杠(/)分割。对于一个形如:

    http://www.xxx.com/aaa/bbb/cc 的url,aaa就表示controller,bbb就表示action,cc就表示id。如果有一个名为aaa的Controller,这个Controller中有一个名为bbb的Action,这个Action接收一个名为id的参数,那么当我们访问:

    http://www.xxx.com/aaa/bbb/cc 这个url时,MVC就会调用aaaController中的bbb方法,并把cc作为参数id的值传递进去。
    defaults表示如果模板中的某个项目缺失,则用指定的值来设置这个项的值。
    例如:如果我们访问的URL如下:
    http://www.xxx.com/aaa/bbb
    也就是没有参数id,那么bbb这个方法的参数id就会用defaults中的值代替,这里一般为null。如果bbb的这个参数是值类型,那么就会报错:

    图片:参数不能为null

    为了防止这种情况,有以下两种处理方法:
    1、路由中为值类型的参数设置默认值,而不是使用UrlParameter.Optional;
    2、在action的定义中避免使用值类型的数据,如果必须使用,则使用此值类型的Nullable泛型。

    如果我们访问的URL如下:
    http://www.xxx.com/aaa
    也就是同时没有了action和id,那么这两个项目都会用defaults中的值代替,也就是会访问aaaController中的Index方法,并传递一个null的id。
    同理,如果仅仅输入域名,那么就会访问HomeController中的Index方法,并传递一个null的id。

    下面对默认路由进行一点点改动,改动后如下:
        routes.MapRoute(
            name: "Default",
            url: "{action}/{controller}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    问题一:请写出访问如下URL时,访问了哪个controller的哪个action,传递了什么参数。
    1、http://www.xxx.com/aaa/bbb/cc
    2、http://www.xxx.com/aaa/bbb
    3、http://www.xxx.com/aaa
    4、http://www.xxx.com
    答案在本文最后。

    简单总结一下:
    当用户输入的URL和某条路由规则中的url模式匹配时,根据这个url模式在输入的URL中查找url模式中的项目,如果查找不到,则用默认值代替。

    二、参数传递
    1、基本类型的参数传递。
    如果在aaaController中有一个叫做ddd的action,方法定义如下:
    public ActionResult ddd(string dParam)
    这个action并不接收参数id,而是接收一个叫做dParam的string型参数。如果要访问这个action,则url应该如下:
    http://www.xxx.com/aaa/ddd?dParam=xxx
    这样,ddd这个action中的dParam参数的值就会被设置为字符串xxx。
    如果我们访问的url如下

    如果我们访问的url如下:
    http://www.xxx.com/aaa/ddd?dParam=xxx&cParam=yyy
    这里url中多了一个名为cParam的值,但是ddd这个action的定义中并不包含这个参数,那么路由系统就会把cParam这个参数忽略。

    再看一个url:
    http://www.xxx.com/aaa/ddd
    这个url后面没有带任何参数,那么ddd这个action中所需的参数dParam就会被设置为null。


    2、对象类的参数传递。
    再看一种情况。如果在aaaController中有一个叫做ObjectParam的action,方法定义如下:
    public ActionResult ObjectParam(ObjectModel objModel)
    ObjectModel的定义如下

        public class ObjectModel
        {
            int ObjParamInt { get; set; }

            string ObjParamString { get; set; }
        }

    如果我们访问如下url:
    http://www.xxx.com/aaa/ObjectParam?ObjParamInt=10&ObjParamString=xxx
    那么,在ObjectParam这个方法中,参数objModel中对应属性的值就会被设定为url中对应的值。但是如果url中的值类型和对象中的对应字段的类型不一致,则会忽略url中的值。
    例如,如果我们访问如下url:
    http://www.xxx.com/aaa/ObjectParam?ObjParamInt=def&ObjParamString=xxx
    那么参数objModel中ObjParamInt这个属性就不会被赋值,它的值就是int型数据的默认值:0。

    另外,还要注意一点,url参数中的各个项目的大小写必须和对象中的一致。
     请回答下面问题:
    问题二:在默认路由情况下,请写出访问如下URL时,参数的状态。
    http://www.xxx.com/aaa/ObjectParam
    答案在本文最后。

    三、特殊路由
    我们把默认路由修改为如下所示:
        routes.MapRoute(
            name: "Default",
            url: "{controller}-{action}-{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

    也就是把默认路由中的斜杠“/”换成了减号“-”。先用如下URL测试:
    http://www.xxx.com/aaa-bbb-ccc
    这时就会访问aaaController中的bbb这个action,同时把ccc作为参数id的值传递进去。
    还记的第一部分的总结吗:当用户输入的URL和某条路由规则中的url模式匹配时,根据这个url模式在输入的URL中查找url模式中的项目,如果查找不到,则用默认值代替。
    我们试验一下修改后的路由如果在url中省略某个参数会是什么情况:
    http://www.xxx.com/aaa-bbb
    访问后出现如下错误:


    图片3:找不到文件

    同样,如果用以下URL,也找不到aaaController中的Index方法:
    http://www.xxx.com/aaa
    也会出现上述错误。
    出现这个错误的原因是,在默认路由中,各项目之间的分割符是斜杠“/”,而修改后的路由中,分割符是减号“-”。但是在MVC的路由系统中,只认为斜杠是分隔符,其他任何字符都仅仅作为模式字符串。当我们用这两个URL

    访问的时候,路由系统认为找不到合适的路由模式,所以就把这个URL作为一个静态请求传递出去,当然这个路径是不存在的。这里“合适的路由模式”应该是三个字符串用减号连接,而且三个字符串中的任意一个都不能为空。

    所以如果我们设计的路由没有用斜杠作为分隔符,那么URL模式中项目就无法使用defaults中的默认值。

    四、进阶版
    先把我总结出来的URL模板规则写出来:
    1、花括号对“{}”之间的字符串为路由项目;
    2、斜杠“/”为分隔符;
    3、其它任何字符都是固定字符,必须在固定的位置出现。
    先用这三条来验证默认的路由:
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    可以看到,默认路由中有三个被花括号包裹起来的项目,他们是:controller、action和id
    这三项之间用斜杠分割。

    再验证一下修改后的路由:
        routes.MapRoute(
            name: "Default",
            url: "{controller}-{action}-{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    这条路由中有三个被花括号包裹起来的项目,他们是:controller、action和id,他们之间各有一个固定字符减号“-”。
    那么既然花括号中的字符串都为路由项目,那么,controller和action这两个项目和其他项目相比就没有任何特殊之处,也就意味着,这两个项目也不是必须的。那么我们可以这么定义一条路由规则:
        routes.MapRoute(
            name: "AboutUs",
            url: "AboutUs.html",
            defaults: new { controller = "Home", action = "AboutUs" }
        );
    这条路由意味着如果用户访问AboutUs.html这个文件,将执行HomeController中的AboutUs这个action。
    看到了吗?这就是利用url路由实现的伪静态。
    问题三:假设我们NewsCenterController中有一个NewsDetail的action,这个action定定义如下:
    public ActionResult NewsDetail(long newsID)
    请试着定义一条路由规则,实现用如下url访问NewsDetail这个action:
    http://www.xxx.com/NewsContent_100.html
    其中数字100是newsID。
    答案在本文最后。

    五、路由顺序
    在MVC的路由系统中,可以定义多条路由规则,多条路由规则的name属性,如下:

        routes.MapRoute(
            name: "AboutUs",
            url: "AboutUs.html",
            defaults: new { controller = "Home", action = "AboutUs" }
        );

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

    当MVC的路由系统接收到一个url时,路由系统就会按照书写的顺序,对每一条路由规则中的路由模式进行匹配,只要发现某一条路由规则中的模式符合当前url时,就使用这条路由规则来处理当前url,后面的路由规则在此次处

    理中就会忽略。
    假设我们的路由规则中有如下两条:

        routes.MapRoute(
            name: "Default1",
            url: "{action}/{controller}/{id}",
            defaults: new { controller = "Home", action = "AboutUs" }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    那么,后面一条路由无论何时都不会被使用。

    问题答案:
    问题一:
    这个问题的路由配置如下:
        routes.MapRoute(
            name: "Default",
            url: "{action}/{controller}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    由于这个问题的路由配置中,路由模式为:{action}/{controller}/{id},所以第一个项目是action,第二个项目为controller,第三个项目为id,因此答案如下:
    1、http://www.xxx.com/aaa/bbb/cc  访问了bbbController的aaa这个action,传递给参数id的值为cc
    2、http://www.xxx.com/aaa/bbb 访问了bbbController的aaa这个action,传递给参数id的值为null
    3、http://www.xxx.com/aaa 访问了bbbController的Index这个action,传递给参数id的值为null
    4、http://www.xxx.com 访问了HomeController的Index这个action,传递给参数id的值为null

    问题二:
    这个问题使用的url如下:
    http://www.xxx.com/aaa/ObjectParam
    这个url访问了aaaController的ObjectParam这个action,但是没有传递任何参数,所以ObjectParam参数中ObjectModel这个对象的值均为默认值,即:
    ObjParamInt = 0
    ObjParamString = null

    问题三:
    路由应该如下配置:
        routes.MapRoute(
            name: "NewsContents",
            url: "NewsContent_{newsID}.html",
            defaults: new { controller = "NewsCenter", action = "NewsDetail", newsID = 0 }

  • 相关阅读:
    ctags cscope
    u-boot initf_bootstage函数分析
    u-boot log_init函数分析
    u-boot v2018.01 启动流程分析
    DECLARE_GLOBAL_DATA_PTR
    CaptchaCodeManager
    UserTokenManager JwtHelper
    AdminSwagger2Configuration
    logService
    AdminWebSessionManager AdminAuthorizingRealm ShiroConfig ShiroExceptionHandler
  • 原文地址:https://www.cnblogs.com/liu-binq63/p/4980206.html
Copyright © 2011-2022 走看看