ASP.NET MVC:模型绑定中的类型转换
本文关键字:类型转换 绑定 模型 NET MVC ASP | 更新日期: 2023-09-27 18:28:39
在ASP.NET MVC 5中,是否有方法将控制器操作中的参数从一种类型转换为另一种类型?
示例。行动方法如下:
public string Test(Guid input) {
return "";
}
如果使用参数"input=hello"调用该方法,则我会收到错误消息:"参数字典包含方法"System.String Test(System.Guid)的不可为null类型"System.Guid"的参数"input"的null条目"中的"。可选参数必须是引用类型、可为null的类型,或者声明为可选参数。"
我想要的是尝试根据特定(自定义)规则将参数强制转换为Guid。这是关于模型绑定的问题吗?解决这项任务的可能方法是什么?对不起我的英语。
关于答案。如果您只想在Guid参数无效的情况下为其分配null,请查看此答案。如果你正在寻找一个自定义模型活页夹的例子,那么看看这个和这个答案。
在回复Hoborg的例子时,https://stackoverflow.com/posts/26676337/revisions如果需要,以下将返回null值或Guid参数。
public class NullableGuidBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(Guid?))
{
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
string input = valueResult.AttemptedValue;
if (string.IsNullOrEmpty(input) || input == "0")
{
// return null, even if input = 0
// however, that is dropdowns' "guid.empty")
// base.BindModel(...) would fail converting string to guid,
// Guid.Parse and Guid.TryParse would fail since they expect 000-... format
// add the property to modelstate dictionary
var modelState = new ModelState { Value = valueResult };
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return null;
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
在控制器中绑定如下
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SelectAction(
[ModelBinder(typeof(NullableGuidBinder))] Guid? id)
{
// your stuff
}
根据@AndreiV和@AntP的评论,决定是:
-
如果字符串是正确的Guid字符串,则它将自动绑定(不需要其他任何东西),
-
如果字符串不是正确的Guid字符串,则应该
2.1.在动作的主体中进行转换(在我看来,这需要代码复制),或
2.2.设置自定义(用户定义)模型绑定器。以下是最后一种方法(模型绑定器)的代码。
// This is an example.
// Note the returning of null which is undesired.
// Also it does not deal with exceptions handling. Use it only as a stub.
public class ExtendedModelBinder : DefaultModelBinder {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
if (!(bindingContext.ModelType == typeof(Guid)))
return base.BindModel(controllerContext, bindingContext);
if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
return null;
string input = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
if (string.IsNullOrEmpty(input))
return null;
Guid g;
if (Guid.TryParse(input, out g))
return g;
var bytes = HttpServerUtility.UrlTokenDecode(s);
var result = new Guid(bytes);
return result;
}
}
必须在Application_Start中注册:
ModelBinders.Binders.Add(typeof(Guid), new RealtyGuide.WebSite.Extensions.MyModelBinder());
可以使用属性而不是全局注册绑定器(请参阅此处),但我不会使用它,因为这会在我的任务中带来不必要的代码重复。
参考:1、2、3
我在搜索Guid
绑定时偶然发现了这个问题,该绑定在值无效时会有一个优雅的回退。如果不必知道实际提供的值,那么使用nullable Guid
(Guid?
)应该很有用。例如(在ASP.NET Web API中测试):
[Route("Test")]
[HttpGet]
public string Test(Guid? input = null)
如果提供了有效的Guid
,则将填充输入。否则,它将是null
。
尝试input="helo"是错误的方法。Guid必须包含32位数值示例(12345678910111213141516171819202)
尝试此输入=12345678910111213141516171819202,通过给出像32位数字这样的值,Guid值接受它。则该方法将不会显示相同的错误。
var input = 12345678910111213141516171819202;
public string Test(Guid input) {
return "";
}