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

Posted

技术标签:

【中文标题】如何处理返回 PartialView 的 ajax 调用控制器操作中的模型状态错误【英文标题】:How to handle model state errors in ajax-invoked controller action that returns a PartialView 【发布时间】:2011-01-16 17:24:15 【问题描述】:

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

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

编辑

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

【问题讨论】:

【参考方案1】:

解决方案

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

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

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

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

接着说细节……

外部链接:所有这些信息(详细解释以及所有代码)也可以在我的博客上找到。最新的代码更新将始终是published there。

自定义异常类

这个类提供了两个东西

    让区分模型状态错误和常规异常变得简单 提供一些我以后可以使用的基本功能

这个类稍后在我的自定义错误过滤器中使用。

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 (KeyValuePair<string, ModelState> state in modelState)
            
                if (state.Value.Errors.Count > 0)
                
                    this.Errors.Add(state.Key, state.Value.Errors[0].ErrorMessage);
                
            
        
    

错误过滤属性

当有任何模型状态错误时,此属性有助于以 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 显示垃圾。这就是我设置编码但它不起作用的原因。如果有人对这种特殊性有解决方法,我会很乐意倾听。 如果我在内容本身中返回错误消息,一切都很好。编码是正确的,我可以显示任何我想要的。

【讨论】:

【参考方案2】:

试试这个。

public ActionResult DoAjaxAction(Entity entity)

   if(ModelState.IsValid)
   
     return PartialView("Valid_View", entity);
   
   else
   
     return PartialView("Invalid_View", entity);
    


【讨论】:

这将不允许从失败的结果中检测成功。所以最好也设置一些 HTTP 错误代码,然后在客户端处理这个 - 如果代码是 xx,那么内容是错误部分。 这还不是解决方案。我第二个@queen3。我的 $.ajax.success() 函数使用 HTML 结果并将其显示在某个容器中。根本不应该在那里显示错误。它们应该被捕获并显示在任何类型的通知区域中。所以这不是一个真正的解决方案。我仍然想触发 $.ajax.error() 函数,但错误字符串正确。 @Robert Koritnik:您始终可以返回带有两个字段的 JsonResult。一种说法是发布的数据是否有效,第二种说法是 html。 @LukLed:我想避免的事情,因为我想使用现有的部分视图基础设施。这样我要么必须在我的代码中提供 HTML,这使得它与代码相关联(没有代码分离),这使得设计人员难以更改/设计/主题......我想按原样使用部分视图,但不是自己打电话给 ExecuteResult。必须有一种方法可以引发异常并将异常消息实际传递给客户端。 @Robert Koritnik:你有没有看这个问题:***.com/questions/377644/…?

以上是关于如何处理返回 PartialView 的 ajax 调用控制器操作中的模型状态错误的主要内容,如果未能解决你的问题,请参考以下文章

ajax如何处理服务器返回的3种数据格式

[当PHP代码失败但发送200时如何处理AJAX?

jquery ajax请求时如果页面卡主 多次发出相同请求 如何处理

HttpOnly cookie 如何处理 AJAX 请求?

你如何处理来自 AJAX 调用的错误?

如何处理耗时的ajax请求