asp.net-mvc - 在自定义 ASP MVC 路由中为 URL 起别名

标签 asp.net-mvc url-rewriting asp.net-mvc-routing

我正在创建 URL 别名功能;将资源 A 映射到资源 B 的能力。

我正在将其放入一个项目中,该项目将一个包罗万象的 URL 映射到一个自定义路由,该路由解析传入的 URL 字符串并在我们的数据库中查找 URL 部分。基本上,整个 URL 字符串是动态的,并映射到类别层次结构(例如/tyres/car/tyres/van、/suspension/ford/focus)。这一切都工作正常,并且仅用于路由到一个 Controller 。

目前,我正在将 URL 别名的代码集成到此路由中,因为我们目前只允许这些动态路由的别名。它会在我们的数据库中查找传入的 URL 以查看是否存在别名,然后获取其映射到的原始 URL 并将该字符串传递给我们的 URL 解析器。这感觉很脏,关注点与一切分离。

我认为更好的方法是映射两条单独的路线。一个是URLAliasRoute,另一个是CustomWebsiteRoute。路由是否有可能影响其他路由看到的 URL?

所以,假设我映射了以下路线:

UrlAliasRoute aliasRoute = new UrlAliasRoute("{*url}");
routes.Add(aliasRoute );
CustomWebsiteRoute customRoute = new CustomWebsiteRoute("{*url}");
routes.Add(customRoute );
routes.MapRoute("Contact Us", "contact", new { controller = "Contact" });
routes.MapRoute("About Us", "about", new { controller = "About" });
//etc 

以及 URL car/tyres 别名为 car-tyres

因此,当传入 /car-tyres 的请求时,我的 UrlAliasRoute 会在数据库中查找它,看到它有“car/tyres”的映射,然后更改从“car-tyres”到“car/tyres”的 RouteData URL。所有其他路线都使用car/tyres 作为 URL 来匹配路线约束?

这还有一个好处,就是允许对开发人员编码的任何预定义路由使用别名......可能很危险,但我会小心。

似乎是一个不错的解决方案,但我一直在努力寻找如何更改调用 GetRouteData() 后其他路由将收到的 URL。

最佳答案

我一般使用如下方法。首先,在靠近顶部的 Routeconfig 中,我注册一个新的 Routebase(称为 LegacyURLRoute):

routes.Add(new LegacyUrlRoute());

其精简版本如下:

public class LegacyUrlRoute : RouteBase
{
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var request = httpContext.Request;
        var response = httpContext.Response;
        var legacyUrl = request.Url.ToString().ToLower();
        var legacyPath = request.Path.ToString().ToLower();

        Tuple<bool, bool, string> result = DervieNewURL(legacyPath);
        bool urlMatch = result.Item1;
        bool urlMatchGone = result.Item2;
        var newUrl = result.Item3;

        if (urlMatch)
        {//For 301 Moved Permanently
            response.Clear();
            response.StatusCode = (int)System.Net.HttpStatusCode.MovedPermanently;
            response.RedirectLocation = "http://www.example.com" + newUrl;
            response.End();
        }
        else if (urlMatchGone)
        {// 410 Gone
            response.Clear();
            response.StatusCode = (int)System.Net.HttpStatusCode.Gone;
            response.End();
        }
        return null;
    }
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        return null;
    }
}

上面的 DervieNewURL 可以包含数据库中的查找,但最近在一个项目中,我将其作为 HTMLHelper,它还允许我传递直接来自数据库列的 URL,然后可以解析这些 URL适当更新。

DervieNewURL 的简单示例如下所示,但您显然会在表中查找,而不是像下面那样进行硬编码。

public static Tuple<bool, bool, string> DervieNewURL(string url)
{
    /*
        return type from this function is as follows:
        Tuple<bool1, bool2, string1, string2>
        bool1 = indicates if we have a replacement url mapped
        bool2 = indicates if we have a url marked as gone (410)
        string1 = indicates replacement url
        */
    Tuple<bool, bool, string> result = new Tuple<bool, bool, string>(false, false, null);
    if (!String.IsNullOrWhiteSpace(url))
    {
        string newUrl = null;
        bool urlMatch = false;
        bool urlMatchGone = false;

        switch (url.ToLower())
        {
            case "/badfoldergone/default.aspx": { urlMatchGone = true; } break;
            case "/oldfoldertoredirect/default.aspx": { urlMatch = true; newUrl = "/somecontroller/someaction"; } break;
            default: { } break;
        }
        result = new Tuple<bool, bool, string>(urlMatch, urlMatchGone, newUrl);

    }
    return result;
}

如果您需要通配符匹配,那么我想您可以修改上述内容或将其构建到数据库调用匹配条件中。

通过尽早使用此路由,您可以将旧 URL 重定向到其他路由,然后当请求沿路由表向下级联时将触发这些路由。最终您将到达类似于以下内容的默认路线:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

如果开发人员有硬编码链接,那么您只需要使用由这些 url 触发的路由即可。通过使用诸如上述之类的内容,可以尽早捕获并添加到数据库中的列表中,并在需要时使用适当的 301 Moved 或 410 gone。

关于asp.net-mvc - 在自定义 ASP MVC 路由中为 URL 起别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23418830/

相关文章:

c# - 如何使用最小起订量模拟 Controller.User

asp.net-mvc - 在强类型 View 中格式化可为空的 DateTime 字段

asp.net-mvc - 如何优雅地重新附加 Entity Framework 5 POCO 结构并保存它?

php - 重写 URL 中的单词 - wordpress

c# - asp .net mvc 中带有 View 模型的多个路由参数

asp.net - 我可以修改 Global.asax 之外的 MVC 路由吗?

c# - 从 Controller 访问数据库实体

.htaccess - htaccess规则重写.htaccess

Javascript 重写 mousedown 上的所有外部链接?

c# - Html.BeginForm 会在该区域后自动添加一个子文件夹