为什么这个路由参数附加到查询字符串上?
我有一个 ASP.NET MVC 3 应用程序,用于记录用户的计步器条目。用户可以通过访问 /Pedometer
查看所有最新的计步器条目,并可以通过访问 /Pedometer/2011
等 URL 按年、年/月或年/月/日进行过滤>、/Pedometer/2011/08
和 /Pedometer/2011/08/15
分别。
我在 Global.asax 中创建了两条映射路线。第一个路由(如下所示)允许使用各种 URL 模式按日期进行过滤。第二条路由(未显示)是默认的 ASP.NET MVC 路由。
routes.MapRoute(
"PedometerEntries", // Route name
"Pedometer/{year}/{month}/{day}", // URL with parameters
new
{
controller = "Pedometer",
action = "Index",
year = UrlParameter.Optional,
month = UrlParameter.Optional,
day = UrlParameter.Optional
}, // Parameter defaults
new
{
year = @"\d{4}",
month = @"([012]?\d{1})?",
day = @"(([1-9])|([12][0-9])|(3[0-1]))?"
} // Parameter constraints
);
这是我的问题。我有一个视图,我想在其中创建以下形式的链接:currentUrl?format=csv
,这将允许用户以 CSV 格式下载所请求 URL 的计步器条目。因此,如果用户访问 /Pedometer
,下载链接将是 /Pedometer?format=csv
。如果用户正在访问 /Pedometer/2011/08
,下载链接将是 /Pedometer/2011/08?format=csv
。
为了创建这样的链接,我使用以下代码添加了一个名为 DownloadToExcel
的自定义 Html Helper:
public static MvcHtmlString DownloadToExcel(this HtmlHelper helper, string linkText)
{
RouteValueDictionary routeValues = helper.ViewContext.RouteData.Values;
// Add the format parameter to the route data collection, if needed
if (!routeValues.ContainsKey("format"))
routeValues.Add("format", "csv");
return helper.ActionLink(linkText, // Link text
routeValues["action"].ToString(), // Action
routeValues); // Route values
}
当我在视图中添加 @Html.DownloadToExcel()
标记时,它会生成一个链接,但问题在于 - 当用户访问最近的条目或按年/月或年/月/日期过滤的条目时,它会按预期工作,但当用户访问年份过滤器 URL 时则不会。
以下列表显示了用户访问的 URL 以及自定义 Html Helper 生成的相应 URL:
- 访问:
/Pedometer
- 下载链接:/Pedometer?format=csv
- 访问:
/Pedometer/2011
- 下载链接:/Pedometer?year=2011&format=csv
- 访问:
/Pedometer/2011/08
- 下载链接:/Pedometer/2011/08?format=csv
- 访问:
/Pedometer/2011/08/15
> - 下载链接:/Pedometer/2011/08/15?format=csv
为什么访问/Pedometer/2011
时会出现这样的情况?下载链接是 /Pedometer?year=2011&format=csv
而不是 /Pedometer/2011?format=csv
?为什么它不适用于该一种情况,但对于年/月和年/月/日期情况按预期工作?
谢谢
I have an ASP.NET MVC 3 application that records a user's pedometer entries. A user can view all most recent pedometer entries by visiting /Pedometer
and can filter by year, year/month, or year/month/date by visiting URLs like /Pedometer/2011
, /Pedometer/2011/08
and /Pedometer/2011/08/15
, respectively.
I've created two mapped routes in Global.asax
. The first route, shown below, is what allows the various URL patterns for filtering by date. The second route (not shown) is the default ASP.NET MVC route.
routes.MapRoute(
"PedometerEntries", // Route name
"Pedometer/{year}/{month}/{day}", // URL with parameters
new
{
controller = "Pedometer",
action = "Index",
year = UrlParameter.Optional,
month = UrlParameter.Optional,
day = UrlParameter.Optional
}, // Parameter defaults
new
{
year = @"\d{4}",
month = @"([012]?\d{1})?",
day = @"(([1-9])|([12][0-9])|(3[0-1]))?"
} // Parameter constraints
);
Here's my question. I have a view where I want to create a link of the form: currentUrl?format=csv
, which will let the user download the pedometer entries for the requested URL in a CSV format. So if a user is visiting /Pedometer
, the download link would be to /Pedometer?format=csv
. If the user is visiting /Pedometer/2011/08
the download link would be to /Pedometer/2011/08?format=csv
.
To create such a link I added a custom Html Helper named DownloadToExcel
with the following code:
public static MvcHtmlString DownloadToExcel(this HtmlHelper helper, string linkText)
{
RouteValueDictionary routeValues = helper.ViewContext.RouteData.Values;
// Add the format parameter to the route data collection, if needed
if (!routeValues.ContainsKey("format"))
routeValues.Add("format", "csv");
return helper.ActionLink(linkText, // Link text
routeValues["action"].ToString(), // Action
routeValues); // Route values
}
When I add the @Html.DownloadToExcel()
markup in my view, it generates a link, but here's the rub - when the user visits the recent entries or the entries filtered by year/month or year/month/date, it works as expected, but not when the user visits the year filter URL.
The following list shows the URL the user visits and the corresponding URL generated by the custom Html Helper:
- Visiting:
/Pedometer
- Download link:/Pedometer?format=csv
- Visiting:
/Pedometer/2011
- Download link:/Pedometer?year=2011&format=csv
- Visiting:
/Pedometer/2011/08
- Download link:/Pedometer/2011/08?format=csv
- Visiting:
/Pedometer/2011/08/15
- Download link:/Pedometer/2011/08/15?format=csv
Why is it when visiting /Pedometer/2011
the download link is /Pedometer?year=2011&format=csv
and not /Pedometer/2011?format=csv
? And why does it not work for that one case but works as expected for the year/month and year/month/date cases?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此问题很可能是由
This problem is most likely caused by this bug described by Phil Haack on his blog. There's a regression bug introduced in ASP.NET MVC 3 when you have two consecutive optional URL parameters.
我使用您提供的代码创建了一个小型 MVC 3 应用程序,并获得了与所描述的完全相同的行为。
如果我转到 http://localhost:51181/pedometer/2011 生成的链接将是 http://localhost:51181/Pedometer?year=2011&format=csv。
但如果我明确输入操作的名称(索引),它将正确呈现。
访问 http://localhost:51181/pedometer/index/2011 将生成以下链接:
< a href="http://localhost:51181/pedometer/index/2011?format=csv" rel="nofollow">http://localhost:51181/pedometer/index/2011?format=csv
HtmlHelper 扩展方法似乎并不总是使用正确的路线。
如果我在自定义路由下方、默认 MVC 路由之前添加以下路由,则它可以正常工作。
I created a small MVC 3 application with the code you provided and got exactly the same behavior as described.
If I go to http://localhost:51181/pedometer/2011 the generated link would be http://localhost:51181/Pedometer?year=2011&format=csv.
But if I explicitly entered the name of the action (Index) it would render correctly.
Visiting http://localhost:51181/pedometer/index/2011 will generate the following link:
http://localhost:51181/pedometer/index/2011?format=csv
It seems the correct route is not always used by the HtmlHelper extension method.
If I add the following route just below your custom route, but before the default MVC route it works OK.