当我有一个可以为null的参数时,ModelState.IsValid为false

Nib*_*Pig 11 asp.net-mvc model-binding asp.net-web-api

我在一个全新的MVC Web API项目中重现了我遇到的问题.

这是默认代码,略有修改.

public string Get(int? id, int? something = null)
{
    var isValid = ModelState.IsValid;
    return "value";
}
Run Code Online (Sandbox Code Playgroud)

如果你去,http://localhost/api/values/5?something=123那么这很好,isValid是true.

如果你去http://localhost/api/values/5?something=那么isValid是false.

我遇到的问题是,如果为可以为空的项提供null或省略的值,ModelState.IsValid会标记验证错误 "A value is required but was not present in the request."

ModelState字典也如下所示:

在此输入图像描述

有两个条目something,一个可以为空,我不确定它是否重要.

知道如何解决这个问题,以便在省略可空参数或提供为null时模型是有效的吗?我在我的web api中使用模型验证,如果每个带有可为空参数的方法都会产生模型错误,它就会破坏它.

fre*_*n-m 7

似乎默认绑定模型并不完全理解可为空类型。正如问题中所见,它给出了三个参数错误,而不是预期的两个。

您可以使用自定义的可为空模型绑定器解决此问题:

模型绑定器

public class NullableIntModelBinder : IModelBinder
{
    public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(int?))
        {
            return false;
        }

        ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (val == null)
        {
            return false;
        }

        string rawvalue = val.RawValue as string;

        // Not supplied : /test/5
        if (rawvalue == null)
        {
            bindingContext.Model = null;
            return true;
        }

        // Provided but with no value : /test/5?something=
        if (rawvalue == string.Empty)
        {
            bindingContext.Model = null;
            return true;
        }

        // Provided with a value : /test/5?something=1
        int result;
        if (int.TryParse(rawvalue, out result))
        {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value to int");
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

public ModelStateDictionary Get(
    int? id, 
    [ModelBinder(typeof(NullableIntModelBinder))]int? something = null)
{
    var isValid = ModelState.IsValid;

    return ModelState;
}
Run Code Online (Sandbox Code Playgroud)

改编自 asp.net 页面:http : //www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api以供进一步阅读和替代方法将其设置在类(控制器)级别而不是每个参数。

这处理 3 个有效场景:

/test/5
/test/5?something=
/test/5?something=2
Run Code Online (Sandbox Code Playgroud)

这首先将“某物”作为空值。其他任何东西(例如?something=x)都会出错。

如果您将签名更改为

int? somthing
Run Code Online (Sandbox Code Playgroud)

(即 remove = null)那么您必须明确提供该参数,即/test/5除非您也调整您的路线,否则将不是有效的路线。