我的一位同事发现了一个链接,该链接表明这是设计使然,并且该文章的作者似乎向MVC 团队提出了一个问题,称这是对早期版本的更改。他们的回复如下(对于“页面”,您可以阅读“x”以使其与上述问题相关):
这是设计使然。路由本身不关心查询字符串值;它只关注来自 RouteData 的值。相反,您应该从 Defaults 字典中删除“page”条目,并在操作方法本身或过滤器中设置“page”的默认值(如果尚未设置)。
我们希望将来有一种更简单的方法来将参数标记为显式来自 RouteData、查询字符串或表单。在实施之前,上述解决方案应该可以工作。如果没有,请告诉我们!
所以看起来这种行为是“正确的”,但它与最小惊讶原则是如此正交,以至于我仍然不能完全相信它。
编辑#1:请注意,帖子详细说明了如何提供默认值的方法,但是这不再有效,因为ActionMethod
他用来访问的属性MethodInfo
已在最新版本的 ASP.NET MVC 中删除。我目前正在研究替代方案,完成后会发布。
编辑#2:我已经更新了链接帖子中的想法,以便与 ASP.NET MVC 的 Preview 5 版本一起使用,我相信它也应该与 Beta 版本一起使用,尽管我不能保证,因为我们没有移动到那个版本呢。它是如此简单,我刚刚将它内联发布在这里。
首先是默认属性(我们不能使用现有的 .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);
}
}
自定义活页夹:
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);
}
}
然后您可以简单地将其应用于查询字符串中的方法参数,例如
public ActionResult Foo([Default(1)] int x)
{
// implementation
}
奇迹般有效!