MVC 路由扩展 实例

之前写了一篇《MVC路由机制》,今天想了一个实例来加强一下,这才对得起观众。让大家能够系统的理解MVC的路由机制。

扩展思路

  从上一篇文章(MVC路由机制)中,我们可以比较容易的发现,UrlRoutingModule通过遍历RouteTable.Routes中的路由对象来获取匹配的RouteData,从而将请求转发到相应的IHttpHandler处理程序。从整个过程中,我们可以从三个地方对MVC的路由进行扩展:Route,IRouteHandler和IRouteConstraint。

  简单回顾一下:

  Route:它继承实现RouteBase。RouteTable.Routes是一个RouteBase对象集合,可向集合中添加任何RouteBase的子类。所以,我们可以通过创建一个RouteBase的子类,然后将其添加到RouteTable.Routes集合中,以此实现自定义路由规则。

  IRouteHandler:UrlRoutingModule在获取到合适的RouteData后,将通过其RouteHandler属性来获取实际的IHttpHandler对象,通过IHttpHandler来处理请求。

  IRouteConstraint:IRouteConstraint接口由Route类的Constraints属性使用,用于判断当前的Url是否符合路由的约束条件。

实验场景

  对于特殊后缀的处理,比如".do"

  1. 网站url只能使用.do结尾。

  2.对于".do"结尾的url进行特殊处理,非".do"页面正常处理(这个有一定的应用场景)。

程序实现

     1. 我们采取自已写一个Route,然后将它加入RouteTable就可以了。

  a. 写route.

using System.Web;

using System.Web.Routing;
using System.Web.Mvc;

namespace RoutStudy.Routes
{
    public class DoRoute:RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            // 模拟出错:外面的某步操作发生404
            if (httpContext.Request.Url.AbsoluteUri.EndsWith(".do"))
            {
                RouteData rd = new RouteData(this, new MvcRouteHandler());
                rd.Values.Add("controller", "RouteExtend");
                rd.Values.Add("action", "Do");

                return rd;
            }

            return null;
        }

        /// <summary>
        /// 获取虚拟路径
        /// 注意:此方法目前在 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"),才被调用
        /// </summary>
        /// <param name="requestContext"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return null;
        }


    }
}


  b. 控制器:   

using System.Web.Mvc;

namespace RoutStudy.Controllers
{
    public class RouteExtendController : Controller
    {
        //
        // GET: /RouteExtend/
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Do()
        {
            return Content("后缀为DO处理!");
        }
    }
}

   c. 注册路由:

 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.Add("myDoRoute", new DoRoute());
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "RouteExtend", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }

跑一下吧:


出问题了,仔细想想。正常现象,因为我们重写的DoRoute没有处理MVC逻辑。改个路径:http://localhost:4055/abc.do,再刷新。

这是预期的结果。

2. 对于".do"结尾的url进行特殊处理,非".do"页面正常处理

  思路:这里我们可以对以".do"结尾的路径专门写一个处理程序来处理;否则,我们走正常MVC流程。

                 我们知道:UrlRoutingModule在获取到合适的RouteData后,将通过其RouteHandler属性来获取实际的IHttpHandler对象,通过IHttpHandler来处理请求。所以:1.  我们重写IHttpHander,处理".do"后缀程序;2. 将IHttpHander实现扔进路由IRouteHandler中,所以我们要重写IRouteHandler;3. 最终将IRouteHandler实例装进路由对象,再将路由对象进行注册,因此我们需要重写Route。

a.  实现 IHttpHandler和 IRouteHandler接口(包含1、2两步)

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

namespace RoutStudy.Handlers
{
    /// <summary>
    /// 自定义获取IHttpHandler实例的接口
    /// </summary>
    public class DoRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new DoHandler();
        }

        private class DoHandler : IHttpHandler
        {

            #region IHttpHandler Members


            public bool IsReusable
            {
                get { return true; }
            }

            public void ProcessRequest(HttpContext context)
            {
                context.Response.Write("后缀为DO处理!1. 重写:IHttpHandler和 IRouteHandler接口;2. 重写Route,注册DoRouteHandler;3. 在RouteTable中注册Route");
            }

            #endregion

        }
    }

}


b.  重写Route

using System.Web;
using System.Web.Routing;
using System.Web.Mvc;

using RoutStudy.Handlers;

namespace RoutStudy.Routes
{
    public class DoRouteV2 : RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            if (httpContext.Request.Url.AbsoluteUri.EndsWith(".do"))
            {
                // 注册自定义IRouteHandler 接口
                RouteData rd = new RouteData(this, new DoRouteHandler());
                return rd;
            }
            else
            {
                // 否则使用原MVC路由
                RouteData rd = new RouteData(this, new MvcRouteHandler());
                rd.Values.Add("controller", "RouteExtend");
                rd.Values.Add("action", "Index");

                return rd;
            }
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return null;
        }
    }
}

c.  注册Route

    

 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.Add("myDoRoute", new DoRouteV2());
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "RouteExtend", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }


现在运行一下:

  

加入".do":

其他:

  在MVC中,也可以重写IRouteConstraint 来实际路由的匹配逻辑,这里不细谈。仅贴点代码:  

using System.Web;
using System.Web.Routing;

namespace RoutStudy.Constraints
{
    /// <summary>
    /// 自定义do约束
    /// </summary>
    public class DoConstraint: IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (httpContext.Request.Url.AbsoluteUri.EndsWith(".do"))
            {
                return true;
            }

            return false;

        }
    }
}

注册:

 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.Add("myDoRoute", new DoRouteV2());
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                 new { controller = "RouteExtend", action = "Index", id = UrlParameter.Optional }
                ,new DoConstraint()// Parameter defaults
            );
        }

O啦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值