别名化自定义ASP MVC路由内的URL [英] Aliasing a URL inside a custom ASP MVC Route

查看:56
本文介绍了别名化自定义ASP MVC路由内的URL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm creating URL aliasing functionality; the ability to map resource A to resource B.

我正在将其应用到一个项目中,该项目具有一个映射到自定义Route的通用URL,该URL解析传入的URL字符串并在数据库中查找URL部分.基本上,整个网址字符串都是动态的,并且映射到类别层次结构(例如/tyres/car/tyres/van,/suspension/ford/focus).一切正常,仅存在于路由到一个控制器的情况.

I'm fitting this into a project with a catch-all URL mapped to a custom Route that parses the incoming URL string and looks up the URL parts inside our database. Basically, the entire URL string is dynamic and maps to a category hierarchy (e.g. /tyres/car /tyres/van, /suspension/ford/focus). This is all working fine, and only exists to route to one controller.

当前,我将URL别名的代码集成到此Route中,因为我们目前仅允许对这些动态路由进行别名.它查找传入数据库的URL,以查看是否存在别名,然后获取其映射到的原始URL并将该字符串传递给我们的URL解析器.这感觉很脏,关注点和所有内容都分离了.

Currently I'm integrating my code for URL aliasing into this Route, since we're currently only allowing aliasing of these dynamic routes. It looks up the incoming URL to our database to see if an alias exists, and then grabs the original URL it's mapped to and passes that string to our URL parser. This feels dirty, separation of concerns and all.

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

I think a better approach would be two separate routes mapped. One, URLAliasRoute, and the other CustomWebsiteRoute. Is it possible for a Route to affect the URL that other routes will see?

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

So, imagine I have the following routes mapped:

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 

以及别名 car-tyres

因此,当收到/car-tyres 的传入请求时,我的UrlAliasRoute会在数据库中查找它,看到其中有一个"car/tyres"的映射,然后更改从汽车轮胎"到汽车/轮胎"的RouteData URL.然后,所有其他路线都使用 car/tyres 作为URL来与路线约束进行匹配?

So when an incoming request for /car-tyres comes in, my UrlAliasRoute will look it up in the database, see that is has a mapping for "car/tyres", and then changes the RouteData URL from "car-tyres" to "car/tyres". All other Routes are then using car/tyres as the URL to match against the Route constraints?

这也将带来好处,即允许对开发人员已编码的任何预定义路由进行别名别名...潜在的危险,但我会谨慎处理.

This would also have the benefit of allowing for aliasing of any predefined routes that developers have coded...potentially dangerous but something I'll be careful about.

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

Seems like a nice solution, but I've been struggling to find how to change the URL that other routes will receive after GetRouteData() is called.

推荐答案

我通常使用以下方法.首先,在顶部附近的Routeconfig中,注册一个新的Routebase(称为LegacyURLRoute):

I generally use a method such as below. Firstly within Routeconfig near the top I register a new Routebase (called 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,它还允许我传递直接来自DB列的URL,然后可以对它们进行解析和解析.已适当更新.

The DervieNewURL above can then include the lookup in the DB, but recently on a project I have had that as a HTMLHelper that also allows me to pass in the URL's that come directly from a DB column and these can then be parsed and updated as appropriate.

DervieNewURL的简单示例如下所示,但是显然您将在表中查找,而不是如下进行硬编码.

Simple example of DervieNewURL could be as follows, but you would obviously lookup in a table rather than having bits hard coded as below.

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;
}

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

If you require wildcard matches then I guess you could amend the above or build this into the DB call matching criteria.

通过尽早使用此路由,您可以将旧版url重定向到其他路由,然后在请求沿路由表级联时将被触发.最终,您将使用默认路由,类似于:

By employing this route early on you can redirect legacy url's to other routes that will then be triggered as the request cascades down the routing table. Ultimately you will end up at your Default route similar to:

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

如果开发人员具有硬编码的链接,那么您只需要使用将由这些url触发的路由.通过采用上述方法,可以尽早捕获并通过适当的301 Move或410消失添加到数据库列表中.

If developers have hard coded links then you will just need employ routes that will be triggered by these url's. By employing something such as above can capture most early on and add to the list in your DB with appropriate 301 Moved or 410 gone if required.

这篇关于别名化自定义ASP MVC路由内的URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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