带有自定义 slug 的 .NET MVC-4 路由 [英] .NET MVC-4 routing with custom slugs

查看:29
本文介绍了带有自定义 slug 的 .NET MVC-4 路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 ASP.Net MVC 4 重写一个网站项目,但我发现很难设置正确的路由.url 结构不是 RESTful 或遵循控制器/操作模式 - 页面具有以下 slug 结构.所有 slug 都保存在数据库中.

I'm rewriting a website project with ASP.Net MVC 4 and I find it difficult to setup the right routes. The url structure is not RESTful or following a controller/action pattern - the pages have the following structure of slugs. All slugs are saved in the database.

/country
/country/carmake
/country/carmake/carmodel
/custom-landing-page-slug
/custom-landing-page-slug/subpage

示例:

/italy
/italy/ferrari
/italy/ferrari/360
/history-of-ferrari
/history-of-ferrari/enzo

由于 CountryCar MakeCar Model 是不同的模型/实体,我想要像 CountryController、CarMakesController 和CarModelsController 在这里我可以处理不同的逻辑并从中呈现适当的视图.此外,我有自定义登录页面,其中可以包含包含一个或多个斜杠的 slug.

Since Country, Car Make and Car Model are different models/entities, I would like to have something like a CountriesController, CarMakesController and CarModelsController where I can handle the differing logic and render the appropriate views from. Furthermore, I have the custom landing pages which can have slugs containing one or more slashes.

我的第一次尝试是有一个包罗万象的 PagesController 它将在数据库中查找 slug 并根据页面类型调用适当的控制器(例如.CarMakesController>),然后将执行一些逻辑并呈现视图.但是,我从未成功调用"另一个控制器并呈现适当的视图 - 感觉不对.

My first attempt was to have a catch-all PagesController which would look up the slug in the database and call the appropriate controller based on the page type (eg. CarMakesController), which would then perform some logics and render the view. However, I never succeed to "call" the other controller and render the appropriate view - and it didn't feel right.

有人能在这里指出我正确的方向吗?谢谢!

Can anyone point me in the right direction here? Thanks!

澄清:我不想要重定向 - 我想将请求委托给不同的控制器来处理逻辑和呈现视图,具体取决于内容的类型(CountryCarMake 等).

To clarify: I do not want a redirect - I want to delegate the request to a different controller for handling logic and rendering a view, depending on the type of content (Country, CarMake etc.).

推荐答案

由于您的链接看起来很相似,因此您无法在路由级别将它们分开.但这里有个好消息:您可以编写自定义路由处理程序,而无需考虑典型的 ASP.NET MVC 链接解析.

Since your links looks similar, you can't separate them at the routing level. But here are good news: you can write custom route handler and forget about typical ASP.NET MVC links' parsing.

首先,让我们将 RouteHandler 附加到默认路由:

First of all, let's append RouteHandler to default routing:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Default", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new SlugRouteHandler();

这允许您以不同的方式操作您的网址,例如:

This allows you to operate with your URLs in different ways, e.g.:

public class SlugRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var url = requestContext.HttpContext.Request.Path.TrimStart('/');

        if (!string.IsNullOrEmpty(url))
        {
            PageItem page = RedirectManager.GetPageByFriendlyUrl(url);
            if (page != null)
            {
                FillRequest(page.ControllerName, 
                    page.ActionName ?? "GetStatic", 
                    page.ID.ToString(), 
                    requestContext);
            }
        }

        return base.GetHttpHandler(requestContext);
    }

    private static void FillRequest(string controller, string action, string id, RequestContext requestContext)
    {
        if (requestContext == null)
        {
            throw new ArgumentNullException("requestContext");
        }

        requestContext.RouteData.Values["controller"] = controller;
        requestContext.RouteData.Values["action"] = action;
        requestContext.RouteData.Values["id"] = id;
    }
}

这里需要一些解释.

首先,您的处理程序应该从 System.Web.Mvc 派生 MvcRouteHandler.

First of all, your handler should derive MvcRouteHandler from System.Web.Mvc.

PageItem 代表我的数据库结构,其中包含有关 slug 的所有必要信息:

PageItem represents my DB-structure, which contains all the necessary information about slug:

ContentID 是内容表的外键.

GetStatic 是 action 的默认值,对我来说很方便.

GetStatic is default value for action, it was convenient in my case.

RedirectManager 是一个用于数据库的静态类:

RedirectManager is a static class which works with database:

public static class RedirectManager
{
    public static PageItem GetPageByFriendlyUrl(string friendlyUrl)
    {
        PageItem page = null;

        using (var cmd = new SqlCommand())
        {
            cmd.Connection = new SqlConnection(/*YourConnectionString*/);
            cmd.CommandText = "select * from FriendlyUrl where FriendlyUrl = @FriendlyUrl";
            cmd.Parameters.Add("@FriendlyUrl", SqlDbType.NVarChar).Value = friendlyUrl.TrimEnd('/');

            cmd.Connection.Open();
            using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
            {
                if (reader.Read())
                {
                    page = new PageItem
                               {
                                   ID = (int) reader["Id"],
                                   ControllerName = (string) reader["ControllerName"],
                                   ActionName = (string) reader["ActionName"],
                                   FriendlyUrl = (string) reader["FriendlyUrl"],
                               };
                }
            }

            return page;
        }
    }
}

使用此代码库,您可以添加所有限制、异常和奇怪的行为.

Using this codebase, you can add all the restrictions, exceptions and strange behaviors.

它在我的情况下有效.希望这对您有所帮助.

It worked in my case. Hope this helps in yours.

这篇关于带有自定义 slug 的 .NET MVC-4 路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆