Return JSON with error status code MVC

前端 未结 11 1699
隐瞒了意图╮
隐瞒了意图╮ 2020-11-27 13:23

I was trying to return an error to the call to the controller as advised in This link so that client can take appropriate action. The controller is called by javascript via

相关标签:
11条回答
  • 2020-11-27 13:43

    There is a very elegant solution to this problem, just configure your site via web.config:

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

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

    0 讨论(0)
  • 2020-11-27 13:45

    And if your needs aren't as complex as Sarath's you can get away with something even simpler:

    [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 };
          }
       }
    }
    
    0 讨论(0)
  • 2020-11-27 13:49

    I was running Asp.Net Web Api 5.2.7 and it looks like the JsonResult class has changed to use generics and an asynchronous execute method. I ended up altering Richard Garside's solution:

    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;
        }
    }
    

    Following Richard's example, you could then use this class like this:

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

    Unfortunately, you can't use an anonymous type for the content, as you need to pass a concrete type (ex: CustomErrorType) to the JsonHttpStatusResult initializer. If you want to use anonymous types, or you just want to be really slick, you can build on this solution by subclassing ApiController to add an HttpStatusCode param to the Json methods :)

    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());
        }
    }
    

    Then you can use it with an anonymous type like this:

    if(thereWereErrors)
    {
        var errorModel = new { error = "There was an error" };
        return Json(errorModel, HttpStatusCode.InternalServerError);
    }
    
    0 讨论(0)
  • 2020-11-27 13:52

    The thing that worked for me (and that I took from another stackoverflow response), is to set the flag:

    Response.TrySkipIisCustomErrors = true;
    
    0 讨论(0)
  • 2020-11-27 13:53

    The neatest solution I've found is to create your own JsonResult that extends the original implementation and allows you to specify a 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);
        }
    }
    

    You can then use this in your controller action like so:

    if(thereWereErrors)
    {
        var errorModel = new { error = "There was an error" };
        return new JsonHttpStatusResult(errorModel, HttpStatusCode.InternalServerError);
    }
    
    0 讨论(0)
  • 2020-11-27 13:57

    You need to decide if you want "HTTP level error" (that what error codes are for) or "application level error" (that what your custom JSON response is for).

    Most high level objects using HTTP will never look into response stream if error code set to something that is not 2xx (success range). In your case you are explicitly setting error code to failure (I think 403 or 500) and force XMLHttp object to ignore body of the response.

    To fix - either handle error conditions on client side or not set error code and return JSON with error information (see Sbossb reply for details).

    0 讨论(0)
提交回复
热议问题