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,请查看此答案。如果你正在寻找一个自定义模型活页夹的例子,那么看看这个和这个答案。

ASP.NET MVC:模型绑定中的类型转换

在回复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的评论,决定是:

  1. 如果字符串是正确的Guid字符串,则它将自动绑定(不需要其他任何东西),

  2. 如果字符串不是正确的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 GuidGuid?)应该很有用。例如(在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 "";
}