2012-07-06 101 views
27

我试图按照 This link中的建议将错误返回给控制器的调用,以便客户端可以采取适当的措施。 控制器通过jquery AJAX通过javascript调用。只有当我没有将状态设置为错误时,我才会返回Json对象。 下面是示例代码返回带有错误状态码MVC的JSON

if (response.errors.Length > 0) 
    Response.StatusCode = (int)HttpStatusCode.BadRequest; 
return Json(response); 

我得到JSON的,如果我不设置的StatusCode。 如果我设置了状态码,我会返回状态码,但不会返回Json错误对象。

更新 我想发送一个Error对象作为JSON,以便它可以处理ajax的错误回调。

回答

26

我找到了解决办法here

我不得不创建一个动作过滤器来覆盖MVC

这里的默认行为是我的异常类

class ValidationException : ApplicationException 
{ 
    public JsonResult exceptionDetails; 
    public ValidationException(JsonResult exceptionDetails) 
    { 
     this.exceptionDetails = exceptionDetails; 
    } 
    public ValidationException(string message) : base(message) { } 
    public ValidationException(string message, Exception inner) : base(message, inner) { } 
    protected ValidationException(
    System.Runtime.Serialization.SerializationInfo info, 
    System.Runtime.Serialization.StreamingContext context) 
     : base(info, context) { } 
} 

请注意,我有构造函数初始化我的JSON。这里是动作过滤器

public class HandleUIExceptionAttribute : FilterAttribute, IExceptionFilter 
{ 
    public virtual void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 
     if (filterContext.Exception != null) 
     { 
      filterContext.ExceptionHandled = true; 
      filterContext.HttpContext.Response.Clear(); 
      filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
      filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; 
      filterContext.Result = ((ValidationException)filterContext.Exception).myJsonError; 
     } 
    } 

现在,我有行动过滤器,我来装饰我的控制器与过滤器属性

[HandleUIException] 
public JsonResult UpdateName(string objectToUpdate) 
{ 
    var response = myClient.ValidateObject(objectToUpdate); 
    if (response.errors.Length > 0) 
    throw new ValidationException(Json(response)); 
} 

当错误被抛出的动作过滤器,它实现个IExceptionFilter被调用和我在错误回调中返回客户端上的Json。

+10

如果读者认为“所有必要?”,答案是“否”。 - 我和@Sarath处于相同的情况,并希望返回一个HTTP错误代码和一些描述错误的JSON数据。事实证明,我可以只使用清除响应的行,IIS自定义错误将被跳过,并且状态码已被占用。我将这3行放在我的控制器的Action中,在这3行之后,我只是像往常一样返回我的JSON数据。像魅力一样工作。 – 2013-02-10 16:17:02

+6

事实确实如此,但为了可重复使用,您可能希望按照答案的指示进行操作,而不是将相同的代码复制/过滤到每个操作中。 – Hades 2013-06-06 15:35:39

+0

如果我设置了'StatusCode = 500',那么它会忽略我的JsonResponse,而是返回“页面无法显示,因为发生了内部服务器错误。”。不知道这是由于OWIN管道中的差异还是由于什么。 – AaronLS 2016-04-21 19:36:33

4

你必须返回设置的StatusCode后JSON错误对象自己,像这样......

if (BadRequest) 
{ 
    Dictionary<string, object> error = new Dictionary<string, object>(); 
    error.Add("ErrorCode", -1); 
    error.Add("ErrorMessage", "Something really bad happened"); 
    return Json(error); 
} 

另一种方法是有一个JsonErrorModel和填充它

public class JsonErrorModel 
{ 
    public int ErrorCode { get; set;} 

    public string ErrorMessage { get; set; } 
} 

public ActionResult SomeMethod() 
{ 

    if (BadRequest) 
    { 
     var error = new JsonErrorModel 
     { 
      ErrorCode = -1, 
      ErrorMessage = "Something really bad happened" 
     }; 

     return Json(error); 
    } 

    //Return valid response 
} 

看看答案here以及

+4

我已经有响应对象的错误。问题是我得到“错误的请求”,而不是JSON对象。如果我没有设置状态,我会得到带有错误的JSON,但客户端并不知道它是一个异常情况。 – Sarath 2012-07-06 22:50:52

+0

@Sarath检查答案中的链接。你需要在jQuery – 2012-07-07 14:55:05

+1

中使用ajax方法的error属性,我所面临的问题是如果我设置了状态,那么在响应中我不会返回JSON。你指出的答案是我到底在做什么。问题是如果我设置响应状态我没有得到JSON。 – Sarath 2012-07-07 19:48:58

4

您需要决定是否想要“HTTP级别错误”(即哪些错误代码适用)或“应用程序级别错误”(即w你自定义的JSON响应是为了)。

如果错误代码设置为非2xx(成功范围),则使用HTTP的大多数高级对象都不会查看响应流。在你的情况下,你明确地设置错误代码为失败(我认为403或500)并强制XMLHttp对象忽略响应的主体。

修复 - 处理客户端的错误条件或不设置错误代码并返回带有错误信息的JSON(详见Sbossb回复)。

+1

感谢您的回复。客户如何知道有一个例外,我没有设置状态码? – Sarath 2012-07-06 22:47:29

+0

@Sarath,与你现在在服务器端(假设JavaScript客户端)正在做同样的检查'response.errors && response.errors.length> 0'。 – 2012-07-06 22:51:32

+2

@Alexi是的。但我想隐式通知客户发生错误。也就是说,我想处理这个失败的Ajax调用回调而不是成功的回调,然后查找errors.length。 – Sarath 2012-07-06 23:00:42

17

这个问题有一个非常优雅的解决方案,只需通过网站配置您的网站。配置:

<system.webServer> 
    <httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough"/> 
</system.webServer> 

来源:https://serverfault.com/questions/123729/iis-is-overriding-my-response-content-if-i-manually-set-the-response-statuscode

+1

BOOM!我正在寻找的答案。它在本地很好,但不在远程服务器上。我知道这可以通过一些配置设置来完成。干杯! – ThiagoPXP 2015-12-08 07:40:06

+0

绝对试试这个,如果它在当地工作但不是天蓝色! – Icycool 2017-01-06 20:29:30

+0

对于问题是,我在本地(开发)机器中获取StatusCode和Json响应,但从生产中运行它时,我只是获取StatusCode。 这个解决方案是最简单的解决方案。 – Vikneshwar 2018-01-18 05:14:40

2

如果你的需求是不一样复杂萨拉特的你可以逃脱的东西更简单:

[MyError] 
public JsonResult Error(string objectToUpdate) 
{ 
    throw new Exception("ERROR!"); 
} 

public class MyErrorAttribute : FilterAttribute, IExceptionFilter 
{ 
    public virtual void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext == null) 
     { 
     throw new ArgumentNullException("filterContext"); 
     } 
     if (filterContext.Exception != null) 
     { 
     filterContext.ExceptionHandled = true; 
     filterContext.HttpContext.Response.Clear(); 
     filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
     filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; 
     filterContext.Result = new JsonResult() { Data = filterContext.Exception.Message }; 
     } 
    } 
} 
6

最巧妙的解决方案,我发现是创建自己的JsonResult,它扩展了原始实现并允许指定一个HttpStatusCode:

public class JsonHttpStatusResult : JsonResult 
{ 
    private readonly HttpStatusCode _httpStatus; 

    public JsonHttpStatusResult(object data, HttpStatusCode httpStatus) 
    { 
     Data = data; 
     _httpStatus = httpStatus; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     context.RequestContext.HttpContext.Response.StatusCode = (int)_httpStatus; 
     base.ExecuteResult(context); 
    } 
} 

你可以在你的控制器动作,然后用这个像这样:从理查德·加赛德答案

if(thereWereErrors) 
{ 
    var errorModel = new { error = "There was an error" }; 
    return new JsonHttpStatusResult(errorModel, HttpStatusCode.InternalServerError); 
} 
3

大厦,这里的ASP.Net Core版本

public class JsonErrorResult : JsonResult 
{ 
    private readonly HttpStatusCode _statusCode; 

    public JsonErrorResult(object json) : this(json, HttpStatusCode.InternalServerError) 
    { 
    } 

    public JsonErrorResult(object json, HttpStatusCode statusCode) : base(json) 
    { 
     _statusCode = statusCode; 
    } 

    public override void ExecuteResult(ActionContext context) 
    { 
     context.HttpContext.Response.StatusCode = (int)_statusCode; 
     base.ExecuteResult(context); 
    } 

    public override Task ExecuteResultAsync(ActionContext context) 
    { 
     context.HttpContext.Response.StatusCode = (int)_statusCode; 
     return base.ExecuteResultAsync(context); 
    } 
} 

然后在你的控制器,作为回报如下:

// Set a json object to return. The status code defaults to 500 
return new JsonErrorResult(new { message = "Sorry, an internal error occurred."}); 

// Or you can override the status code 
return new JsonErrorResult(new { foo = "bar"}, HttpStatusCode.NotFound); 
+1

谢谢你。 – aman 2018-01-30 15:39:40

相关问题