我在一个全新的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或省略的值,ModelState.IsValid会标记验证错误"A value is required but was not present in the request."
ModelState字典也如下所示:
有两个something
条目,一个可以为空,我不确定它是否重要。
任何想法如何解决这个问题,以便在省略可空参数或提供为null时模型是有效的?我在我的web api中使用模型验证,如果每个带有可为空参数的方法都会产生模型错误,它就会破坏它。
答案 0 :(得分:4)
看来默认绑定模型并不完全理解可空类型。如问题所示,它给出了三个参数错误,而不是预期的两个错误。
您可以使用自定义可为空的模型绑定器解决此问题:
模型活页夹
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以进行进一步阅读,并将其设置为类(控制器)级别而非每个参数。
这处理3个有效场景:
/test/5
/test/5?something=
/test/5?something=2
这首先将“something”视为null。其他任何事情(例如?something=x
)都会出错。
如果您将签名更改为
int? somthing
(即删除= null
)然后您必须明确提供参数,即除非您调整路线,否则/test/5
将不是有效路线。
答案 1 :(得分:0)
从第二个参数中删除默认的空值。如果模型绑定器不是int。
,则将其设置为null答案 2 :(得分:0)
您必须为可空类型注册自定义模型绑定器,因为默认绑定器也为可为空的参数调用验证器,后者将这些空值视为无效。
Model Binder:
public class NullableModelBinder<T> : IModelBinder where T : struct
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null)
return false;
var rawVal = val.RawValue as string;
if (rawVal == null)
return false;
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.IsValid(rawVal))
{
bindingContext.Model = converter.ConvertFromString(rawVal);
return true;
}
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);
// ...
}
}
答案 3 :(得分:0)
我找到了一个可行的解决方法(只需从发送的数据中排除空值 - 而不是将值作为空值发送)。