การจัดการข้อผิดพลาด ASP.NET MVC Ajax


117

ฉันจะจัดการข้อยกเว้นที่เกิดขึ้นในคอนโทรลเลอร์ได้อย่างไรเมื่อ jquery ajax เรียกการดำเนินการ

ตัวอย่างเช่นฉันต้องการโค้ดจาวาสคริปต์ส่วนกลางที่ดำเนินการกับข้อยกเว้นของเซิร์ฟเวอร์ใด ๆ ในระหว่างการเรียก ajax ซึ่งจะแสดงข้อความยกเว้นหากอยู่ในโหมดดีบักหรือเป็นเพียงข้อความแสดงข้อผิดพลาดปกติ

ในฝั่งไคลเอ็นต์ฉันจะเรียกใช้ฟังก์ชันเกี่ยวกับข้อผิดพลาดของ ajax

ในฝั่งเซิร์ฟเวอร์ฉันต้องเขียนตัวกรองการดำเนินการที่กำหนดเองหรือไม่


8
ดูโพสต์ของ beckelmansสำหรับตัวอย่างที่ดี คำตอบของ Darins สำหรับโพสต์นี้ดี แต่ไม่ได้ตั้งรหัสสถานะที่ถูกต้องสำหรับข้อผิดพลาด
แดน

6
น่าเสียดายที่ตอนนี้ลิงค์เสีย
Chris Nevill

1
นี่คือลิงค์ของเครื่อง wayback: 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
ขอบคุณสำหรับสิ่งนี้สิ่งหลังคือสิ่งที่ฉันกำลังมองหา ดังนั้นสำหรับข้อยกเว้น mvc ของ asp.net มีวิธีเฉพาะที่ฉันต้องโยนเพื่อให้ตัวจัดการข้อผิดพลาด jquery จับได้หรือไม่
Shawn Mclean

1
@Lol coder ไม่ว่าคุณจะทิ้งข้อยกเว้นในการดำเนินการของคอนโทรลเลอร์อย่างไรเซิร์ฟเวอร์จะส่งคืนรหัสสถานะ 500 และการerrorเรียกกลับจะถูกดำเนินการ
Darin Dimitrov

ขอบคุณสมบูรณ์แบบสิ่งที่ฉันกำลังมองหา
Shawn Mclean

1
รหัสสถานะ 500 จะไม่ผิดใช่ไหม ในการอ้างบทนี้broadcast.oreilly.com/2011/06/… : "การไม่ตระหนักว่าข้อผิดพลาด 4xx หมายความว่าฉันทำผิดพลาดและ 5xx หมายความว่าคุณทำผิดพลาด" - ที่ที่ฉันเป็นไคลเอนต์และคุณคือเซิร์ฟเวอร์
Chris Nevill

คำตอบนี้ยังใช้ได้กับ ASPNET เวอร์ชันใหม่กว่า?
gog

73

หลังจาก googling ฉันเขียนการจัดการข้อยกเว้นอย่างง่ายตาม 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);
        }
    }
}

และเขียนใน 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

1
ขอบคุณสำหรับสิ่งนี้! ควรทำเครื่องหมายเป็นคำตอบ IMO เป็นการกรองคำขอ ajax และสืบทอดคลาสที่ถูกต้องแทนที่จะเป็นสิ่งที่ HandleErrorAttribute สืบทอดมา
mtbennett

2
คำตอบที่ยอดเยี่ยม! : D
Leniel Maccaferri

1
ฉันคิดว่า "Request.IsAjaxRequest ()" ไม่น่าเชื่อถือในบางครั้ง
Will Huang

สำหรับการกำหนดค่าการดีบักจะใช้งานได้เสมอ แต่ไม่ทำงานเสมอในการกำหนดค่าการเปิดตัวและส่งคืน html แทนใครมีวิธีแก้ปัญหาสำหรับกรณีดังกล่าวหรือไม่
Hitendra

9

น่าเสียดายที่ไม่มีคำตอบใดที่ดีสำหรับฉัน น่าแปลกใจที่วิธีแก้ปัญหานั้นง่ายกว่ามาก กลับจากคอนโทรลเลอร์:

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

และจัดการเป็นข้อผิดพลาด HTTP มาตรฐานบนไคลเอนต์ตามที่คุณต้องการ


@ Will Huang: ชื่อของตัวอย่างเช่น
schmendrick

intฉันต้องโยนอาร์กิวเมนต์แรก นอกจากนี้เมื่อฉันทำสิ่งนี้ผลลัพธ์จะถูกส่งต่อไปยังajax successตัวจัดการไม่ใช่errorตัวจัดการ นี่คือพฤติกรรมที่คาดหวังหรือไม่?
Jonathan Wood

4

ฉันแก้ปัญหาอย่างรวดเร็วเพราะฉันไม่มีเวลาและมันก็ใช้ได้ แม้ว่าฉันคิดว่าตัวเลือกที่ดีกว่าคือใช้ตัวกรองข้อยกเว้นบางทีโซลูชันของฉันอาจช่วยได้ในกรณีที่ต้องการโซลูชันง่ายๆ

ฉันทำสิ่งต่อไปนี้ ในวิธีการควบคุมฉันส่งคืน JsonResult พร้อมคุณสมบัติ "Success" ภายใน 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 }, };
    }

ต่อมาในการโทร 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 ในฝั่งไคลเอ็นต์คุณกำหนดฟังก์ชันให้กับerrorตัวเลือกของการโทร ajax

ในการตั้งค่าเริ่มต้นทั่วโลกคุณสามารถใช้ฟังก์ชั่นที่อธิบายที่นี่: http://api.jquery.com/jQuery.ajaxSetup


คำตอบที่ฉันให้ไว้เมื่อ 4 ปีที่แล้วจู่ๆก็มีการโหวตลดลง? ทุกคนสนใจที่จะให้เหตุผลว่าทำไม?
Brian Ball

1
ติดต่อ SOF และขอให้ DBA สอบถามว่าใครเป็นผู้โหวตลงคะแนน จากนั้นส่งข้อความถึงบุคคลนั้นเพื่อให้พวกเขาสามารถอธิบายได้ ไม่ใช่แค่ใครก็ได้ที่สามารถให้เหตุผลว่าทำไม
JoshYates1980
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.