Penanganan kesalahan ASP.NET MVC Ajax

117

Bagaimana cara menangani pengecualian yang dilemparkan ke pengontrol ketika jquery ajax memanggil tindakan?

Misalnya, saya ingin kode javascript global yang dijalankan pada semua jenis pengecualian server selama panggilan ajax yang menampilkan pesan pengecualian jika dalam mode debug atau hanya pesan kesalahan normal.

Di sisi klien, saya akan memanggil fungsi pada kesalahan ajax.

Di sisi server, Apakah saya perlu menulis filter tindakan kustom?

Shawn Mclean
sumber
8
Lihat posting beckelmans untuk contoh yang baik. Jawaban Darins untuk posting ini bagus tetapi jangan mengatur kode status yang benar untuk kesalahan.
Dan
6
Sayangnya tautan itu sekarang rusak
Chris Nevill
1
Ini adalah tautan di mesin wayback
BruceHill

Jawaban:

161

Jika server mengirimkan beberapa kode status berbeda dari 200, callback kesalahan dijalankan:

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

dan untuk mendaftarkan penangan kesalahan global Anda dapat menggunakan $.ajaxSetup()metode:

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

Cara lain adalah dengan menggunakan JSON. Jadi Anda bisa menulis filter tindakan kustom di server yang menangkap pengecualian dan mengubahnya menjadi respons 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
        };
    }
}

lalu hiasi tindakan pengontrol Anda dengan atribut ini:

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

dan akhirnya memanggilnya:

$.getJSON('/home/foo', { id: null }, function (result) {
    if (!result.success) {
        alert(result.error);
    } else {
        // handle the success
    }
});
Darin Dimitrov
sumber
1
Terima kasih untuk ini, Yang terakhir adalah yang saya cari. Jadi untuk pengecualian MVC asp.net, apakah ada cara khusus yang saya perlukan untuk membuangnya agar dapat ditangkap oleh jquery error handler?
Shawn Mclean
1
@Lol coder, tidak peduli bagaimana Anda melempar pengecualian di dalam aksi pengontrol, server akan mengembalikan kode status 500 dan errorcallback akan dijalankan.
Darin Dimitrov
Terima kasih, sempurna, apa yang saya cari.
Shawn Mclean
1
Bukankah kode Status 500 salah? Mengutip chap ini broadcast.oreilly.com/2011/06/… : "Gagal menyadari bahwa kesalahan 4xx berarti saya mengacaukan dan 5xx berarti Anda mengacaukannya" - di mana saya adalah klien dan Anda adalah servernya.
Chris Nevill
Jawaban ini masih berlaku untuk ASPNET versi terbaru?
gog
73

Setelah googling saya menulis penanganan Exception sederhana berdasarkan MVC Action Filter:

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

dan tulis di global.ascx:

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

lalu tulis skrip ini di layout atau halaman Master:

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

Akhirnya Anda harus mengaktifkan kesalahan khusus. dan kemudian nikmati :)

Arash
sumber
Saya dapat melihat kesalahan di Firebug tetapi tidak mengalihkan ke halaman Kesalahan.?
pengguna2067567
1
Terima kasih untuk ini! harus ditandai sebagai jawaban IMO sebagai pemfilterannya pada permintaan ajax dan mewarisi kelas yang benar daripada apa yang diwarisi HandleErrorAttribute
mtbennett
2
Jawaban yang luar biasa! : D
Leniel Maccaferri
1
Saya pikir "Request.IsAjaxRequest ()" terkadang tidak dapat diandalkan.
Will Huang
Untuk konfigurasi debug itu selalu berfungsi tetapi tidak selalu berfungsi dalam konfigurasi rilis & mengembalikan html, sebaliknya ada yang punya solusi untuk kasus seperti itu?
Hitendra
9

Sayangnya, tidak ada jawaban yang baik untuk saya. Ternyata solusinya jauh lebih sederhana. Kembali dari pengontrol:

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

Dan menanganinya sebagai kesalahan HTTP standar pada klien sesuka Anda.

alehro
sumber
@ Will Huang: nama contoh pengecualian
schmendrick
Saya harus memberikan argumen pertama ke int. Juga, ketika saya melakukan ini, hasilnya akan diteruskan ke ajax successpawang, dan bukan errorpawang. Apakah ini perilaku yang diharapkan?
Jonathan Wood
4

Saya melakukan solusi cepat karena saya kekurangan waktu dan berhasil dengan baik. Meskipun menurut saya opsi yang lebih baik adalah menggunakan Filter Pengecualian, mungkin solusi saya dapat membantu jika solusi sederhana diperlukan.

Saya melakukan hal berikut. Dalam metode pengontrol saya mengembalikan JsonResult dengan properti "Sukses" di dalam Data:

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

Kemudian dalam panggilan ajax saya hanya meminta properti ini untuk mengetahui apakah saya memiliki pengecualian:

$.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.')
    }
});

Semoga ini membantu. Selamat kode! : P

Daniel Silva
sumber
4

Sesuai dengan tanggapan aleho, berikut adalah contoh lengkapnya. Ini bekerja seperti pesona dan sangat sederhana.

Kode pengontrol

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

Kode Javascript dalam tampilan

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

Semoga ini bisa membantu orang lain!

Rymnel
sumber
0

Untuk menangani kesalahan dari panggilan ajax di sisi klien, Anda menetapkan fungsi ke erroropsi panggilan ajax.

Untuk menyetel default secara global, Anda dapat menggunakan fungsi yang dijelaskan di sini: http://api.jquery.com/jQuery.ajaxSetup .

Brian Ball
sumber
Jawaban yang saya berikan lebih dari 4 tahun yang lalu tiba-tiba mendapat suara negatif? Ada yang mau memberi alasan mengapa?
Brian Ball
1
Hubungi SOF dan minta DBA mereka untuk menanyakan siapa yang memberikan suara tidak setuju. Selanjutnya, kirim pesan kepada individu tersebut agar mereka dapat menjelaskan. Tidak sembarang orang bisa memberi alasan kenapa.
JoshYates1980