使用MVC返回带错误状态码的JSON

62

我想按照这个链接中的建议,向控制器返回一个错误,以便客户端可以采取适当的行动。该控制器是通过jquery AJAX从javascript中调用的。只有当我不将状态设置为错误时,才会收到Json对象。

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

如果我不设置状态码,我就会得到Json。 如果我设置状态码,我会收到状态码,但不会收到Json错误对象。

更新 我希望将一个错误对象作为JSON发送,这样可以在ajax的错误回调中处理它。

13个回答

3
如果你的需求不像Sarath那么复杂,你可以使用更简单的方法:
[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 };
      }
   }
}

2

我正在运行Asp.Net Web Api 5.2.7,看起来JsonResult类已更改为使用泛型和异步执行方法。 我最终修改了Richard Garside的解决方案:

public class JsonHttpStatusResult<T> : JsonResult<T>
{
    private readonly HttpStatusCode _httpStatus;

    public JsonHttpStatusResult(T content, JsonSerializerSettings serializer, Encoding encoding, ApiController controller, HttpStatusCode httpStatus) 
    : base(content, serializer, encoding, controller)
    {
        _httpStatus = httpStatus;
    }

    public override Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var returnTask = base.ExecuteAsync(cancellationToken);
        returnTask.Result.StatusCode = HttpStatusCode.BadRequest;
        return returnTask;
    }
}

跟随Richard的例子,你可以像这样使用这个类:

if(thereWereErrors)
{
    var errorModel = new CustomErrorModel("There was an error");
    return new JsonHttpStatusResult<CustomErrorModel>(errorModel, new JsonSerializerSettings(), new UTF8Encoding(), this, HttpStatusCode.InternalServerError);
}

很遗憾,您不能在内容中使用匿名类型,因为您需要传递一个具体类型(例如:CustomErrorType)给JsonHttpStatusResult初始化程序。如果您想使用匿名类型,或者您只是想变得更加流畅,您可以通过子类化ApiController来添加HttpStatusCode参数到Json方法中 :)

public abstract class MyApiController : ApiController
{
    protected internal virtual JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus, JsonSerializerSettings serializerSettings, Encoding encoding)
    {
        return new JsonHttpStatusResult<T>(content, httpStatus, serializerSettings, encoding, this);
    }

    protected internal JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus, JsonSerializerSettings serializerSettings)
    {
        return Json(content, httpStatus, serializerSettings, new UTF8Encoding());
    }

    protected internal JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus)
    {
        return Json(content, httpStatus, new JsonSerializerSettings());
    }
}

然后,您可以像这样使用匿名类型来使用它:
if(thereWereErrors)
{
    var errorModel = new { error = "There was an error" };
    return Json(errorModel, HttpStatusCode.InternalServerError);
}

这对我有效。但是HTTP状态码被硬编码为错误请求。必须将其从return Task.Result.StatusCode = HttpStatusCode.BadRequest;更改为return Task.Result.StatusCode = _httpStatus; - Tochi

0
这是针对ASP.NET v5+的JsonResult重写答案。我已经测试过了,它的效果和早期版本一样好。
public class JsonHttpStatusResult : JsonResult
{
    private readonly HttpStatusCode _httpStatus;

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

    public override Task ExecuteResultAsync(ActionContext context)
    {
        context.HttpContext.Response.StatusCode = (int)_httpStatus;
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var services = context.HttpContext.RequestServices;
        var executor = services.GetRequiredService<IActionResultExecutor<JsonResult>>();
        return executor.ExecuteAsync(context, this);
    }
}

1
刚刚了解到在.NET Core和5+中没有必要这样做。而是使用JsonResult:new JsonResult("error") { status = (int)HttpStatusCode.InternalServerError } - Trujllo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接