ASP.NET MVC 路由失败。这是错误还是极端情况?

发布于 2024-10-21 16:54:37 字数 1255 浏览 6 评论 0原文

我有一个 ASP.NET MVC 3 应用程序,用户可以在其中发布类似“bla bla 如果 yada yada yada 会更好”的建议。 对于建议详细信息页面,我定义了一个很好的SEO友好路线,如下所示:

routes.MapRoute(null, "suggestion/{id}/{it}/would-be-better-if-{if}", 
    new { controller = "suggestion", action = "details" });

如您所见,我希望修复“如果”部分会更好。

该路线非常适合任何旧建议,并生成诸如 suggestion/5/this-site/would-be-better-if-it-had-a-iphone-application 之类的链接,然后单击该链接实际上请求适当的详细信息页面。

具有讽刺意味的是,我的一个朋友恰好是一名测试人员,他成功地不由自主地发布了一条实际上打破了路线的建议:“如果‘如果’总是在中间对齐,那么这个网站会更好”。
为此建议生成的链接是 /suggestion/84/this-site/would-be-better-if-would-be-better-if-was-always-alligned-in-the-middle

我已经尝试过 Phil Haack 的路由调试器 并确认该路线实际上会一直有效,直到 suggestion/84/this-site/would-be-better-if-would-be-better-if-,因此第二个“would-be-better-if” " 实际上已被接受;之后添加任何内容实际上都会导致 url 不匹配任何路由(感谢 Omar - 请参阅评论- 寻求帮助)


请记住,我真的不想更改路由定义,因为我认为在这种情况下,就 SEO 而言,它已经是我可以管理的最好的了。

那么,为什么让文本等于路由的固定部分会阻止链接与路由匹配呢? 为什么路线中断?

实际上,我对为什么更感兴趣,因为我相信理解为什么会带来解决方案,或者至少能够正确理解一个相当有趣的问题。

I have an ASP.NET MVC 3 application where users can post suggestions along the lines of "bla bla would be better if yada yada yada".
For the suggestion detail page I have defined a nice SEO friendly route as follows:

routes.MapRoute(null, "suggestion/{id}/{it}/would-be-better-if-{if}", 
    new { controller = "suggestion", action = "details" });

As you can see I want the "would be better if" part to be fixed.

This route works perfectly for any old suggestion and generates links like suggestion/5/this-site/would-be-better-if-it-had-a-iphone-application, and clicking on the link actually requests the appropriate detail page.

A friend of mine, who ironically happens to be a tester, has managed to, involuntarily, post a suggestion that actually breaks the route: "This site would be better if 'would be better if' was always aligned in the middle".
The link generated for this suggestion is
/suggestion/84/this-site/would-be-better-if-would-be-better-if-was-always-alligned-in-the-middle.

I have tried Phil Haack's Routing Debugger and have confirmed that the route will actually work up until suggestion/84/this-site/would-be-better-if-would-be-better-if-, so the second "would-be-better-if" is actually accepted; adding anything after that will actually cause the url not to match any route (thanks to Omar -see comments- for help).


Please bear in mind that I really don't want to change the route definition since I think it is as good as I can manage for this case, SEO-wise.

So, how come having text equal to the fixed part of the route prevents the link from matching the route? why is the route breaking?

I am actually rahter more interested in the why, as I believe understanding the why will lead to a solution or at least a proper understanding of a rather interesting problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

匿名。 2024-10-28 16:54:38

这看起来像是 ASP.NET 路由的欺骗:之间的文字子段标记,并使用来自文字子段的字符路由值,这是该错误的简单得多的版本。我建议关闭这一项,转而支持那一项。

我回答了这个问题。

This looks like a dupe of ASP.NET routing: Literal sub-segment between tokens, and route values with a character from the literal sub-segment which is a much simpler version of the bug. I'd recommend closing this one in favor of that one.

I answered that question.

抚你发端 2024-10-28 16:54:37

我不确定为什么它会这样,但你可以使用这样的东西:

public interface IRouteRule
{
    object ProcessIncoming(object value);
    object ProcessOutgoing(object value);
}

public class StartsWithRouteRule : IRouteRule
{
    public StartsWithRouteRule(string value)
    {
        Value = value;
    }

    public string Value { get; protected set; }

    public object ProcessIncoming(object value)
    {
        var result = value as string;
        if (result == null)
            return null;

        if (!result.StartsWith(Value))
            return null;

        return result.Substring(Value.Length);
    }

    public object ProcessOutgoing(object value)
    {
        var result = value as string;
        if (result == null)
            return null;

        return Value + result;
    }
}

public class ComplexRoute : Route
{
    public ComplexRoute(string url, object defaults, object rules)
        : this(url, new RouteValueDictionary(defaults), rules)
    { }
    public ComplexRoute(string url, RouteValueDictionary defaults, object rules)
        : base(url, defaults, new MvcRouteHandler())
    {
        Rules = new Dictionary<string, IRouteRule>();
        foreach (var pair in new RouteValueDictionary(rules))
            Rules.Add(pair.Key, (IRouteRule)pair.Value);
    }

    public Dictionary<string, IRouteRule> Rules { get; protected set; }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var result = base.GetRouteData(httpContext);

        if (result == null)
            return null;

        foreach (var pair in Rules)
        {
            var currentValue = result.Values[pair.Key];
            if (currentValue == null)
                return null;

            var value = pair.Value.ProcessIncoming(currentValue);
            if (value == null)
                return null;

            result.Values[pair.Key] = value;
        }

        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        values = new RouteValueDictionary(values);

        foreach (var pair in Rules)
        {
            var currentValue = values[pair.Key];
            if (currentValue == null)
                return null;

            var value = pair.Value.ProcessOutgoing(currentValue);
            if (value == null)
                return null;

            values[pair.Key] = value;
        }

        return base.GetVirtualPath(requestContext, values);
    }
}

用法:

routes.Add(new ComplexRoute(
    "suggestion/{id}/{it}/{if}",
    new { controller = "suggestion", action = "details" },
    new { @if = new StartsWithRouteRule("would-be-better-if-") }));

I'm not sure why it behaves this way, but you can use something like this:

public interface IRouteRule
{
    object ProcessIncoming(object value);
    object ProcessOutgoing(object value);
}

public class StartsWithRouteRule : IRouteRule
{
    public StartsWithRouteRule(string value)
    {
        Value = value;
    }

    public string Value { get; protected set; }

    public object ProcessIncoming(object value)
    {
        var result = value as string;
        if (result == null)
            return null;

        if (!result.StartsWith(Value))
            return null;

        return result.Substring(Value.Length);
    }

    public object ProcessOutgoing(object value)
    {
        var result = value as string;
        if (result == null)
            return null;

        return Value + result;
    }
}

public class ComplexRoute : Route
{
    public ComplexRoute(string url, object defaults, object rules)
        : this(url, new RouteValueDictionary(defaults), rules)
    { }
    public ComplexRoute(string url, RouteValueDictionary defaults, object rules)
        : base(url, defaults, new MvcRouteHandler())
    {
        Rules = new Dictionary<string, IRouteRule>();
        foreach (var pair in new RouteValueDictionary(rules))
            Rules.Add(pair.Key, (IRouteRule)pair.Value);
    }

    public Dictionary<string, IRouteRule> Rules { get; protected set; }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var result = base.GetRouteData(httpContext);

        if (result == null)
            return null;

        foreach (var pair in Rules)
        {
            var currentValue = result.Values[pair.Key];
            if (currentValue == null)
                return null;

            var value = pair.Value.ProcessIncoming(currentValue);
            if (value == null)
                return null;

            result.Values[pair.Key] = value;
        }

        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        values = new RouteValueDictionary(values);

        foreach (var pair in Rules)
        {
            var currentValue = values[pair.Key];
            if (currentValue == null)
                return null;

            var value = pair.Value.ProcessOutgoing(currentValue);
            if (value == null)
                return null;

            values[pair.Key] = value;
        }

        return base.GetVirtualPath(requestContext, values);
    }
}

Usage:

routes.Add(new ComplexRoute(
    "suggestion/{id}/{it}/{if}",
    new { controller = "suggestion", action = "details" },
    new { @if = new StartsWithRouteRule("would-be-better-if-") }));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文