如何处理返回PartialView的ajax调用的控制器操作中的模型状态错误

我有一个POST控制器动作,返回一个局部视图。 一切似乎都很容易。 但。 我使用$.ajax()加载它,将类型设置为html 。 但是当我的模型validation失败时,我想我应该抛出模型状态错误的错误。 但我的回复总是返回500 Server错误。

如何在不返回Json的情况下报告模型状态错误。 我仍然希望返回部分视图,我可以直接附加到某些HTML元素。

编辑

我还想避免返回错误局部视图。 这看起来像是在客户端上取得了成功。 让客户端解析结果以查看它是否真正成功容易出错。 设计人员可能会更改局部视图输出,仅此一项就会破坏function。 所以我想抛出exception,但是将正确的错误消息返回给ajax客户端。

我必须编写两个独立的部分,它们可以完全按照预期自动工作

所以当控制器动作过程成功时它应该返回一个局部视图,当事情不好时它应该抛出一些错误细节,所以客户端的事情会区分成功和失败,而不是总是处理成功。

有两个主要部分用于实现此目的:

  • 出现问题时抛出的自定义exception类 ,以便我们可以区分出于任何原因随时可能发生的一般exception以及与我们的处理相关的错误(最明显的是模型状态无效)
  • 捕获我们的自定义exception并根据该exception准备结果的exception操作filter ; 正如您将从代码中看到的,我们的自定义exception将保存有关模型状态错误的信息,因此此filter将能够返回自定义HTTP状态代码以及一些文本信息

然后详细说明……

外部链接 :所有这些信息(详细说明以及所有代码)也可以在我的博客上找到。 最新的代码更新将始终在那里发布 。

自定义exception类

这个类提供了两件事

  1. 使模型状态错误与常规exception区分开来变得简单
  2. 提供一些我以后可以使用的基本function

稍后在我的自定义错误filter中使用此类。

 public class ModelStateException : Exception { public Dictionary 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(); } public ModelStateException(ModelStateDictionary modelState) : this() { this.ModelState = modelState; if (!modelState.IsValid) { foreach (KeyValuePair state in modelState) { if (state.Value.Errors.Count > 0) { this.Errors.Add(state.Key, state.Value.Errors[0].ErrorMessage); } } } } } 

错误filter属性

当存在任何模型状态错误时,此属性有助于在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的错误以及我在filter中设置的正确信息。 然后将该信息显示给用户(当它与模型状态错误相关时,它显示用户应该修改的表单字段以使表单有效)。

 [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 */ ); } 

这使得我的代码可以重用任何模型状态错误,并且这些错误将被发送到客户端。

一个问题(现已解决)

但是仍然有一个与此代码相关的问题。 当我的错误操作filter设置StatusDescription并且该字符串包含一些特殊字符(如Č)时,我会在客户端上获得垃圾。 除非我使用IE(我使用的是版本8)。 FF和CH显示垃圾。 这就是为什么我设置编码,但它不起作用。 如果有人有这种特殊性的解决方法,我会非常乐意收听。
如果我在内容本身返回错误消息,一切都很好。 编码是正确的,我可以显示我想要的任何内容。

试试这个。

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