zoukankan      html  css  js  c++  java
  • Asp.Net MVC 路由

    原文链接:http://www.asp.net/learn/mvc/

    在这篇教程中,我将为你介绍每个ASP.NET MVC应用程序都具有的一个重要功能,称作ASP.NET路由(ASP.NET Routing)。ASP.NET路由模块负责将即将到来的浏览器请求映射到特定的MVC控制器动作。学完这篇教程之后,你将会理解标准的路由表是如何将请求映射到控制器动作的。

    1. 理解默认路由表

    当你创建一个新的ASP.NET MVC应用程序时,应用程序已经被配置为使用ASP.NET路由。ASP.NET路由在两个地方设置。

    第一点,在你的应用程序Web配置文件(Web.config文件)中启用ASP.NET路由。在配置文件中有四个节点与路由有关:sytem.web.httpModules节,system.web.httpHandlers节,system.webserver.modules节,以及system.webserver.handlers节。特别要小心不要删除了这些节点,因为没有它们路由将不能工作。

    第二点,也是更为重要的一点,在应用程序的Global.asax文件中创建了一个路由表。Global.asax文件是一个特殊的文件,它包含了作用于ASP.NET应用程序生命周期事件的事件处理程序。路由表在Application Start事件期间创建。

    代码清单1中的文件包含了一个ASP.NET MVC应用程序的默认Global.asax文件。

    代码清单1 - Global.asax.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace MvcApplication1
    {
        // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
        // visit http://go.microsoft.com/?LinkId=9394801
    
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
                );
    
            }
    
            protected void Application_Start()
            {
                RegisterRoutes(RouteTable.Routes);
            }
        }
    }

    当一个MVC应用程序首次运行时,会调用Application_Start()方法。这个方法随后调用了RegisterRoutes()方法。RegisterRoutes()方法创建了路由表。

    默认的路由表包含了一个路由(名叫Default)。Default路由将URL的第一部分映射到控制器名,URL的第二部分映射到控制器动作,第三个部分映射到一个叫做id的参数。

    假设你在浏览器的地址栏输入了下面的URL:

    /Home/Index/3

    默认的路由将这个URL映射为下面的参数:

    Controller = Home

    Action = Index

    id = 3

    当你请求URL /Home/Index/3时,将会执行下面的代码:

    HomeController.Index(3)

    Default路由包含了所有三个参数的默认值。如果你不提供控制器,那么控制器参数默认值为Home。如果你不提供动作,动作参数默认为值Index。最后,如果你不提供id,id参数默认为空字符串。

    让我们看看几个例子,Default路由是如何将URL映射到控制器动作的。设想你在浏览器地址栏输入了下面的URL:

    /Home

    由于Default路由参数的默认值,输入这个URL将会调用代码清单2中的HomeController类的Index()方法。

    代码清单2 - HomeController.cs

    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        [HandleError]
        public class HomeController : Controller
        {
            public ActionResult Index(string id)
            {
                return View();
            }
        }
    }

    在代码清单2中,HomeController类包含了一个叫做Index()的方法,它接受一个叫做Id的参数。URL /Home将会导致调用Index()方法,并使用空字符串作为Id参数的值。

    出于MVC框架调用控制器动作的方式,URL /Home也匹配代码清单3中HomeController类的Index()方法。

    代码清单3 - HomeController.cs(不含参数的Index动作)

    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        [HandleError]
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
        }
    }

    代码清单3中的Index()方法不接受任何的参数。URL /Home将会导致调用这个Index()方法。URL /Home/Index/3也会调用这个方法(Id被忽略)。

    URL /Home也会匹配代码清单4中HomeController类的Index()方法。

    代码清单4 - HomeController.cs(使用可空参数的Index动作)

    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        [HandleError]
        public class HomeController : Controller
        {
            public ActionResult Index(int? id)
            {
                return View();
            }
        }
    }

    在代码清单4中,Index()方法拥有一个整数参数。因为这个参数是一个可空参数(可以拥有Null值),因此可以调用Index()而不会引发错误。

    最后,使用URL /Home 调用代码清单5中的Index()方法将会引发一个异常,因为Id参数并非一个可空参数。如果你试图调用Index()方法,那么你将会获得一个图1中所示的错误。

    代码清单5 - HomeController.cs(含有Id参数的Index动作)

    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        [HandleError]
        public class HomeController : Controller
        {
            public ActionResult Index(int id)
            {
                return View();
            }
        }
    }

    图01: 调用一个期望参数值的控制器动作

    另一方面,URL /Home/Index/3 能够与代码清单5中的Index控制器动作很好地工作。/Home/Index/3请求将会引发调用含有一个Id的Index()方法,且该Id值为3.

    这篇教程的目的是为你提供一个ASP.NET路由的简短介绍。我们仔细查看了默认的路由表,它在你创建新的ASP.NET MVC应用程序时获得。你学习了默认的路由表如何将URL映射到控制器动作。

    2.创建自定义路由

    在这篇教程中,你会学习到如何为ASP.NET MVC应用程序添加自定义路由。你会学习如何将Global.asax文件中的默认路由表修改为自定义路由。

    对于简单的ASP.NET MVC应用程序,默认的路由表已经可以很好的完成工作了。然而,你可能发现会存在特定的路由需求。在这种情况下,你可以创建一个自定义路由。

    设想一下,举个例子,你正在创建一个博客应用程序。你可能想要像这样处理即将到来的请求:

    /Archive/12-25-2009

    当用户输入这一请求,你想要返回对应于日期12/25/2009的博客条目。为了处理这种类型的请求,你需要创建一个自定义路由。

    代码清单1中的Global.asax包含了一个新的自定义路由,命名为了Blog,它处理了类似/Archive/条目日期 这样的请求。

    代码清单1 - Global.asax(含有自定义路由)

    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace MvcApplication1
    {
    
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
    
                routes.MapRoute(
                    "Blog",                                           // Route name
                    "Archive/{entryDate}",                            // URL with parameters
                    new { controller = "Archive", action = "Entry" }  // Parameter defaults
                );
    
    
                routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
                );
    
            }
    
            protected void Application_Start()
            {
                RegisterRoutes(RouteTable.Routes);
            }
        }
    }

    添加到路由表中的路由顺序非常重要。我们的新自定义Blog路由在现有的Default路由前面。如果你将这个顺序颠倒过来,那么Default路由将总是被调用,而不是自定义路由。

    自定义Blog路由匹配任何以/Archive/作为开始的请求。因此,它匹配所有下面的URL:

    /Archive/12-25-2009

    /Archive/10-6-2004

    /Archive/apple

    自定义路由将即将到来的请求映射到名为Archive的控制器,并且调用了Entry()动作。当调用Entry()方法时,条目日期作为entryDate参数进行了传递。

    代码清单2 - ArchiveController.cs

    using System;
    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        public class ArchiveController : Controller
        {
    
            public string Entry(DateTime entryDate)
            {
                return "You requested the entry from " + entryDate.ToString();
            }
    
        }
    }

    注意到代码清单2中的Entry()方法接受一个DateTime类型的参数。MVC框架非常的聪明,足以自动地将URL中的条目日期转换为DateTime值。如果URL中的条目日期参数不能转换为DateTime,将会引发错误(如图1)。

    图1 - 转换参数时的错误

    这篇教程的目的是演示如何创建自定义路由。你学习了如何在Global.asax文件的路由表中添加自定义路由,该路由代表着博客条目。我们讨论了如何将对博客条目的请求映射到名为ArchiveController的控制器,和名为Entry()的控制器动作上。

    3.创建路由约束

    你可以使用路由约束来限制匹配特定路由的浏览器请求。可以使用正则表达式来指定一个路由约束。

    举个例子,假设你已经在Global.asax文件中定义了一个路由。

    代码清单1 - Global.asax.cs

    routes.MapRoute(
        "Product",
        "Product/{productId}",
        new {controller="Product", action="Details"}
    );

    代码清单1包含一个叫做Product的路由。你可以使用Product路由将浏览器请求映射到代码清单2中的ProductController。

    代码清单2 - ControllersProductController.cs

    using System.Web.Mvc;
    
    namespace MvcApplication1.Controllers
    {
        public class ProductController : Controller
        {
            public ActionResult Details(int productId)
            {
                return View();
            }
        }
    }

    注意到Product控制器公布的Details()动作接受一个叫做productId的参数。这个参数是一个整数参数。

    定义在代码清单1中的路由将会匹配下面的任意URL:

    • /Product/23
    • /Product/7

    不幸的是,路由也会匹配下面的URL:

    • /Product/blah
    • /Product/apple

    因为Details()动作期望的是一个整数值,发起一个含有非整数值的请求将会导致错误。举个例子,如果你在浏览器中输入/Product/apple URL,那么你将会得到图1所示的错误页。

     

    图1:错误页

    你实际想做的是只匹配包含合适整数productId的URL。当定义路由来限制与路由相匹配的URL时,你可以使用约束。代码3中的修改后的Product路由包含了一个正则表达式,它限制了只匹配数字。

    代码清单3 - Global.asax.cs

    routes.MapRoute(
        "Product",
        "Product/{productId}",
        new {controller="Product", action="Details"},
        new {productId = @"d+" }
     );

    正则表达式d+匹配一个或多个整数。这个限制使得Product路由匹配了下面的URL:

    • /Product/3
    • /Product/8999

    但是不匹配下面的URL:

    • /Product/apple
    • /Product

    这些浏览器请求将由另外的路由处理,或者,如果没有匹配的路由,将会返回一个“The resource could not be found”错误。

    4. 创建一个自定义路由约束

    这篇教程的目标是演示如何创建一个自定义路由约束。自定义路由约束允许你阻止某个路径被匹配,除非满足一些自定义的条件。

    在这篇教程中,我们创建了一个Localhost路由约束。Localhost路由约束只匹配本地计算机发出的请求。通过互联网发出的远程请求不会被匹配。

    你可以通过实现IRouteConstraint接口来实现一个自定义路由。这是一个极其简单的接口,它只描述了一个方法:

    bool Match(
        HttpContextBase httpContext,
        Route route,
        string parameterName,
        RouteValueDictionary values,
        RouteDirection routeDirection
    )

    这个方法返回一个布尔值。如果返回了false,与约束相关联的路由将不会匹配浏览器请求。

    Localhost约束包含在了代码清单1中。

    代码清单1 - LocalhostConstraint.cs

    using System.Web;
    using System.Web.Routing;
    
    namespace MvcApplication1.Constraints
    {
        public class LocalhostConstraint : IRouteConstraint
        {
            public bool Match
                (
                    HttpContextBase httpContext, 
                    Route route, 
                    string parameterName, 
                    RouteValueDictionary values, 
                    RouteDirection routeDirection
                )
            {
                return httpContext.Request.IsLocal;
            }
    
        }
    }

    代码清单1中的约束利用了HttpRequest类公布的IsLocal属性。当发出请求的IP地址是127.0.0.1或者与服务器的IP地址相同时,这个属性返回true。

    你在定义于Global.asax的路由中使用了自定义约束。代码清单2中的Global.asax文件使用了Localhost约束来阻止任何人请求Admin页面,除非他们从本地服务器发出请求。举个例子,当请求来自远程服务器时,对于/Admin/DeleteAll的请求将会失败。

    代码清单2 - Global.asax

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using MvcApplication1.Constraints;
    
    namespace MvcApplication1
    {
    
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterRoutes(RouteCollection routes){
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
    
                routes.MapRoute(
                    "Admin",
                    "Admin/{action}",
                    new {controller="Admin"},
                    new {isLocal=new LocalhostConstraint()}
                );
    
                //routes.MapRoute(
                //    "Default",                                              // Route name
                //    "{controller}/{action}/{id}",                           // URL with parameters
                //    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
                //);
            }
    
            protected void Application_Start(){
                RegisterRoutes(RouteTable.Routes);
            }
        }
    }

    Localhost约束使用在了Admin路由的定义中。这个路由不会被远程浏览器请求所匹配。然而,应该意识到定义在Global.asax中的其他路由可能会匹配相同的请求。理解这一点很重要:约束阻止了特定路由匹配某一请求,而不是所有定义在Global.asax文件中的路由。

    注意到Default路由在代码清单2中的Glabal.asax文件中被注释掉了。如果你包含Default路由,那么Default路由将会匹配对Admin控制器的请求。在这种情况下,远程用户仍然可以调用Admin控制器的动作,即使他们的请求不匹配Admin路由。

  • 相关阅读:
    HDU 1850 Being a Good Boy in Spring Festival
    UESTC 1080 空心矩阵
    HDU 2491 Priest John's Busiest Day
    UVALive 6181
    ZOJ 2674 Strange Limit
    UVA 12532 Interval Product
    UESTC 1237 质因子分解
    UESTC 1014 Shot
    xe5 android listbox的 TMetropolisUIListBoxItem
    xe5 android tts(Text To Speech)
  • 原文地址:https://www.cnblogs.com/superfeeling/p/4863486.html
Copyright © 2011-2022 走看看