Вернуть JSON с кодом ошибки MVC

Я пытался вернуть сообщение об ошибке в контроллер, как советовали в Эта ссылка так что клиент может принять соответствующие меры. Контроллер вызывается JavaScript через JQuery AJAX. Я возвращаю объект Json только в том случае, если я не установил статус на ошибку. Вот пример кода

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

Я получу Json, если не установлю код состояния. Если я установлю код состояния, я получу код состояния обратно, но не объект ошибки Json.

Update Я хочу отправить объект Error как JSON, чтобы он мог обрабатывать ответный вызов ошибки ajax.

Ответы на вопрос(8)

И если ваши потребности не так сложны, как у Сарата, вы можете сделать что-то еще проще:

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

Вам нужно решить, хотите ли вы «Ошибка уровня HTTP» (то, для чего предназначены коды ошибок) или «ошибка уровня приложения» (это то, что ваш пользовательский ответ JSON для).

Большинство объектов высокого уровня, использующих HTTP, никогда не будут смотреть в поток ответов, если для кода ошибки установлено значение, отличное от 2xx (диапазон успеха). В вашем случае вы явно устанавливаете код ошибки на ошибку (я думаю, 403 или 500) и заставляете объект XMLHttp игнорировать тело ответа.

Чтобы исправить - либо обработайте условия ошибки на стороне клиента, либо не устанавливайте код ошибки и верните JSON с информацией об ошибке (подробности см. В ответе Sbossb).

 Sarath07 июл. 2012 г., 01:00
@ Алекси Да. Но я хотел бы неявно сообщить клиенту, что произошла ошибка. То есть я хотел бы обработать это условие при сбое обратного вызова вызова ajax вместо успешного обратного вызова, а затем искать ошибки. Длина.
 Sarath07 июл. 2012 г., 00:47
Спасибо за ваш ответ. Как клиент узнает, что произошло исключение, если я не установил код состояния?
 07 июл. 2012 г., 00:51
@Sarath, тот же чекresponse.errors && response.errors.length > 0 как вы делаете сейчас на стороне сервера (при условии, клиент JavaScript).

Существует очень элегантное решение этой проблемы, просто настройте свой сайт через web.config:

<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

 06 янв. 2017 г., 21:29
Обязательно попробуйте это, если это работает на местном, но не лазурном!
 08 дек. 2015 г., 08:40
БУМ! Ответ, который я искал. Это работало нормально для меня локально, но не на удаленном сервере. Я знал, что это можно сделать с некоторыми настройками конфигурации. Ура!
 18 янв. 2018 г., 06:14
Проблема заключалась в том, что я получал StatusCode и Json Response на локальном (dev) компьютере, но во время работы с производства я получал только StatusCode. Это решение, пожалуй, самое простое.

Вы должны вернуть объект ошибки JSON самостоятельно после установки StatusCode, вот так ...

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
}

Посмотрите на ответВот также

 Sarath09 июл. 2012 г., 23:50
Я хочу, чтобы это перезвонило.
 Sarath07 июл. 2012 г., 00:50
У меня уже есть ошибка в объекте ответа. Проблема в том, что я получаю "Плохой запрос" а не объект JSON. Если я не устанавливаю статус, я получаю JSON с ошибками, но клиент не знает, что это исключительное условие.
 Sarath07 июл. 2012 г., 21:48
проблема, с которой я сталкиваюсь, состоит в том, что в ответе я не получаю JSON, если я устанавливаю статус. Ответ, который вы указали, заключается в том, что именно я делаю. Проблема в том, что если я установлю статус ответа, я не получу JSON.
 07 июл. 2012 г., 16:55
@Sarath Проверьте ссылку в ответе. Вам нужно использовать атрибут error метода ajax в JQuery
 08 июл. 2012 г., 01:23
Как ни странно, вы можете просто установить код ошибки в ответе JSON на код ошибки http, а затем проверить его на клиенте. Не устанавливайте код ошибки на стороне сервера. Я обновлю свой ответ, чтобы отразить решение

Самое лучшее решение, которое я нашел, состоит в том, чтобы создать свой собственный 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);
}

Опираясь на ответ Ричарда Гарсайда, приведу версию 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);
 30 янв. 2018 г., 16:39
Спасибо за это.
 28 нояб. 2018 г., 05:48
Я озадачен, почему вы сделали это в ASP.NET Core? Просто вернисьNotFound("message"); и т.д. будет делать ...
 08 июн. 2018 г., 11:06
Нет необходимости добавлять это в ASP.NETCore, эта функциональность существует -stackoverflow.com/questions/42360139/…
Решение Вопроса

Я нашел решениеВот

Мне пришлось создать фильтр действий, чтобы переопределить поведение 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;
        }
    }

Теперь, когда у меня есть фильтр действий, я украслю свой контроллер атрибутом filter

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

Когда выдается ошибка, вызывается фильтр действий, который реализует IExceptionFilter, и я возвращаю Json на клиенте при обратном вызове ошибки.

 06 июн. 2013 г., 17:35
Действительно, это правда, но для возможности повторного использования вы хотели бы сделать это, поскольку ответ указывает, а не копировать / вставлять один и тот же код в каждое действие.
 21 апр. 2016 г., 21:36
Если я установлюStatusCode = 500 затем он игнорирует мой JsonResponse и возвращает «Страница не может быть отображена, поскольку произошла внутренняя ошибка сервера». Не уверен, если это из-за разницы в конвейере OWIN или что.
 10 февр. 2013 г., 17:17
В случае, если читатель думает «Все ли это необходимо?», Ответ «нет». - Я был в той же ситуации, что и @Sarath, и хотел вернуть код ошибки HTTP и некоторые данные JSON, описывающие ошибку. Оказалось, что я могу просто использовать строки, в которых был очищен ответ, пользовательские ошибки IIS пропускаются, а код состояния - «сат». Я поместил эти 3 строки в свой Action на моем контроллере, и после этих 3 строк я просто вернул свои данные JSON как обычно. Работал как шарм.

То, что работало для меня (и что я взял издругой ответ на стек), чтобы установить флаг:

Response.TrySkipIisCustomErrors = true;

Ваш ответ на вопрос