web-dev-qa-db-ja.com

エラーステータスコードMVCでJSONを返す

このリンク でアドバイスされているように、コントローラーへの呼び出しにエラーを返そうとしていたので、クライアントは適切なアクションを取ることができます。コントローラは、jquery AJAXを介してjavascriptによって呼び出されます。ステータスをエラーに設定しない場合にのみ、Jsonオブジェクトを取得しています。サンプルコードはこちら

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

ステータスコードを設定しない場合、Jsonを取得します。ステータスコードを設定すると、Jsonエラーオブジェクトではなく、ステータスコードが返されます。

Updateajaxのエラーコールバックを処理できるように、ErrorオブジェクトをJSONとして送信したい。

39
Sarath

私は解決策を見つけました ここ

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が返されます。

32
Sarath

私が見つけた最も近いソリューションは、元の実装を拡張し、HttpStatusCodeを指定できる独自のJsonResultを作成することです。

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);
}
25
Richard Garside

この問題に対する非常に洗練された解決策があります。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

22
Gabrielius

リチャード・ガーサイドからの回答に基づいて、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);
6
Lee Oades

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
}

答えを見てください こちら も同様に

5
Stefan Bossbaly

「HTTPレベルエラー」(エラーコードの目的)または「アプリケーションレベルエラー」(カスタムJSON応答の目的)のどちらを使用するかを決定する必要があります。

HTTPを使用するほとんどの高レベルオブジェクトは、エラーコードが2xx(成功範囲)以外の値に設定されている場合、応答ストリームを参照しません。あなたの場合、エラーコードを明示的に失敗に設定し(403または500と思います)、XMLHttpオブジェクトに応答の本文を無視させます。

修正するには-クライアント側でエラー状態を処理するか、エラーコードを設定せずにエラー情報付きのJSONを返します(詳細については、Sbossbの返信を参照してください)。

4
Alexei Levenkov

また、ニーズがサラスほど複雑でない場合は、さらに単純なもので逃げることができます。

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

私のために働いた(そして、私は 別のstackoverflow response から取った)、フラグを設定することです:

Response.TrySkipIisCustomErrors = true;
3
Philippe

Jsonにエラーを送信する簡単な方法は、応答オブジェクトのHTTPステータスコードを制御し、カスタムエラーメッセージを設定することです。

コントローラー

public JsonResult Create(MyObject myObject) 
{
  //AllFine
  return Json(new { IsCreated = True, Content = ViewGenerator(myObject));

  //Use input may be wrong but nothing crashed
  return Json(new { IsCreated = False, Content = ViewGenerator(myObject));  

  //Error
  Response.StatusCode = (int)HttpStatusCode.InternalServerError;
  return Json(new { IsCreated = false, ErrorMessage = 'My error message');
}

[〜#〜] js [〜#〜]

$.ajax({
     type: "POST",
     dataType: "json",
     url: "MyController/Create",
     data: JSON.stringify(myObject),
     success: function (result) {
       if(result.IsCreated)
     {
    //... ALL FINE
     }
     else
     {
    //... Use input may be wrong but nothing crashed
     }
   },
    error: function (error) {
            alert("Error:" + erro.responseJSON.ErrorMessage ); //Error
        }
  });
1