Почему ModelState.IsValid не работает для моего метода ApiController с параметрами, допускающими значение NULL?

У меня есть метод ApiController, который принимает несколько параметров, например:

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

        ...
    }

Когда я делаю POST для этого, я помещаю объект FileDto в тело запроса, а другие параметры в строку запроса.

Я уже обнаружил, что я не могу просто опустить параметры, допускающие значение NULL, — мне нужно поместить их в строку запроса с пустым значением. Итак, мой запрос выглядит так, когда я не хочу указывать значение для параметров, допускающих значение NULL:

http://myserver/api/files?existingFileId=&linkFromExistingFile=true&previousTrackingId=

Это соответствует моему методу контроллера, и когда метод выполняется, параметры, допускающие значение NULL, действительно равны null (как и следовало ожидать).

Однако вызов ModelState.IsValid возвращает false, и когда я просматриваю ошибки, он жалуется на оба параметра, допускающие значение NULL. (Другие биты модели не имеют ошибок). Сообщение:

Требуется значение, но его не было в запросе.

Почему он считает, что значение требуется/отсутствует? Наверняка (а) значение не требуется для значения, допускающего значение NULL, и (б) значение (вроде) присутствовало — нулевым способом?


person Gary McGill    schedule 17.08.2012    source источник


Ответы (2)


В дополнение к первому ответу вы должны иметь возможность заставить свой код работать, позволяя опустить префикс в URL-адресе, если вы переместите все необязательные в конец объявления метода, и я всегда устанавливаю их в NULL для хорошей меры:

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

Но

Хороший вопрос: пустое значение URL-адреса с префиксом... это то же самое, что и NULL... Размышляя о строках, является ли ?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 };
    }     
}
person Mark Jones    schedule 27.09.2012
comment
Отличный ответ, это помогло! Я все еще хотел бы знать, почему применение связывателя на уровне параметра волшебным образом делает эту работу, а глобальная установка - нет. Мне не нравится применять одни и те же привязки к параметрам повсюду. - person tcarvin; 18.04.2014
comment
Это единственное, что решило мою проблему за час гугления! Спасибо! - person jessewolfe; 01.02.2018

Я решил это, переместив все параметры в один класс.

public class UploadFileModel {
   public FileDto FileDto { get; set; }
   public int? ExistingFileId { get; set; }
   public bool LinkFromExistingFile { get; set; }
   public Guid? PreviousTrackingId { get; set; }
}

public HttpResponseMessage UploadFile([FromUri]UploadFileModel model)
{
   // ...
}
person Bertrand Marron    schedule 26.10.2012
comment
Это должен быть правильный ответ. Проблема, я считаю, это ошибка в WebAPI, в противном случае это не имеет особого смысла. Украшать все аргументы с помощью Binder — тоже не лучший вариант. - person AlexCode; 20.06.2018