学习路由和数据传递

ASP.NET MVC 路由组成部分

理解路由概念

  • 路由,源自网络中路由器概念。负责分配网络中数据传输的路径
  • ASP.NET MVC 路由系统主要职责是:将各种URL请求转发给控制器处理。

例如:
这里给定了两个路径:

/book/detail/3.html
/account/login

第一个路径:/book/detail/3.html中控制器为book,动作方法为detail()
第二个路径:/account/login中控制器为account,动作方法为login()
由此可以了解到,路由系统是将请求通过分配不同控制器调用动作方法来执行命令。

掌握路由组成部分

routes.MapRoute() 路由完整定义

下面是一个完整的ADO.NET项目中的完整路由定义:

MapRoute(
	string name,//名称
	string url,//URL模式
	object defaults,//默认值
	object constraints,//约束
	string[] namespaces//命名空间
)

name :路由器名称,区分不同路由配置
url:路由匹配方式
defaults:路由匹配方式中的默认值。
constaints:路由匹配方式中的约束,限制url的格式以及其他。
namespaces:去除路由匹配方式中的二义性,区分不同的路由来处理不同的请求。
后面这两个参数可以不指明。

URL模式匹配

路由定义

定义:

字面量{占位符}字面量{占位符}字面量…{占位符}字面量
字面量或占位符指的是任意字符字符串

下面给出三种URL模式:

 {table}/Details.aspx 
 Blog/{action}/{id}
 {lan}-{country}/{action}

带大括号的内容在请求的时候可以随意输入,但是不带大括号的值是必须输入成指定的。在这里面,“/”也属于固定字符。

路由匹配规则

特殊规则

  • 不能以"/“或”~“开头,整体不能包含”?"

例子:`

/{controller} //错误
~books/detail{id}//错误
{action}?id={id}//错误
  • 占位符不能连续
    例子:
{controller}{action}/{id}//错误

大括号和大括号之间必须有固定字符,哪怕是斜杠也是属于我们的固定字符。

路由匹配规则

  • URL模式匹配原理

URL模式:

{controller}/{action}/{id}

实际URL

http://localhost/Home/Index/1

其中的:
{controller}与实际URL中的Home相互对应。
{action}与实际URL中的Index相对应。
{id}与实际URL中的1相对应。

URL模式:

blogs/{action}/{id}

实际URL

http://localhost/blogs/edit/2

其中的blogs是必须带的允许修改,在实际URL中也不允许修改
{action}与实际URL中的edit相对应
{id}与实际URL中的2相对应

路由匹配

  • 按顺序将请求路径中的内容映射到占位符
  • 字面量必须严格匹配
  • URL模式不区分大小写

“*”匹配URL剩余部分

"{controller}/{action}/{query-name}/{*plus}"

以上面的URL定义,我们给出三种URL:
URL1:

/home/index/select/a/b

上面的URL中,home对应的是URL定义中的{controller}.,
index对应的是URL定义之后的{action},
最后a/b对应的就是带“*”的plus.
也就是匹配不上的部分,都归plus所有。
URL2:

/home/index/select/

上面的URL中,home对应的是URL定义中的{controller}.,
index对应的是URL定义之后的{action},
之后的puls的值就是null;
因为定义之中的plus有大括号代表着占位符,但是没有值,所以plus的值是null。

贪婪匹配规则

我们分析一下URL和URL模式还有路由数据:
URL为

/food.xml.aspx

URL模式为:

{filename}.{ext}

路由数据

filename = "food.xml"
ext = "aspx"

观察一下URL中有两个".“但是在URL模式中只有一个”.",在看读取出的路由数据中,是将URL分为两个部分,前面的"food.xml"是占位符filename的值,而后面的aspx为占位符ext 的值。
可以得出,在这种情况下,URL会自动识别最后的一个".“然后以最后一个”."为分界线,前的所有内容为前面占位符的,后面的内容为后面占位符的。

URL为

/xyzxyzxyzABCD

URL模式为:

{foo}xyz{bar}

路由数据则为:

foo="xyzxyz"
bar="ABCD"

在这种情况下:
三个xyz中,foo获取到的是前两个,所以foo的值是xyzxyz。
当然如果出现了这三个xyz相同字符重复,作为字面量xyz,系统在自动确认最后一个xyz为字面量,自动对应占位符foo的值为xyz。
后面一个,bar自动对应的是ABCD。

例子实现代码如下:
RouteConfig.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace ch0301
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{a}abc{c}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }//包含了控制器,动作方法
            );
        }
    }
}

HomeController.cs

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

namespace ch0301.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

    }
}

Index.aspx

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
            controller:<%=RouteData.Values["controller"] %><br/>
            action:<%=RouteData.Values["action"] %><br />
            id:<%=RouteData.Values["id"] %><br />
          
        
            a:<%=RouteData.Values["a"] %><br/>
            b:<%=RouteData.Values["b"] %><br />
            c:<%=RouteData.Values["c"] %><br />

            a:<%=RouteData.Values["a"] %><br />
            c:<%=RouteData.Values["c"] %><br />
    </div>
</body>
</html>

路由默认值

路由默认值

路由默认值:defaults属性中默认指明了信息。

  defaults: new 
  { 
  	controller = "Home", 
  	action = "Index",
  	id = UrlParameter.Optional
	}

可以访问的UR的形式为:

http://localhost/home/index/1
http://localhost/home/index
http://localhost/home
http://localhost/

含默认值路由匹配规则

如果没有指明默认值,必须通过URL提供对应占位符参数

    routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults:new{action="index",id=0}

下面给出四中请求

1. /home //因为虽然没有设置默认值,但是我们已经给了action,id,这两个占位符赋了初始值,然后再提供控制器,所以就匹配成功
2. /home/index //同样如上,已经给定了id占位符的初始值,我们只用给定controller和action的值。
3. /home/index/2 //第三个将controller,action,id,都给定,相当于给了一个完整的url,所以能匹配成功
4. /

这四种请求能被匹配的是1,2,3。
第四个没有办法匹配:
因为第四个请求只给定了一个固定字符,在输入请求的时候没有提供一个正确的controller,action,id的值,但是初始值我们已经给定 action,id,但因为缺失controller的值,导致系统不知道要去哪里寻找页面,所以会报错。

如果指明中间参数默认值,该中间参数默认值不起作用。

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

下面给定三种url,

1./home/index/2 //全部给定,完全可以匹配
2./book/detail/1//全部给定,完全可以匹配
 3./home/0

第三个为什么不能匹配?
因为电脑只能从左到右去匹配,home匹配controller,但是这个给定的“0”会被电脑自动匹配成为action占位符的参数,这样id就没有值,id有无确定值其实不太重要在现在这个阶段,主要是找不到action的值,相当于没有使用我们之前给定的action。

如果路由含有字面量时,默认参数不起作用。

 routes.MapRoute(
                "Default", 
               "{controller}-{action}", 
               new { action="index"}
                );

下面给他三种url请求:

1.home-index//url请求中包含了一套完整的控制器和动作方法。
2./home//不能匹配
3./home-//不能匹配

其中
第二个url请求因为只给定了controller控制器而且定义中存在字面量但是url请求中并没有该字面量存在,所以无法对应请求,所以无法匹配。
第三个url请去虽然存在这字面量字符,但是只提供了一个控制器。
其实如果想理解这句话的意思:路由含有字面量时,默认参数不起作用。
首先可以理解为默认参数提供的默认值可以看成默认的url,参数提供完全。
就如第三个例子说,计算机会去调用home,然后根据所给的action去寻找动作方法,但电脑会从左往右读取参数。在输入的时候要注意。根据如果路由含有字面量时,默认参数不起作用这一条,所以第三个不能成功匹配。
观察下列URL定义:

routes.MapRoute("Default",
               "{controller}/{action}+{id}/{no}",
               new { controller = "home",
                      action = "index",
                      id = "0",
                      no = "0" });

并给出以下URL请求:

1./home/index+1
2./home/index+10/N123
3./
4./home
5./home/index
6./home/index+


分析结果如下:
第一个给定了完整的控制器,动作方法和Id,所以能够匹配成功
第二个提供了完整的url,所以也匹配成功
第三个什么也没提供,但是我们默认值都给定了但是还是不能匹配成功,就是因为有字面量的存在,值得注意的是,上面例子中无效的是"{action}+{id}",其他的并不是被无效化。才会匹配不成功。
第四个与第三个同理,只给定了控制器。预设的参数又被无效化。
第五个因为给定了控制器和动作方法,但是没有把字面量给定,所以不能成功匹配。
第六个:
提供了控制器,动作方法,但是含有字面量的参数没有完全给定,所以匹配不成功。

总结

  • 没有指明默认值时,URL必须包含对应的路由参数。
  • 没有只指明路由中间参数时,该参数默认值不起作用
  • 如果包含字面量时,默认参数不起作用。

路由约束和命名空间

路由约束

假设我们有一个Blog系统,定义URL模式,可根据URL中“年月日”读取文章。
我们定义一个URL模式为:

{year}/{month}/{day}

但是输入的时候,我们错误的输入的不合逻辑的URL请求。

/2012/11/test

这样日期是字符串类类型,我们该怎么做来避免这种情况出现呢。
我们可以用constraints参数来设定URL约束。
例子如下:

   routes.MapRoute(
                 "bolg", "{year}/{month}/{day}",
                 new { controller = "blog", action = "index" },
                 constraints: new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" }
                );

这样就会避免出现以上情况。

命名空间

  • 区分不同区域中的路由访问的控制器,以免请求冲突。

例子如下:

  routes.MapRoute(
                name: "Default",
                url: "{year}/{mouth}/{day}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces:new string[]{"Ch03.Controllers"}

数据传递

如何从控制器向试图传递数据?
使用session不是理想选择。根据数据的不同.NET MVC 提供了三种数据传递对象。——ViewData,ViewBag,TempData

使用ViewData对象传递数据

  • 字典类型数据,通过键值对的形式来保存数据。
  • 视图基类和控制器基类的属性
  • viewData和viewBag数据相通。
  • 传递一次就失效
  • 适合传递单个数据,需要类型转换

使用ViewBag对象传递数据

  • dynamic(动态类型)类型数据
  • 视图基类和控制器基类的属性
  • viewBag和viewData数据相通
  • 传递一次就失效
  • -适合传递单个数据,不需要类型转换。

使用TempData对象传递

  • 字典类型数据,通过键值对的形式来保存数据。
  • 视图基类和控制器属性基类的属性。
  • TempData支持跨请求传递数据(跨控制器传递数据)
  • 默认的数据保存机制是Session
  • 在跨请求传递数据这个过程中,只要有一方拿到数据,TempData就会失效。
  • 只能在一次请求过程中有效,在下一个请求就会失效。
  • 主要用来跨多个动作方法传递数据

使用View()+Model形式传递数据

又称强类型视图传递

基本数据

  • 第一步 ,动作方法中v使用View()对象来传递Model数据
Book book = manager.GetBookById(id);
return View(book);
  • 第二步,视图声明为ViewPage类型
<%@ Page language="C#" MasterPageFile="~/Views/Shared/Site.Master"Inherits="System.Web.Mvc.ViewPage<BookShop.Models.Book>"%>
  • 第三步,在视图中使用Model对象获取数据
作者:<%=Model.Author%><br/>
出版社:<%=Model.Publisher.Name %>

适合传递模型数据,不需要类型转换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值