ASP.NET MVC Validation Framework при публикации через jquery $ .ajax? - PullRequest
6 голосов
/ 09 октября 2009

Существует множество очень хороших постов и объяснений, как реализовать валидацию с ASP.NET MVC, и я предпочитаю один из них:

Однако мне действительно нравится вызывать ActionMethods через метод jquery $ .ajax. Одна из причин, по которой я хочу использовать $ .ajax, заключается в том, что будет много частичных представлений, загружаемых на страницу динамически (даже форма для создания сущности) посредством вызовов $ .ajax, и я не могу просто вернуть представление - Я потеряю весь динамически загружаемый контент.

Чтобы получить более полное представление о проблеме, я опубликую простой код, объясняющий, как бы я хотел вызывать действия контроллеров и обрабатывать ответы в клиентском коде jquery.

Контроллеры ActionMethod:

    public ActionResult CreateCustomer(string name, string accountNumber)
    {
        try
        {
            CustomerService.InsertCustomer(name, accountNumber);

            return Json(new ActionInfo()
            {
                Success = true,
                Message = "Customer Is Successfully Created"
            });

        }
        catch (Exception ex)
        {
            return Json(new ActionInfo()
            {
                Success = false,
                Message = ex.Message
            });
        }
    }

Вызов и обработка в коде клиента:

$.ajax({
type: "POST",
url: $form.attr('action'),// /MyController/CreateCustomer
data: $form.serialize(),
error: HandleUnespectedError,
dataType: "json",
success: function(response) {

    if (response.Success)
        alert("Success: " + response.Message);
    else
        alert("Error: " + response.Message);
}});

Есть ли хороший способ заставить некоторые из этих платформ валидации работать так, как мне нужно? Я знаю, что могу добавить ошибки валидации в ActionInfo, а затем обработать их в клиенте, но это будет я полагаю, это уже здание моей единственной проверки.

Ответы [ 2 ]

5 голосов
/ 15 октября 2009

Я добился большого успеха при выполнении проверки через AJAX с использованием атрибутов аннотаций данных. Чтобы проверить достоверность ваших данных, вам нужно использовать свойство контроллера ModelState, которое имеет собственное свойство, называемое IsValid. Я настоятельно рекомендую взглянуть на учебник по атрибутам проверки аннотаций данных с официального сайта ASP.NET MVC.

Прежде всего, вы захотите изменить действие вашего контроллера, чтобы он принимал объект модели в качестве параметра, а не отдельное имя и номер счета. Это значительно упростит выполнение проверки, которую я продемонстрирую ниже. Исходя из вашего примера, я думаю, что ваш объект модели называется или будет называться Customer. У вас может быть следующий код для определения объекта модели и действия вашего контроллера ...

// model object
public class Customer
{
  public Int32 Id {get; set;}
  public String Name {get; set;}
  public String AccountNumber {get; set;}
}

// controller
public class CustomerController : Controller
{
  public ActionResult CreateCustomer( [Bind(Exclude = "Id")] Customer customer )
  {
     // controller action code
  }
}

1010 *
*

Убедитесь, что поля формы имеют имена, совпадающие с именами свойств объекта Customer, чтобы ASP.NET MVC мог автоматически связывать их. Атрибут «Bind» в данном случае говорит ASP.NET MVC игнорировать свойство «Id» класса Customer при привязке полей формы к свойствам модели. Поскольку это новый клиент, у нас пока нет идентификатора, поэтому мы можем спокойно оставить идентификатор как любое значение по умолчанию и покинуть слой данных, чтобы выяснить, как лучше его сгенерировать.

Как только контроллер сконструировал объект модели для метода действия, его достоверность можно легко проверить с помощью свойства ModelState.IsValid. Как и следовало ожидать, он вернет true, если свойства модели верны, или false, если 1 или более свойств недействительны.

Из исходного вопроса выясняется, что метод CustomerService.InsertCustomer выдает исключения, когда проверка не проходит. Это совершенно не нужно. InsertCustomer должен выполнять только те операции с данными, которые необходимы для вставки новой записи. Если вы не хотите абстрагировать специфичные для реализации исключения, такие как SqlException, InsertCustomer на самом деле не должен перехватывать или генерировать какие-либо исключения, но, скорее всего, может просто позволить любым исключениям пузыриться до контроллера (или от того, кем бы он ни был).

Конечным результатом всего этого может быть действие контроллера, которое выглядит следующим образом:

public ActionResult CreateCustomer( [Bind(Exclude = "Id")] Customer customer )
{
  // model is invalid
  if (!ModelState.IsValid)
  {
    return Json(new ActionInfo()
    {
      Success = false,
      Message = "Validation failed" // you will probably want a more robust message :-)
    });
  }

  // service method accepts a Customer object rather than arbitrary strings  
  CustomerService.InsertCustomer(customer);

  return Json(new ActionInfo()
  {
    Success = true,
    Message = "Customer created successfully."
  });

}


Если вы хотите сообщить о непредвиденных ошибках, например об исключениях, связанных с базой данных, то вы, безусловно, можете добавить блок try / catch вокруг вызова InsertCustomer и вернуть необходимый результат для отображения сообщения об ошибке обратно клиенту.

2 голосов
/ 27 ноября 2010

Прошло больше года с тех пор, как вы задали свой вопрос, но я рассмотрел проверку на стороне сервера с помощью вызовов Ajax в моем блоге , который может вас заинтересовать. Я вижу, что вы возвращаете ошибочные результаты как успешные вызовы HTTP. Я справился с этим по-другому (я думаю, это более правильно, поскольку $.ajax имеет возможность ответа success и error). А ваш конкретный пример - прекрасный пример, который можно реализовать с помощью функций, которые я объясню в своем блоге.

По сути, вместо того, чтобы всегда возвращать успешный ответ (но со свойствами, установленными, чтобы сообщить клиенту, что обработка на стороне сервера не удалась), я скорее выбрасываю исключение на сервере и обрабатываю его соответственно на клиенте. Я использую пользовательский класс ModelStateException вместе с HandleModelStateException фильтром действий.

...