ASP.NET MVC Ajaxエラー処理


117

jquery ajaxがアクションを呼び出すときにコントローラーでスローされた例外をどのように処理しますか?

たとえば、デバッグモードまたは通常のエラーメッセージの場合に例外メッセージを表示するajax呼び出し中に、あらゆる種類のサーバー例外で実行されるグローバルJavaScriptコードが必要です。

クライアント側では、ajaxエラー時に関数を呼び出します。

サーバー側では、カスタムアクションフィルターを作成する必要がありますか?


8
良い例については、beckelmansの投稿を参照してください。この投稿に対するDarinsの回答は適切ですが、エラーに対して正しいステータスコードを設定しないでください。
Dan

6
悲しいことに、そのリンクは今壊れています
Chris Nevill

1
ここではウェイバックマシン上のリンクは次のとおりです。web.archive.org/web/20111011105139/http://beckelman.net/post/...
BruceHill

回答:


161

サーバーが200以外のステータスコードを送信すると、エラーコールバックが実行されます。

$.ajax({
    url: '/foo',
    success: function(result) {
        alert('yeap');
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

グローバルエラーハンドラーを登録するには、次の$.ajaxSetup()メソッドを使用できます。

$.ajaxSetup({
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

別の方法は、JSONを使用することです。そのため、例外をキャッチしてJSON応答に変換するカスタムアクションフィルターをサーバーに作成できます。

public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new JsonResult
        {
            Data = new { success = false, error = filterContext.Exception.ToString() },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}

次に、この属性でコントローラーアクションを装飾します。

[MyErrorHandler]
public ActionResult Foo(string id)
{
    if (string.IsNullOrEmpty(id))
    {
        throw new Exception("oh no");
    }
    return Json(new { success = true });
}

そして最後にそれを呼び出します:

$.getJSON('/home/foo', { id: null }, function (result) {
    if (!result.success) {
        alert(result.error);
    } else {
        // handle the success
    }
});

1
このおかげで、後者は私が探していたものでした。asp.net mvc例外の場合、jqueryエラーハンドラーでキャッチできるように、それをスローする必要がある特定の方法はありますか?
Shawn Mclean 2011年

1
@Lolコーダーは、コントローラーアクション内でどのように例外をスローしても、サーバーは500ステータスコードを返し、errorコールバックが実行されます。
Darin Dimitrov

ありがとう、完璧、ちょうど私が探していたもの。
Shawn Mclean 2011年

1
ステータスコード500はちょっと間違っているのではないでしょうか。これを引用すると、broadcast.oreilly.com / 2011/06 /…:「4xxエラーが失敗したことを意味し、5xxが失敗したことを意味する」-私はクライアントであり、あなたはサーバーです。
Chris Nevill、2014年

この回答はASPNETの新しいバージョンでも有効ですか?
gog

73

グーグルした後、MVCアクションフィルターに基づく簡単な例外処理を記述します。

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    filterContext.Exception.Message,
                    filterContext.Exception.StackTrace
                }
            };
            filterContext.ExceptionHandled = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

そしてglobal.ascxに書きます:

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
      filters.Add(new HandleExceptionAttribute());
 }

次に、このスクリプトをレイアウトまたはマスターページに記述します。

<script type="text/javascript">
      $(document).ajaxError(function (e, jqxhr, settings, exception) {
                       e.stopPropagation();
                       if (jqxhr != null)
                           alert(jqxhr.responseText);
                     });
</script>

最後に、カスタムエラーをオンにする必要があります。そしてそれを楽しんでください:)


Firebugでエラーを確認できますが、エラーページにリダイレクトされません。
user2067567 2013

1
これをありがとう!HandleErrorAttributeが継承するものではなく、ajaxリクエストに対するフィルタリングと正しいクラスを継承するため、回答IMOとしてマークする必要があります
mtbennett

2
素晴らしい答え!:D
レニエルマッカフェリ2014

1
「Request.IsAjaxRequest()」は時々それほど信頼できないと思います。
Huangは

デバッグ構成では常に機能しますが、リリース構成では常に機能せず、代わりにhtmlを返します。そのような場合の回避策はありますか?
Hitendra 2016

9

残念ながら、どちらの答えも私には良くありません。驚くべきことに、解決策ははるかに簡単です。コントローラから戻る:

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);

そして、それを好きなようにクライアントの標準HTTPエラーとして処理します。


@Will Huang:例外インスタンスの名前
schmendrick

最初の引数をにキャストする必要がありintます。また、これを行うと、結果はajax successハンドラーではなくハンドラーに渡されerrorます。これは予想される動作ですか?
ジョナサンウッド

4

時間がないので問題なく動いたので、すぐに解決しました。私はより良いオプションは例外フィルターを使用することだと思いますが、おそらく私の解決策は単純な解決策が必要な場合に役立つでしょう。

私は次のことをしました。コントローラーメソッドで、Data内に "Success"プロパティを持つJsonResultを返しました。

    [HttpPut]
    public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave) 
    {
        if (!ModelState.IsValid)
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = "Model is not valid", Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }
        try
        {
            MyDbContext db = new MyDbContext();

            db.Entry(employeToSave).State = EntityState.Modified;
            db.SaveChanges();

            DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];

            if (employeToSave.Id == user.Id)
            {
                user.Company = employeToSave.Company;
                user.Language = employeToSave.Language;
                user.Money = employeToSave.Money;
                user.CostCenter = employeToSave.CostCenter;

                Session["EmployeLoggin"] = user;
            }
        }
        catch (Exception ex) 
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = ex.Message, Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }

        return new JsonResult() { Data = new { Success = true }, };
    }

後のajax呼び出しで、このプロパティに例外があるかどうかを確認するように要求しました。

$.ajax({
    url: 'UpdateEmployeeConfig',
    type: 'PUT',
    data: JSON.stringify(EmployeConfig),
    contentType: "application/json;charset=utf-8",
    success: function (data) {
        if (data.Success) {
            //This is for the example. Please do something prettier for the user, :)
            alert('All was really ok');                                           
        }
        else {
            alert('Oups.. we had errors: ' + data.ErrorMessage);
        }
    },
    error: function (request, status, error) {
       alert('oh, errors here. The call to the server is not working.')
    }
});

お役に立てれば。ハッピーコード!:P


4

alehoの回答に同意して、ここに完全な例を示します。それは魅力のように機能し、超シンプルです。

コントローラーコード

[HttpGet]
public async Task<ActionResult> ChildItems()
{
    var client = TranslationDataHttpClient.GetClient();
    HttpResponseMessage response = await client.GetAsync("childItems);

    if (response.IsSuccessStatusCode)
        {
            string content = response.Content.ReadAsStringAsync().Result;
            List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
            return Json(content, JsonRequestBehavior.AllowGet);
        }
        else
        {
            return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
        }
    }
}

ビューのJavaScriptコード

var url = '@Html.Raw(@Url.Action("ChildItems", "WorkflowItemModal")';

$.ajax({
    type: "GET",
    dataType: "json",
    url: url,
    contentType: "application/json; charset=utf-8",
    success: function (data) {
        // Do something with the returned data
    },
    error: function (xhr, status, error) {
        // Handle the error.
    }
});

これが他の誰かを助けることを願っています!


0

クライアント側でajax呼び出しからのエラーを処理するには、ajax呼び出しのerrorオプションに関数を割り当てます。

デフォルトをグローバルに設定するには、http//api.jquery.com/jQuery.ajaxSetupで説明されている関数を使用できます 。


4年以上前に答えたのですが、突然反対票が投じられましたか?誰もが理由を気にしてくれませんか?
ブライアンボール

1
SOFに連絡し、DBAに反対票を投じた人物を問い合わせるよう依頼します。次に、説明できるようにその個人にメッセージを送ります。誰もが理由を説明できるわけではありません。
JoshYates1980
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.