基于存储在数据库中的URL的自定义MVC路由

时间:2012-08-23 10:41:20

标签: asp.net-mvc-3 routing

我正在尝试添加一些基于存储在mvc数据库中的url的自定义路由逻辑。 (CMS赞),我认为它相当基本,但我觉得我并没有真正到达任何地方。

基本上用户可以键入url,例如:

www.somesite.com/categorya/categoryb/categoryf/someitem
www.somesite.com/about/someinfo

在数据库中存储这些项目及其类型,即普通页面或产品页面。

根据这一点,我想实际点击一个不同的'动作'方法,即我想要上面的方法:

PageController/Product
PageController/Normal

然后,这些操作会加载此页面的内容并显示相同的视图(产品视图或普通视图)。

使用正常的路由方式是行不通的,因为我可能有类似的东西;

cata/producta
cata/catb/catc/catd/cate/catf/producta

现在我一直在这里看:ASP.NET MVC custom routing for search

并尝试将此作为基础,但我如何实际“更改”我想在InvokeActionMethod调用中触及的操作方法?

使用MVC 3.0 btw。

感谢您提供任何帮助/建议

最终解决方案:

Global.asax中

routes.MapRoute(
                "Default",
                "{*path}",
                new { controller = "Page", action = "NotFound", path= "Home" }
            ).RouteHandler = new ApplicationRouteHandler();

路线处理程序

public class ApplicationRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new ApplicationHandler(requestContext);
        }
    }

    public class ApplicationHandler : MvcHandler, IRequiresSessionState
    {
        public ApplicationHandler(RequestContext requestContext)
            : base(requestContext)
        {

        }

        protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
        {
            var url = RequestContext.RouteData.Values["path"].ToString();
            var page = SomePageService.GetPageByUrl(url);

            if (page == null)
            {
                RequestContext.RouteData.Values["Action"] = "NotFound";
            }
            else
            {
                RequestContext.RouteData.Values["Action"] = page.Action;
                RequestContext.RouteData.Values["page"] = page;
            }

            return base.BeginProcessRequest(httpContext, callback, state);
        }
    }

1 个答案:

答案 0 :(得分:4)

对你的情况可能不是一个确切的解决方案,但我最近不得不处理类似的事情,所以这可能会指出你正确的方向。

我所做的是在Global.asax中设置一个简单的路由,其中​​包含一个调用自定义RouteHandler类的catch-all参数。

// Custom MVC route
routes.MapRoute(
    "Custom",
    "{lang}/{*path}",
    new { controller = "Default", action = "Index" },
    new { lang = @"fr|en" }
).RouteHandler = new ApplicationRouteHandler();

ApplicationRouteHandler.cs:

public class ApplicationRouteHandler : IRouteHandler
{
    /// <summary>
    /// Provides the object that processes the request.
    /// </summary>
    /// <param name="requestContext">An object that encapsulates information about the request.</param>
    /// <returns>
    /// An object that processes the request.
    /// </returns>
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string path = requestContext.RouteData.Values["path"] as string;
    // attempt to retrieve controller and action for current path
        Page page = GetPageData(path);

    // Method that returns a 404 error
        if (page == null)
            return SetupErrorHandler(requestContext, "ApplicationRouteHandler");

    // Assign route values to current requestContext
        requestContext.RouteData.Values["controller"] = page.Controller;
        requestContext.RouteData.Values["action"] = page.Action;
        return new MvcHandler(requestContext);
    }
}

显然,从数据库中检索动作和控制器名称的方式可能与我的大不相同,但这应该会给你一个想法。