前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >精通MVC3摘译(3)-自定义路由系统

精通MVC3摘译(3)-自定义路由系统

作者头像
py3study
发布2020-01-03 11:19:59
5260
发布2020-01-03 11:19:59
举报
文章被收录于专栏:python3python3

路由系统非常灵活,但是如果这还不能满足你的 需求,那么,你可以定制路由系统。

创建基于RouteBase 的接口

如果你不喜欢标准路由对象匹配URL的方式,或者你想实现一些特殊的接口,你可以从RouteBase中继承一个类。让你可以控制URL匹配,参数如何解析,URL链接如何生成。从RouteBase继承,你需要实现2个方法:

GetRouteData(HttpContextBase httpContext):这是一个URL匹配工作机制。framework依次在每个RouteTable.Routes调用这个方法。直到其中一个返回non-null值。

GetVirtualPath(RequestContext requestContext, RouteValueDictionary values):  这是生成对外URL的工作机制。

在此,我们演示这种自定义方式,我们创建一个RouteBase类,该类会处理继承来的URL请求。假设我们从一个已经存在的application上移植到一个MVC Framework,但是一些用户已经收藏了之前的URL地址,并且在脚本中硬编码了。我们希望能继续支持老的URL。我们可以通过常规的路由系统处理,但是这里介绍一种更好的方法。

开始之前。我们需要建立一个controller,这个controller能接受之前的request。我们把它命名为LegacyController,如下:

代码语言:javascript
复制
using System.Web.Mvc;   namespace URLsAndRoutes.Controllers {      public class LegacyController : Controller {          public ActionResult GetLegacyURL(string legacyURL) {              return View((object)legacyURL);          }      }  }   

这是一个很简单的controller,GetLegacyURL action方法会将参数传递给View。如果我们要实现这个controller,我们需要使用这个方法来接受我们请求的文件,但是现在是简单的把这个URL展现在view中。

注意,上面我们已经为View方法转换了参数,View方法的其中一个重载方法接受一个string参数,该参数指定要显示的view的名字,如果不转变,那么C#编译器会认为我们是调用这个重载函数,为了避免这种情况,我们把它转换成object,这样的话我们可以调用调用另一个重载函数,该重载函数使用默认的view,并且传递view model值。我们也可以使用另一个重载方法,同时指定view name和view model,但这里,我们不希望action方法和view直接显式的关联。

GetLegacyURL.cshtml是和这个action关联的view,显示如下:

代码语言:javascript
复制
@model string  @{  ViewBag.Title = "GetLegacyURL";  Layout = null;  }  <h2>GetLegacyURL</h2> The URL requested was: @Model  

这个例子非常简单,我们只是演示自定义路由行为,所以我们不会去创建复杂的action和view。

路由接收到的URL

创建LegacyRoute类,如下:

using System;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

namespace URLsAndRoutes.Infrastructure

{

    public class LegacyRoute : RouteBase

    {

        private string[] urls;

        public LegacyRoute(params string[] targetUrls)

        {

            urls = targetUrls;

        }

public override RouteData GetRouteData(HttpContextBase httpContext)

        {

            RouteData result = null;

            string requestedURL =

            httpContext.Request.AppRelativeCurrentExecutionFilePath;

            if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))

            {

                result = new RouteData(this, new MvcRouteHandler());

                result.Values.Add("controller", "Legacy");

                result.Values.Add("action", "GetLegacyURL");

                result.Values.Add("legacyURL", requestedURL);

            }

            return result;

        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext,

        RouteValueDictionary values)

        {

            return null;

        }

    }

}

此类的构造函数,接受一个string数组,表示路由类将要支持的URL,之后,我们会在注册路由的时候指定它。上例中的GetRouteData方法,路由系统会调用它,以此判断是否要处理收到的URL。如果我们不处理这个请求,那么返回null,路由系统继续判断路由表中的下一个记录。如果可以处理,返回一个RouteData类的实例,该实例包含了controller和action变量。

当创建RouteData对象,我们需要在handler中传递值,我们使用标准的MvcRouteHandler类,此类指定了controller和 action的值:

result = new RouteData(this, new MvcRouteHandler());

对大多数的MVC应用程序来说,这个类是必须的,因为此类连结了路由系统和controller/action model。但是你可以实现一个类代替MvcRouteHandler。之后会讲到。

在这个路由实现中,我们路由了任何传递到构造函数的URL请求。当得到一个URL请求,我们为RouteValues的controller和action方法硬编码了一些值,传递了请求的URL作为legacyURL的属性。注意,属性的名字和我们action方法的参数名一致,这样保证了我们生成的值会通过参数传递给action方法。最后一步是用我们的RouteBase子类注册一个新的路由,如下代码:

public static void RegisterRoutes(RouteCollection routes) {

routes.Add(new LegacyRoute(

"~/articles/Windows_3.1_Overview.html",

"~/old/.NET_1.0_Class_Library"));

routes.MapRoute("MyRoute", "{controller}/{action}/{id}",

new { controller = "Home", action = "Index", id = UrlParameter.Optional });

}

我们实现了该类的实例,把我们想要路由的URL传给它。然后加入到RouteCollection集合。现在当我面请求一个我们定义的legacy URL,这个请求由我们的自定义类路由出来,并且定位到我们的controller。如下:

clipboard
clipboard

生成对外的URL

要支持对外URL的生成,我们需要实现GetVirtualPath方法。同样的,如果不能处理请求的,就通过返回null让路由系统。否则就返回VirtualPathData的实例。

public override VirtualPathData GetVirtualPath(RequestContext requestContext,RouteValueDictionary values)

        {

            VirtualPathData result = null;

            if (values.ContainsKey("legacyURL") &&

            urls.Contains((string)values["legacyURL"], StringComparer.OrdinalIgnoreCase))

            {

                result = new VirtualPathData(this,

                new UrlHelper(requestContext)

                .Content((string)values["legacyURL"]).Substring(1));

            }

            return result;

        }

我们使用匿名类型传递了片段变量和其他参数,但是这背后的事情是,路由系统会将这些值转换成RouteValueDictionary对象。所以,比如,我们下面view中的代码:

@Html.ActionLink("Click me", "GetLegacyURL", new { legacyURL =

"~/articles/Windows 3.1 Overview.html" })

和legacyURL属性一起生产的匿名类型转换成RouteValueDictionary类,包含相同的名称。在此类中,我们可以处理一个对外的URL请求,如果有个key命名为legacyURL,并且它的值是之前传递到构造函数的URL值中的一个。我们能进一步指定并检测controller 和action的值,但是对这个例子来说,也已经足够了。

如果我们得到一个匹配,创建一个新 VirtualPathData的实例,在引用中传递给当前对象和对外的URL。我们使用了UrlHelper类的Content方法,转换相对URL,使之能被浏览器处理。可惜,路由系统会预先加了一个额外的/在URL上,所以我们必须小心的处理掉这个/。

创建自定义路由Handler

在路由中,我们依赖的是MvcRouteHandler,因为它连结了routing system和MVC FrameWork。路由系统允许我们自定义我们的路由handler,通过实现IRouteHandler 接口。如下:

using System.Web;

using System.Web.Routing;

namespace URLsAndRoutes.Infrastructure

{

    public class CustomRouteHandler : IRouteHandler

    {

        public IHttpHandler GetHttpHandler(RequestContext requestContext)

        {

            return new CustomHttpHandler();

        }

    }

    public class CustomHttpHandler : IHttpHandler

    {

        public bool IsReusable

        {

            get { return false; }

        }

        public void Proce***equest(HttpContext context)

        {

            context.Response.Write("Hello");

        }

    }

}

IRouteHandler接口的目的是提供一个生成IHttpHandler接口的方法,其中IHttpHandler的作用是处理请求的。在此例中,非常简单,只是输出Hello到Client。我们在定义路由的时候可以注册自定义的handler。如下:

public static void RegisterRoutes(RouteCollection routes) {

routes.Add(new Route("SayHello", new CustomRouteHandler()));

    routes.MapRoute("MyRoute", "{controller}/{action}/{id}",

    new { controller = "Home", action = "Index", id = UrlParameter.Optional });

}

当请求URL/SayHello,我们的handler会处理该请求。

clipboard[1]
clipboard[1]

你可以实现自定义路由handler意味着你自己要对那些常用的方法负责,比如controller和action的处理方式,但是这也给你更多自由。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档