ASP.NET MVC 3 — установка пустого поля в DTO при привязке к HTTP POST вместо сбоя

У меня есть действие контроллера HttpPost, которое принимает объект DTO простой формы.

[HttpPost]
public ViewResult Index(ResultQueryForm queryForm)
{
   ...
}

public class ResultQueryForm
{
   public DateTime? TimestampStart { get; set; }
   public DateTime? TimestampEnd { get; set; }
   public string Name { get; set; }
}

Объект DTO имеет пустые поля даты и времени, используемые для создания диапазона. Причина, по которой для него установлено значение nullable, заключается в том, что форма, привязанная к модели, является формой запроса, и пользователю не нужно вводить значение даты в форму.

Проблема, с которой я сталкиваюсь, заключается в том, что если пользователь вводит недопустимую дату, я бы хотел, чтобы привязка модели MVC по умолчанию предоставляла сообщение об ошибке. Это происходит безупречно, если у меня есть действие контроллера, которое принимает DateTime? type в качестве аргумента, но так как я передаю DTO, который содержит DateTime? type привязка модели просто устанавливает DateTime? переменная в ноль. Это приводит к неожиданным результатам.

Примечание:

[HttpPost]
public ViewResult Index(DateTime? startDate)
{
   // If the user enters an invalid date, the controller action won't even be run because   the MVC model binding will fail and return an error message to the user
}

Можно ли как-то сказать, что привязка модели MVC «сбой», если она не может привязать DateTime? значение объекта DTO формы, вместо того, чтобы просто установить его в значение null? Есть ли способ лучше? Передача каждого отдельного ввода формы контроллеру невозможна из-за большого количества свойств в объекте form/dto (я исключил многие из них для удобства чтения).


person contactmatt    schedule 03.01.2012    source источник
comment
Вы проверили ModelState.IsValid?   -  person Max Toro    schedule 03.01.2012


Ответы (2)


Вы можете проверить свою модель в действии контроллера.

if(!Model.IsValid)
{
  return View(); // ooops didn't work
}
else
{
  return RedirectToAction("Index"); //horray
}

Конечно, вы можете поместить туда все, что хотите, и вернуть объект Json, если хотите отобразить его на своей странице.

Также вам нужно добавить ValidateInput(true) вверху вашего метода действия, например: [HttpPost, ValidateInput(true)]

person bobek    schedule 03.01.2012
comment
Что делает атрибут ValidateInput(true)? - person contactmatt; 03.01.2012
comment
В вашей модели вы можете указать методы проверки. Вы также можете сделать [Обязательно], если хотите, чтобы поле было обязательным. Если бы у вас был ValidateInput(false) в вашем методе действия, он не учитывал бы ваши атрибуты проверки. Посмотрите ответ @olivehour. Вы можете объединить мое и его, чтобы получить хорошее решение. - person bobek; 03.01.2012
comment
Я думал, что вам нужно было только поставить [ValidateInput(false)], если вы хотите, чтобы ваша форма могла отправлять текст HTML в метод действия. Я никогда не помещал [ValidateInput(true)] в свои методы действий, и ModelState.IsValid по-прежнему возвращает false при ошибках проверки на уровне модели. - person danludwig; 03.01.2012
comment
о да, только для Model.IsValid вам это не нужно. Но если вы хотите выполнить некоторую проверку jquery/js, вам это нужно. - person bobek; 04.01.2012

Я думаю, вы можете создать для этого собственный атрибут ValidationAttribute.

[DateTimeFormat(ErrorMessage = "Invalid date format.")]
public DateTime? TimestampStart { get; set; }
[DateTimeFormat(ErrorMessage = "Invalid date format.")]
public DateTime? TimestampEnd { get; set; }


[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DateTimeFormatAttribute : ValidationAttribute
{
    public override bool IsValid(object value) {

        // allow null values
        if (value == null) { return true; }

        // when value is not null, try to convert to a DateTime
        DateTime asDateTime;
        if (DateTime.TryParse(value.ToString(), out asDateTime)) {
            return true; // parsed to datetime successfully
        }
        return false; // value could not be parsed
    }
}
person danludwig    schedule 03.01.2012