为什么使用此正则表达式时 ASP.NET-MVC 路由的 UrlParameter.Optional 被忽略?

发布于 2024-10-17 02:51:43 字数 1982 浏览 1 评论 0原文

这是我今天早上遇到的 ASP.NET MVC URL 路由问题的简化示例。

相当简单,我想要调用路由的 Action,无论是否提供了最后的参数。

该路由工作正常,可以匹配 /apple//apple/test/

routes.MapRoute(
    "Working Route",
    "apple/{parameter}",
    new { 
        controller = "Apple", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9\.-]+)" }
);

但是,第二条路由仅匹配 /banana/test/等等。当我尝试 /banana/ 时,路由器直接越过它并返回包罗万象的 404 错误。

routes.MapRoute(
    "Non-Working Route",
    "banana/{parameter}",
    new { 
        controller = "Banana", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9]+)" }
);

唯一的区别是参数的正则表达式验证,但由于它是一个非常简单的正则表达式匹配,因此它们对于像 /banana/ 这样的 URL 应该可以完美工作,但第二条路由无法识别它。

我通过更改路由 #2 上的正则表达式以匹配路由 #1 上的正则表达式来回避我的问题,并接受“.”。和“-”字符,我只是想知道是否有人知道为什么会发生这种情况。

编辑:

这是我在示例中使用的控制器和操作。这里没什么特别的。

public class AppleController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

public class BananaController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

所以我的问题是 /apple/ 会显示“未指定参数。”,而 /banana/ 却给了我一个不想要的 404 。


So far..

在路由声明中使用 parameter = URLParameter.Optional: 路线#1 工作正常,路线#2 在没有参数的情况下不匹配。

在路由声明中使用 parameter = "": 路线 #1 和路线 #1当 URL 中省略该参数时,路由 #2 无法匹配。

在 Action 方法签名中声明 parameter = "": 由于 .NET 版本的原因,不可能。

删除所有其他路由没有任何效果。

This is a stripped down example of a problem I was having this morning with ASP.NET MVC's URL routing.

Fairly simple, I wanted a route's Action to be called, whether or not the parameter on the end was supplied.

This route works fine, matching both /apple/ and /apple/test/

routes.MapRoute(
    "Working Route",
    "apple/{parameter}",
    new { 
        controller = "Apple", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9\.-]+)" }
);

However, this second route will only match /banana/test/ and the like. When I try /banana/, the router just passes right over it and returns the catch-all 404 error.

routes.MapRoute(
    "Non-Working Route",
    "banana/{parameter}",
    new { 
        controller = "Banana", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9]+)" }
);

The only difference is the Regex validation of the parameter, but as it's quite a simple Regex match, they should both work perfectly fine for a URL like /banana/, yet the second route just fails to recognise it.

I side-stepped my problem by just changing the Regex on route #2 to match that on route #1, and accept the '.' and '-' characters, I just wondered if anyone knows why this seems to be happening.

EDIT:

Here are the Controllers and Actions that I'm using for my example. Nothing fancy here.

public class AppleController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

public class BananaController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

So my problem is that /apple/ would display "No parameter specified.", while /banana/ gives me an undesired 404 instead.


So far..

Using parameter = URLParameter.Optional in the Route declaration:
Route #1 works perfectly, Route #2 doesn't match without the parameter.

Using parameter = "" in the Route declaration:
Both Route #1 & Route #2 fail to match when the parameter is left off the URL.

Declaring parameter = "" in the Action method signature:
Not possible due to .NET version.

Removing all other routes has no effect.

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

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

发布评论

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

评论(2

是伱的 2024-10-24 02:51:43

如果标记是可选的,那么您使用的任何正则表达式约束也必须反映这一点,例如 (foo)?


I was able to reproduce this issue with ASP.NET MVC 2 on .NET 4 . Then I upgraded to ASP.NET MVC 3 and everything worked as expected. The solution I present above does not work with ASP.NET MVC 2, but it works with ASP.NET MVC 3, so I can only assume this is a bug on v2 that is now fixed in v3.

您可以引用 v2,并在 web.config 上使用它来测试 v3:

<runtime>
   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
         <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
         <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
   </assemblyBinding>
</runtime>

If the token is optional then whatever regex constraint you use must also reflect that, e.g. (foo)?.


I was able to reproduce this issue with ASP.NET MVC 2 on .NET 4 . Then I upgraded to ASP.NET MVC 3 and everything worked as expected. The solution I present above does not work with ASP.NET MVC 2, but it works with ASP.NET MVC 3, so I can only assume this is a bug on v2 that is now fixed in v3.

You can reference v2, and use this on web.config to test with v3:

<runtime>
   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
         <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
         <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
   </assemblyBinding>
</runtime>
中性美 2024-10-24 02:51:43

第二次编辑

匹配 ~/fruit/ 和 ~fruit/apple

routes.MapRoute(
    "Working Route",
    "Fruit/{fruit}",
    new
    {
        controller = "Fruit",
        action = "Index",
        fruit = ""
    },
    new { fruit = @"([a-z0-9\.-]+)" }
);

public ActionResult Index(string fruit)
{
    ViewData["fruit"] = !String.IsNullOrEmpty(fruit) ? fruit : "None specified.";
    return View();
}

匹配 ~/banana/ 和 ~/banana/yellow

routes.MapRoute(
    "Non-Working Route",
    "Banana/{color}",
    new
    {
        controller = "Banana",
        action = "Index",
        color = ""
    },
    new { color = @"([a-z0-9]+)" }
);

public ActionResult Index(string color)
    {
        ViewData["Color"] = color;
        return View();
    }

第一次编辑

尝试实际将参数设置为操作签名上的可选参数,例如: string parameter = ""


我没有得到这种行为。正如您所描述的那样,这两条路线都对我有用(如果我在路线中添加“-”,第二条路线会抛出 404,但这是预期的)。您的操作方法签名是什么样的?

我将我的路线(和控制器/视图)设置为如下所示:

routes.MapRoute(
    "Working Route",
    "Fruit/{fruit}",
    new
    {
        controller = "Fruit",
        action = "Index",
        fruit = UrlParameter.Optional
    },
    new { fruit = @"([a-z0-9]+)" }
);

我的 Index() 操作如下所示:

public ActionResult Index(string fruit = "")
{
    ViewData["fruit"] = fruit;
    return View();
}

2nd EDIT

Matching ~/fruit/ and ~fruit/apple

routes.MapRoute(
    "Working Route",
    "Fruit/{fruit}",
    new
    {
        controller = "Fruit",
        action = "Index",
        fruit = ""
    },
    new { fruit = @"([a-z0-9\.-]+)" }
);

public ActionResult Index(string fruit)
{
    ViewData["fruit"] = !String.IsNullOrEmpty(fruit) ? fruit : "None specified.";
    return View();
}

Matching ~/banana/ and ~/banana/yellow

routes.MapRoute(
    "Non-Working Route",
    "Banana/{color}",
    new
    {
        controller = "Banana",
        action = "Index",
        color = ""
    },
    new { color = @"([a-z0-9]+)" }
);

public ActionResult Index(string color)
    {
        ViewData["Color"] = color;
        return View();
    }

1st EDIT

Try actually setting the parameter as optional on the action signature, such that: string parameter = ""


I'm not getting that behavior. Both routes work for me as you're describing them (the second route throws a 404 if I add a "-" to the route, but that's expected). What does your action method signature look like?

I set my route (and controller/view) to look like:

routes.MapRoute(
    "Working Route",
    "Fruit/{fruit}",
    new
    {
        controller = "Fruit",
        action = "Index",
        fruit = UrlParameter.Optional
    },
    new { fruit = @"([a-z0-9]+)" }
);

And my Index() action looks like:

public ActionResult Index(string fruit = "")
{
    ViewData["fruit"] = fruit;
    return View();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文