asp.net-mvc ASP.NET MVC QueryString 默认覆盖提供的值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/458288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC QueryString defaults overriding supplied values?
提问by Greg Beech
Using ASP.NET MVC Preview 5 (though this has also been tried with the Beta), it appears that querystring defaults in a route override the value that is passed in on the query string. A repro is to write a controller like this:
使用 ASP.NET MVC Preview 5(尽管这也已在 Beta 中尝试过),路由中的查询字符串默认值似乎覆盖了在查询字符串中传递的值。重现是编写这样的控制器:
public class TestController : Controller
{
public ActionResult Foo(int x)
{
Trace.WriteLine(x);
Trace.WriteLine(this.HttpContext.Request.QueryString["x"]);
return new EmptyResult();
}
}
With route mapped as follows:
路由映射如下:
routes.MapRoute(
"test",
"Test/Foo",
new { controller = "Test", action = "Foo", x = 1 });
And then invoke it with this relative URI:
然后用这个相对 URI 调用它:
/Test/Foo?x=5
The trace output I see is:
我看到的跟踪输出是:
1
5
So in other words the default value that was set up for the route is always passed into the method, irrespective of whether it was actually supplied on the querystring. Note that if the default for the querystring is removed, i.e. the route is mapped as follows:
因此,换句话说,为路由设置的默认值始终传递到方法中,而不管它是否实际在查询字符串上提供。请注意,如果删除了查询字符串的默认值,即路由映射如下:
routes.MapRoute(
"test",
"Test/Foo",
new { controller = "Test", action = "Foo" });
Then the controller behaves as expected and the value is passed in as the parameter value, giving the trace output:
然后控制器按预期运行,并将值作为参数值传入,给出跟踪输出:
5
5
This looks to me like a bug, but I would find it very surprising that a bug like this could still be in the beta release of the ASP.NET MVC framework, as querystrings with defaults aren't exactly an esoteric or edge-case feature, so it's almost certainly my fault. Any ideas what I'm doing wrong?
这在我看来就像一个错误,但我会发现这样的错误仍然存在于 ASP.NET MVC 框架的 beta 版本中非常令人惊讶,因为具有默认值的查询字符串并不是一个深奥的或边缘情况的功能,所以这几乎肯定是我的错。任何想法我做错了什么?
回答by Dale Ragan
The best way to look at ASP.NET MVC with QueryStrings is to think of them as values that the route does not know about. As you found out, the QueryString is not part of the RouteData, therefore, you should keep what you are passing as a query string separate from the route values.
使用 QueryStrings 查看 ASP.NET MVC 的最佳方法是将它们视为路由不知道的值。正如您所发现的,QueryString 不是 RouteData 的一部分,因此,您应该将作为查询字符串传递的内容与路由值分开。
A way to work around them is to create default values yourself in the action if the values passed from the QueryString are null.
如果从 QueryString 传递的值为空,则解决这些问题的一种方法是在操作中自己创建默认值。
In your example, the route knows about x, therefore your url should really look like this:
在您的示例中,路由知道 x,因此您的 url 应该看起来像这样:
/Test/Foo or /Test/Foo/5
and the route should look like this:
路线应该是这样的:
routes.MapRoute("test", "Test/Foo/{x}", new {controller = "Test", action = "Foo", x = 1});
To get the behavior you were looking for.
获得您正在寻找的行为。
If you want to pass a QueryString value, say like a page number then you would do this:
如果你想传递一个 QueryString 值,比如页码,那么你可以这样做:
/Test/Foo/5?page=1
And your action should change like this:
你的动作应该像这样改变:
public ActionResult Foo(int x, int? page)
{
Trace.WriteLine(x);
Trace.WriteLine(page.HasValue ? page.Value : 1);
return new EmptyResult();
}
Now the test:
现在测试:
Url: /Test/Foo Trace: 1 1 Url: /Test/Foo/5 Trace: 5 1 Url: /Test/Foo/5?page=2 Trace: 5 2 Url: /Test/Foo?page=2 Trace: 1 2
Url: /Test/Foo Trace: 1 1 Url: /Test/Foo/5 Trace: 5 1 Url: /Test/Foo/5?page=2 Trace: 5 2 Url: /Test/Foo?page=2 Trace: 1 2
Hope this helps clarify some things.
希望这有助于澄清一些事情。
回答by Greg Beech
One of my colleagues found a link which indicates that this is by designand it appears the author of that article raised an issue with the MVC teamsaying this was a change from earlier releases. The response from them was below (for "page" you can read "x" to have it relate to the question above):
我的一位同事发现了一个链接,表明这是设计使然,看来那篇文章的作者向 MVC 团队提出了一个问题,称这是对早期版本的更改。他们的回复如下(对于“页面”,您可以阅读“x”以使其与上述问题相关):
This is by design. Routing does not concern itself with query string values; it concerns itself only with values from RouteData. You should instead remove the entry for "page" from the Defaults dictionary, and in either the action method itself or in a filter set the default value for "page" if it has not already been set.
We hope to in the future have an easier way to mark a parameter as explicitly coming from RouteData, the query string, or a form. Until that is implemented the above solution should work. Please let us know if it doesn't!
这是设计使然。路由与查询字符串值无关;它只关心来自 RouteData 的值。您应该改为从 Defaults 字典中删除“page”条目,并在操作方法本身或过滤器中设置“page”的默认值(如果尚未设置)。
我们希望将来有一种更简单的方法来将参数标记为显式来自 RouteData、查询字符串或表单。在实施之前,上述解决方案应该有效。如果没有,请告诉我们!
So it appears that this behaviour is 'correct', however it is so orthogonal to the principle of least astonishmentthat I still can't quite believe it.
所以看起来这种行为是“正确的”,但是它与最小惊讶原则如此正交,我仍然不太相信它。
Edit #1: Note that the post details a method of how to provide default values, however this no longer works as the ActionMethodproperty he uses to access the MethodInfohas been removed in the latest version of ASP.NET MVC. I'm currently working on an alternative and will post it when done.
编辑 #1:请注意,该帖子详细介绍了如何提供默认值的方法,但是这不再有效,因为ActionMethod他用于访问的属性MethodInfo已在最新版本的 ASP.NET MVC 中删除。我目前正在研究替代方案,并在完成后发布。
Edit #2: I've updated the idea in the linked post to work with the Preview 5 release of ASP.NET MVC and I believe it should also work with the Beta release though I can't guarantee it as we haven't moved to that release yet. It's so simple that I've just posted it inline here.
编辑 #2:我已经更新了链接帖子中的想法以与 ASP.NET MVC 的 Preview 5 版本一起使用,我相信它也应该与 Beta 版本一起使用,但我不能保证它,因为我们没有移动到那个版本呢。这太简单了,我刚刚在此处内嵌发布。
First there's the default attribute (we can't use the existing .NET DefaultValueAttributeas it needs to inherit from CustomModelBinderAttribute):
首先是默认属性(我们不能使用现有的 .NET,DefaultValueAttribute因为它需要从 继承CustomModelBinderAttribute):
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class DefaultAttribute : CustomModelBinderAttribute
{
private readonly object value;
public DefaultAttribute(object value)
{
this.value = value;
}
public DefaultAttribute(string value, Type conversionType)
{
this.value = Convert.ChangeType(value, conversionType);
}
public override IModelBinder GetBinder()
{
return new DefaultValueModelBinder(this.value);
}
}
The the custom binder:
自定义活页夹:
public sealed class DefaultValueModelBinder : IModelBinder
{
private readonly object value;
public DefaultValueModelBinder(object value)
{
this.value = value;
}
public ModelBinderResult BindModel(ModelBindingContext bindingContext)
{
var request = bindingContext.HttpContext.Request;
var queryValue = request .QueryString[bindingContext.ModelName];
return string.IsNullOrEmpty(queryValue)
? new ModelBinderResult(this.value)
: new DefaultModelBinder().BindModel(bindingContext);
}
}
And then you can simply apply it to the method parameters that come in on the querystring, e.g.
然后你可以简单地将它应用于查询字符串中的方法参数,例如
public ActionResult Foo([Default(1)] int x)
{
// implementation
}
Works like a charm!
奇迹般有效!
回答by Richard Garside
I think the reason querystring parameters do not override the defaults is to stop people hacking the url.
我认为查询字符串参数不覆盖默认值的原因是为了阻止人们入侵 url。
Someone could use a url whose querystring included controller, action or other defaults you didn't want them to change.
有人可以使用其查询字符串包含控制器、操作或其他您不希望它们更改的默认值的 url。
I've dealt with this problem by doing what @Dale-Ragan suggested and dealing with it in the action method. Works for me.
我已经按照@Dale-Ragan 的建议处理了这个问题,并在 action 方法中处理了它。对我来说有效。
回答by Spoike
I thought the point with Routing in MVC is to get rid of querystrings. Like this:
我认为 MVC 中的路由的重点是摆脱查询字符串。像这样:
routes.MapRoute(
"test",
"Test/Foo/{x}",
new { controller = "Test", action = "Foo", x = 1 });

