Как обрабатывать ошибки состояния модели в действии контроллера, вызванного ajax, который возвращает PartialView

У меня есть действие контроллера POST, которое возвращает частичный вид. Все кажется очень легким. но. Я загружаю его, используя $.ajax(), тип установки как html. Но когда моя проверка модели не удалась, я подумал, что я должен просто выбросить ошибку с ошибками состояния модели. Но мой ответ всегда возвращает 500 Server error.

Как я могу сообщить об ошибках состояния модели, не возвращая Json с каким-либо результатом. Я все равно хотел бы вернуться к частичному представлению, которое я могу непосредственно добавить к некоторому элементу HTML.

Изменить

Я также хотел бы избежать возврата частичного представления ошибки. Это будет иметь успех на клиенте. Когда клиент проанализирует результат, чтобы увидеть, подвержен ли он фактическому успеху ошибкам. Дизайнеры могут изменять выход частичного представления, и это само по себе может нарушить функциональность. Поэтому я хочу исключить исключение, но с правильным сообщением об ошибке, возвращаемым клиенту ajax.

2 ответа

Решение

Мне пришлось написать две отдельные части, которые автоматически работают точно так, как предполагалось.

Таким образом, он должен возвращать частичный вид, когда процесс действия контроллера преуспевает, и он должен вызывать ошибку с некоторыми деталями сбоев, когда все не так, так что на стороне клиента будут отличаться успех, а также отказ, а не всегда успешность обработки.

Для достижения этой цели используются две основные части:

  • Пользовательский класс исключений, который генерируется, когда что-то пойдет не так, поэтому мы можем различать общие исключения, которые могут произойти в любое время по любой причине и ошибкам, связанным с нашей обработкой (в первую очередь, недопустимым состоянием модели)
  • Фильтр исключений, который ловит наше пользовательское исключение и готовит результат на основе этого исключения; Как вы увидите из кода, наше пользовательское исключение будет содержать информацию о ошибках состояния модели, чтобы этот фильтр мог возвращать пользовательский код состояния HTTP, а также некоторую текстовую информацию.

Подробнее...

Внешняя ссылка. Вся эта информация (подробное объяснение, а также весь код) также доступна в моем блоге. Последние обновления кода всегда будут опубликованы там.

Пользовательский класс исключений

Этот класс предоставляет две вещи

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

Этот класс позже используется в моем настраиваемом фильтре ошибок.

public class ModelStateException : Exception
{
 public Dictionary<string, string=""> Errors { get; private set; }
 public ModelStateDictionary ModelState { get; private set; }
 public override string Message
 {
 get
 {
 if (this.Errors.Count > 0)
 {
 return this.Errors.First().Value;
 }
 return null;
 }
 }
 private ModelStateException()
 {
 this.Errors = new Dictionary<string, string="">();
 }
 public ModelStateException(ModelStateDictionary modelState) : this()
 {
 this.ModelState = modelState;
 if (!modelState.IsValid)
 {
 foreach (************<string, modelstate=""> state in modelState)
 {
 if (state.Value.Errors.Count > 0)
 {
 this.Errors.Add(state.Key, state.Value.Errors[0].ErrorMessage);
 }
 }
 }
 }
}
</string,></string,></string,>

Атрибут фильтра ошибок

Этот атрибут помогает возвращать ошибки клиенту с точки зрения кодов ошибок HTTP при наличии ошибок состояния модели.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class HandleModelStateExceptionAttribute : FilterAttribute, IExceptionFilter
{
 public void OnException(ExceptionContext filterContext)
 {
 if (filterContext == null)
 {
 throw new ArgumentNullException("filterContext");
 }
 if (filterContext.Exception != null && typeof(ModelStateException).IsInstanceOfType(filterContext.Exception) && !filterContext.ExceptionHandled)
 {
 filterContext.ExceptionHandled = true;
 filterContext.HttpContext.Response.Clear();
 filterContext.HttpContext.Response.ContentEncoding = Encoding.UTF8;
 filterContext.HttpContext.Response.HeaderEncoding = Encoding.UTF8;
 filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
 filterContext.HttpContext.Response.StatusCode = 400;
 filterContext.HttpContext.Response.StatusDescription = (filterContext.Exception as ModelStateException).Message;
 }
 }
}

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

[HandleModelStateException]
public ActionResult AddComment(MyModel data)
{
 // check if state is valid
 if (!this.ModelState.IsValid)
 {
 throw new ModelStateException(this.ModelState);
 }
 // get data from store
 return PartialView("Comment", /* store data */ );
}

Это делает мой код повторно используемым с любыми ошибками состояния модели, и они будут отправлены клиенту так, как должны.

Одна единственная проблема (теперь разрешена)

Но есть еще одна проблема, связанная с этим кодом. Когда мой фильтр действий с ошибкой устанавливает StatusDescription, и эта строка содержит некоторые специальные символы, такие как Č, я получаю мусор на клиенте. Если я не использую IE (я использую версию 8). FF и CH показывают мусор. Вот почему я устанавливаю кодировки, но это не работает. Если у кого-то есть обходной путь для этой особенности, я был бы более чем рад слушать. Если я верну сообщение об ошибке в самом содержимом, все будет хорошо. Кодировка правильная, и я могу отображать все, что захочу.


Попробуйте это.

public ActionResult DoAjaxAction(Entity entity)
{
 if(ModelState.IsValid)
 {
 return PartialView("Valid_View", entity);
 }
 else
 {
 return PartialView("Invalid_View", entity);
 } 
}

licensed under cc by-sa 3.0 with attribution.