Asp.net web api 为什么ModelState.IsValid对于具有可为空参数的ApicController方法失败?

Asp.net web api 为什么ModelState.IsValid对于具有可为空参数的ApicController方法失败?,asp.net-web-api,model-binding,Asp.net Web Api,Model Binding,我有一个ApicController方法,它接受几个参数,如下所示: // POST api/files public HttpResponseMessage UploadFile ( FileDto fileDto, int? existingFileId, bool linkFromExistingFile, Guid? previousTrackingId ) { if

我有一个ApicController方法,它接受几个参数,如下所示:

    // POST api/files
    public HttpResponseMessage UploadFile
    (
        FileDto fileDto,
        int? existingFileId,
        bool linkFromExistingFile,
        Guid? previousTrackingId
    )
    {
        if (!ModelState.IsValid)
            return Request.CreateResponse(HttpStatusCode.BadRequest);

        ...
    }
当我发布到这里时,我将
FileDto
对象放在请求体中,其他参数放在查询字符串上

我已经发现,我不能简单地忽略可为null的参数——我需要将它们放在具有空值的查询字符串上。因此,当我不想为可为null的参数指定值时,我的查询如下所示:

http://myserver/api/files?existingFileId=&linkFromExistingFile=true&previousTrackingId=
这确实与我的控制器方法相匹配,当执行该方法时,可为null的参数确实是
null
(正如您所期望的)

但是,调用
ModelState.IsValid
返回
false
,当我检查ERORR时,它抱怨两个可为空的参数。(模型的其他位没有错误)。信息是:

需要一个值,但请求中不存在该值


为什么它认为需要/不存在一个值?当然,(a)可为null的值不是必需的,(b)值是(某种程度上)存在-在某种程度上是空的?

除了第一个答案之外,您应该能够让代码正常工作。如果您将所有可选的都移动到方法声明的末尾,并且我始终将它们设置为空,则允许省略url上的前缀:

FileDto fileDto,
bool linkFromExistingFile,
Guid? previousTrackingId = null,
int? existingFileId = null
但是

好的一点:一个带有前缀的空URL值。。。它是否与空值相同。。。关于字符串,
?q=
是空字符串还是空字符串

我曾试图在框架中找到引发这些错误的确切逻辑(并继续寻找),但在我的实验中,我确实发现直接在URL参数上指定绑定器似乎绕过了逻辑,并允许前缀后面的空值没有模型绑定错误

像这样:

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get(
        [FromUri(BinderType = typeof(TypeConverterModelBinder))] string q = null,
        [FromUri(BinderType = typeof(TypeConverterModelBinder))] int? value = null)
    {
        if (!ModelState.IsValid)
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }

        return new string[] { value.HasValue ? value.Value.ToString() : "", q };
    }     
}
公共类值控制器:ApiController
{
//获取api/值
公共数字获取(
[FromUri(BinderType=typeof(TypeConverterModelBinder))]字符串q=null,
[FromUri(BinderType=typeof(TypeConverterModelBinder))]int?value=null)
{
如果(!ModelState.IsValid)
{
抛出新的HttpResponseException(HttpStatusCode.BadRequest);
}
返回新字符串[]{value.HasValue?value.value.ToString():“”,q};
}     
}

我通过将所有参数移动到一个类中解决了这个问题

公共类上传文件模型{
public FileDto FileDto{get;set;}
public int?ExistingFileId{get;set;}
public bool linkfrom现有文件{get;set;}
公共Guid?PreviousTrackingId{get;set;}
}
公共HttpResponseMessageUploadFile([FromUri]UploadFileModel)
{
// ...
}

回答得很好,这很有帮助!我仍然很想知道为什么在参数级别应用绑定器可以神奇地实现这一点,而在全局设置绑定器则不行。我不喜欢在所有地方的参数上应用相同的绑定。这是在一个小时的谷歌搜索中解决我问题的唯一方法!谢谢这应该是正确的答案。我认为这是WebAPI中的一个bug,否则就没有什么意义了。用活页夹装饰所有arg也不是一个可行的选择。