ข้อผิดพลาดในการบันทึกใน ASP.NET MVC


109

ฉันกำลังใช้ log4net ในแอปพลิเคชัน ASP.NET MVC เพื่อบันทึกข้อยกเว้น วิธีที่ฉันทำคือให้คอนโทรลเลอร์ทั้งหมดของฉันสืบทอดมาจากคลาส BaseController ในเหตุการณ์ OnActionExecuting ของ BaseController ฉันบันทึกข้อยกเว้นใด ๆ ที่อาจเกิดขึ้น:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    // Log any exceptions
    ILog log = LogManager.GetLogger(filterContext.Controller.GetType());

    if (filterContext.Exception != null)
    {
        log.Error("Unhandled exception: " + filterContext.Exception.Message +
            ". Stack trace: " + filterContext.Exception.StackTrace, 
            filterContext.Exception);
    }
}

วิธีนี้ใช้งานได้ดีหากเกิดข้อยกเว้นที่ไม่สามารถจัดการได้ระหว่างการดำเนินการของคอนโทรลเลอร์

สำหรับข้อผิดพลาด 404 ฉันมีข้อผิดพลาดที่กำหนดเองใน web.config ของฉันดังนี้:

<customErrors mode="On">
    <error statusCode="404" redirect="~/page-not-found"/>
</customErrors>

และในการดำเนินการของคอนโทรลเลอร์ที่จัดการกับ URL "ไม่พบหน้าเว็บ" ฉันบันทึก URL เดิมที่ถูกร้องขอ:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PageNotFound()
{
    log.Warn("404 page not found - " + Utils.SafeString(Request.QueryString["aspxerrorpath"]));

    return View();
}

และยังใช้งานได้

ปัญหาที่ฉันพบคือวิธีบันทึกข้อผิดพลาดที่อยู่บนหน้า. aspx ด้วยตัวเอง สมมติว่าฉันมีข้อผิดพลาดในการคอมไพล์ในหน้าใดหน้าหนึ่งหรือโค้ดอินไลน์บางส่วนที่จะทำให้เกิดข้อยกเว้น:

<% ThisIsNotAValidFunction(); %>
<% throw new Exception("help!"); %>

ดูเหมือนว่าแอ็ตทริบิวต์ HandleError จะเปลี่ยนเส้นทางไปยังเพจ Error.aspx ของฉันในโฟลเดอร์ที่ใช้ร่วมกันอย่างถูกต้อง แต่เมธอด OnActionExecuted ของ BaseController ของฉันไม่ถูกจับ ฉันคิดว่าฉันอาจจะใส่รหัสบันทึกในหน้า Error.aspx ได้ แต่ฉันไม่แน่ใจว่าจะดึงข้อมูลข้อผิดพลาดในระดับนั้นได้อย่างไร


+1 สำหรับ ELMAH นี่คือบทช่วยสอน ELMAH ที่ฉันเขียนเพื่อช่วยคุณในการเริ่มต้น อย่าลืมใช้แพ็คเกจElmah.MVCเมื่อใช้ ASP.NET MVC เพื่อหลีกเลี่ยงปัญหาเกี่ยวกับหน้าข้อผิดพลาดที่กำหนดเองเป็นต้น
ThomasArdal

มีผลิตภัณฑ์บางอย่างที่จะบันทึกข้อผิดพลาดทั้งหมดที่เกิดขึ้นในแอป. NET พวกเขาไม่ได้อยู่ในระดับต่ำเหมือน ELMAH หรือ log4net แต่ช่วยให้คุณประหยัดเวลาได้มากหากคุณเพียงแค่พยายามตรวจสอบและวินิจฉัยข้อผิดพลาด: Bugsnagและ AirBrakeเป็นสองสิ่งที่ฉันรู้จัก NET
Don P

คำตอบ:


103

ฉันจะพิจารณาลดความซับซ้อนของโปรแกรมประยุกต์บนเว็บของคุณโดยการเสียบELMAH

คุณเพิ่มแอสเซมบลี Elmah ในโปรเจ็กต์ของคุณแล้วกำหนดค่า web.config ของคุณ จากนั้นจะบันทึกข้อยกเว้นที่สร้างขึ้นที่ระดับคอนโทรลเลอร์หรือระดับเพจ สามารถกำหนดค่าให้เข้าสู่ระบบไปยังที่ต่างๆ (เช่น SQL Server, Email เป็นต้น) นอกจากนี้ยังมีส่วนหน้าเว็บเพื่อให้คุณสามารถเรียกดูบันทึกข้อยกเว้นได้

สิ่งแรกที่ฉันเพิ่มลงในแอป mvc ของ asp.net ที่ฉันสร้างขึ้น

ฉันยังคงใช้ log4net แต่ฉันมักจะใช้เพื่อบันทึกการแก้จุดบกพร่อง / ข้อมูลและปล่อยให้ Elmah มีข้อยกเว้นทั้งหมด

คุณยังสามารถค้นหาข้อมูลเพิ่มเติมได้ในคำถามHow do you log error (exceptions) in your ASP.NET apps? .


3
ฉันเริ่มใช้ Elmah เมื่อเร็ว ๆ นี้และเป็นหนึ่งในเครื่องตัดไม้ที่เรียบง่ายและเรียบง่ายที่สุดที่ฉันเคยใช้ ฉันอ่านโพสต์ที่บอกว่า MS ควรรวมไว้ใน ASP.net และฉันเห็นด้วย
dtc

14
ทำไมฉันต้องมีทั้ง ELMAH และ log4net สำหรับแอป การบันทึก? ทำไมไม่แก้ปัญหาเดียว?
VJAI

จะใช้งานได้หรือไม่แม้ว่าฉันจะมีสถาปัตยกรรมระดับ n ตัวควบคุม - บริการ - ที่เก็บ?
a.farkas2508

2
ELMAH ได้รับคะแนนสูงเกินไป
Ronnie Overby

ELMAH ฟรีหรือไม่?
Dallas

38

คุณสามารถเชื่อมต่อกับเหตุการณ์ OnError ใน Global.asax

สิ่งนี้:

/// <summary>
/// Handles the Error event of the Application control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Application_Error(object sender, EventArgs e)
{
    if (Server != null)
    {
        Exception ex = Server.GetLastError();

        if (Response.StatusCode != 404 )
        {
            Logging.Error("Caught in Global.asax", ex);
        }

    }


}

3
สิ่งนี้ควรเป็นไปตามข้อยกเว้นทั้งหมด ฉันถือว่านี่เป็นแนวทางปฏิบัติที่ดีที่สุด
Andrei Rînea

4
ตามการวิเคราะห์ค่าของ ReSharper Serverจะไม่เป็นค่าว่างเสมอ
Drew Noakes

6
การเพิกเฉย 404 ไม่ได้ผลกับฉันแบบที่คุณเขียน ฉันเขียนif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
pauloya

21

MVC3
สร้างแอตทริบิวต์ที่สืบทอดจาก HandleErrorInfoAttribute และรวมถึงตัวเลือกการบันทึกของคุณ

public class ErrorLoggerAttribute : HandleErrorAttribute 
{
    public override void OnException(ExceptionContext filterContext)
    {
        LogError(filterContext);
        base.OnException(filterContext);
    }

    public void LogError(ExceptionContext filterContext)
    {
       // You could use any logging approach here

        StringBuilder builder = new StringBuilder();
        builder
            .AppendLine("----------")
            .AppendLine(DateTime.Now.ToString())
            .AppendFormat("Source:\t{0}", filterContext.Exception.Source)
            .AppendLine()
            .AppendFormat("Target:\t{0}", filterContext.Exception.TargetSite)
            .AppendLine()
            .AppendFormat("Type:\t{0}", filterContext.Exception.GetType().Name)
            .AppendLine()
            .AppendFormat("Message:\t{0}", filterContext.Exception.Message)
            .AppendLine()
            .AppendFormat("Stack:\t{0}", filterContext.Exception.StackTrace)
            .AppendLine();

        string filePath = filterContext.HttpContext.Server.MapPath("~/App_Data/Error.log");

        using(StreamWriter writer = File.AppendText(filePath))
        {
            writer.Write(builder.ToString());
            writer.Flush();
        }
    }

วางแอตทริบิวต์ใน Global.asax RegisterGlobalFilters

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
       // filters.Add(new HandleErrorAttribute());
        filters.Add(new ErrorLoggerAttribute());
    }

1

คุณเคยคิดที่จะขยายแอตทริบิวต์ HandleError หรือไม่? นอกจากนี้สกอตต์มีโพสต์บล็อกที่ดีเกี่ยวกับดักกรองบนตัวควบคุม / การกระทำที่นี่


1

มุมมอง Error.aspx ถูกกำหนดดังนี้:

namespace MvcApplication1.Views.Shared
{
    public partial class Error : ViewPage<HandleErrorInfo>
    {
    }
}

HandleErrorInfo มีคุณสมบัติสามอย่าง: สตริง ActionName string ControllerName Exception Exception

คุณควรจะสามารถเข้าถึง HandleErrorInfo และดังนั้น Exception ภายในมุมมอง


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