当我有一个可为 null 的参数时,ModelState.IsValid 为 false
ModelState.IsValid is false when I have a nullable parameter
我在一个全新的 MVC Web API 项目中重现了我遇到的问题。
这是稍作修改的默认代码。
public string Get(int? id, int? something = null)
{
var isValid = ModelState.IsValid;
return "value";
}
如果你去 http://localhost/api/values/5?something=123
那么这工作正常,并且 isValid 是 true
。
如果您转到 http://localhost/api/values/5?something=
,则 isValid 为 false
。
我遇到的问题是,如果您为可为 null 的项目提供 null 或省略值,ModelState.IsValid 会标记一个验证错误,提示 "A value is required but was not present in the request."
ModelState 字典也如下所示:
有两个 something
条目,一个可为空,我不确定它是否重要。
知道如何解决这个问题,以便在省略可为 null 的参数或将其提供为 null 时模型有效吗?我在我的网站 api 中使用模型验证,如果每个带有可为空参数的方法都产生模型错误,它会破坏它。
从第二个参数中删除默认的空值。如果它不是 int,模型绑定器会将其设置为 null。
默认绑定模型似乎不能完全理解可为 null 的类型。正如问题中所见,它给出了三个参数错误,而不是预期的两个。
您可以使用自定义可为 null 的模型活页夹解决此问题:
模型活页夹
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;
}
}
用法
public ModelStateDictionary Get(
int? id,
[ModelBinder(typeof(NullableIntModelBinder))]int? something = null)
{
var isValid = ModelState.IsValid;
return ModelState;
}
改编自 asp.net 页面:http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api 供进一步阅读和在 class(控制器)级别而不是每个参数设置它的替代方法。
这处理了 3 个有效场景:
/test/5
/test/5?something=
/test/5?something=2
这首先将 "something" 设为 null。任何其他内容(例如 ?something=x
)都会出错。
如果您将签名更改为
int? somthing
(即删除 = null
),那么您必须明确提供参数,即 /test/5
将不是有效路线,除非您也调整路线。
您必须为可空类型注册一个自定义模型绑定器,因为默认绑定器也在为可空参数调用验证器,而后者认为这些空值无效。
模型活页夹:
public class NullableModelBinder<T> : System.Web.Http.ModelBinding.IModelBinder where T : struct
{
private static readonly TypeConverter converter = TypeDescriptor.GetConverter( typeof( T ) );
public bool BindModel( HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext )
{
var val = bindingContext.ValueProvider.GetValue( bindingContext.ModelName );
// Cast value to string but when it fails we must not suppress the validation
if ( !( val?.RawValue is string rawVal ) ) return false;
// If the string contains a valid value we can convert it and complete the binding
if ( converter.IsValid( rawVal ) )
{
bindingContext.Model = converter.ConvertFromString( rawVal );
return true;
}
// If the string does contain data it cannot be nullable T and we must not suppress this error
if ( !string.IsNullOrWhiteSpace( rawVal ) ) return false;
// String is empty and allowed due to it being a nullable type
bindingContext.ValidationNode.SuppressValidation = true;
return false;
}
}
报名人数:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ...
var provider = new SimpleModelBinderProvider(typeof(int?), new NullableModelBinder<int>());
config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
// ...
}
}
我找到了一个适合我的解决方法(只需从发送的数据中排除空值——而不是将值作为空值发送)。
见
我在一个全新的 MVC Web API 项目中重现了我遇到的问题。
这是稍作修改的默认代码。
public string Get(int? id, int? something = null)
{
var isValid = ModelState.IsValid;
return "value";
}
如果你去 http://localhost/api/values/5?something=123
那么这工作正常,并且 isValid 是 true
。
如果您转到 http://localhost/api/values/5?something=
,则 isValid 为 false
。
我遇到的问题是,如果您为可为 null 的项目提供 null 或省略值,ModelState.IsValid 会标记一个验证错误,提示 "A value is required but was not present in the request."
ModelState 字典也如下所示:
有两个 something
条目,一个可为空,我不确定它是否重要。
知道如何解决这个问题,以便在省略可为 null 的参数或将其提供为 null 时模型有效吗?我在我的网站 api 中使用模型验证,如果每个带有可为空参数的方法都产生模型错误,它会破坏它。
从第二个参数中删除默认的空值。如果它不是 int,模型绑定器会将其设置为 null。
默认绑定模型似乎不能完全理解可为 null 的类型。正如问题中所见,它给出了三个参数错误,而不是预期的两个。
您可以使用自定义可为 null 的模型活页夹解决此问题:
模型活页夹
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;
}
}
用法
public ModelStateDictionary Get(
int? id,
[ModelBinder(typeof(NullableIntModelBinder))]int? something = null)
{
var isValid = ModelState.IsValid;
return ModelState;
}
改编自 asp.net 页面:http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api 供进一步阅读和在 class(控制器)级别而不是每个参数设置它的替代方法。
这处理了 3 个有效场景:
/test/5
/test/5?something=
/test/5?something=2
这首先将 "something" 设为 null。任何其他内容(例如 ?something=x
)都会出错。
如果您将签名更改为
int? somthing
(即删除 = null
),那么您必须明确提供参数,即 /test/5
将不是有效路线,除非您也调整路线。
您必须为可空类型注册一个自定义模型绑定器,因为默认绑定器也在为可空参数调用验证器,而后者认为这些空值无效。
模型活页夹:
public class NullableModelBinder<T> : System.Web.Http.ModelBinding.IModelBinder where T : struct
{
private static readonly TypeConverter converter = TypeDescriptor.GetConverter( typeof( T ) );
public bool BindModel( HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext )
{
var val = bindingContext.ValueProvider.GetValue( bindingContext.ModelName );
// Cast value to string but when it fails we must not suppress the validation
if ( !( val?.RawValue is string rawVal ) ) return false;
// If the string contains a valid value we can convert it and complete the binding
if ( converter.IsValid( rawVal ) )
{
bindingContext.Model = converter.ConvertFromString( rawVal );
return true;
}
// If the string does contain data it cannot be nullable T and we must not suppress this error
if ( !string.IsNullOrWhiteSpace( rawVal ) ) return false;
// String is empty and allowed due to it being a nullable type
bindingContext.ValidationNode.SuppressValidation = true;
return false;
}
}
报名人数:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ...
var provider = new SimpleModelBinderProvider(typeof(int?), new NullableModelBinder<int>());
config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
// ...
}
}
我找到了一个适合我的解决方法(只需从发送的数据中排除空值——而不是将值作为空值发送)。
见