ELMAH를 ASP.NET MVC[HandleError] 특성과 함께 사용하려면 어떻게해야합니까?




asp.net-mvc logging (6)

ELMAH를 사용하여 ASP.NET MVC 응용 프로그램에서 오류를 기록하려고합니다. 그러나 컨트롤러에서 [HandleError] 특성을 사용할 때 오류가 발생하면 오류를 기록하지 않습니다.

ELMAH는 처리되지 않은 오류 만 기록하고 [HandleError] 속성은 오류를 처리하므로 로그 할 필요가 없기 때문에 추측하고 있습니다.

ELMAH가 오류가 있음을 알 수 있도록 속성을 수정하고 변경하는 방법은 무엇입니까?

편집 : 모든 사람이 이해할 수있게하겠습니다, 내가 묻는 질문이 아닌 속성을 수정할 수 있다는 것을 알고 있습니다 ... ELMAH는 handleerror 속성을 사용할 때 무시됩니다. 처리되지 않았기 때문에 오류가 있음을 알 수 없습니다. 이미 속성에 의해 ... 내가 ELMAH가 오류를보고 그것을 처리하더라도 속성을 처리하도록 만드는 방법은 무엇인지 묻고있다. 나는 검색을하고 검색을 강제로하기 위해 어떤 메소드도 보지 않는다. 오류....


NuGet에 ELFMH.MVC 패키지가 추가되었습니다.이 패키지에는 Atif의 개선 된 솔루션과 MVC 라우팅에서 elmah 인터페이스를 처리하는 컨트롤러가 포함되어 있습니다 (더 이상 axd를 사용할 필요가 없습니다)
이 솔루션의 문제 (및 여기에있는 모든 문제)는 elmah 오류 처리기가 실제로 오류를 처리하는 방식으로 customError 태그 또는 ErrorHandler 또는 자체 오류 처리기로 설정하려는 것을 무시한다는 것입니다
가장 좋은 해결책 IMHO는 다른 모든 필터의 끝에서 작동하고 이미 처리 된 이벤트를 기록하는 필터를 만드는 것입니다. elmah 모듈은 응용 프로그램에서 처리되지 않은 다른 오류를 로깅해야합니다. 또한 상태 모니터를 사용하여 오류 이벤트를보기 위해 asp.net에 추가 할 수있는 다른 모든 모듈을 사용할 수 있습니다

나는 elmah.mvc 안의 ErrorHandler에 반사체를 가지고이 글을 썼다.

public class ElmahMVCErrorFilter : IExceptionFilter
{
   private static ErrorFilterConfiguration _config;

   public void OnException(ExceptionContext context)
   {
       if (context.ExceptionHandled) //The unhandled ones will be picked by the elmah module
       {
           var e = context.Exception;
           var context2 = context.HttpContext.ApplicationInstance.Context;
           //TODO: Add additional variables to context.HttpContext.Request.ServerVariables for both handled and unhandled exceptions
           if ((context2 == null) || (!_RaiseErrorSignal(e, context2) && !_IsFiltered(e, context2)))
           {
            _LogException(e, context2);
           }
       }
   }

   private static bool _IsFiltered(System.Exception e, System.Web.HttpContext context)
   {
       if (_config == null)
       {
           _config = (context.GetSection("elmah/errorFilter") as ErrorFilterConfiguration) ?? new ErrorFilterConfiguration();
       }
       var context2 = new ErrorFilterModule.AssertionHelperContext((System.Exception)e, context);
       return _config.Assertion.Test(context2);
   }

   private static void _LogException(System.Exception e, System.Web.HttpContext context)
   {
       ErrorLog.GetDefault((System.Web.HttpContext)context).Log(new Elmah.Error((System.Exception)e, (System.Web.HttpContext)context));
   }


   private static bool _RaiseErrorSignal(System.Exception e, System.Web.HttpContext context)
   {
       var signal = ErrorSignal.FromContext((System.Web.HttpContext)context);
       if (signal == null)
       {
           return false;
       }
       signal.Raise((System.Exception)e, (System.Web.HttpContext)context);
       return true;
   }
}

자, 필터 설정에서 다음과 같이하고 싶습니다.

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //These filters should go at the end of the pipeline, add all error handlers before
        filters.Add(new ElmahMVCErrorFilter());
    }

예외를 처리 할 전역 필터를 추가하려면이 마지막 필터 전에 처리해야하는 전역 필터를 추가하려면 처리기 예외가 ElmahMVCErrorFilter에 의해 무시되는 경우를 실행해야한다는 점을 사람들에게 상기시키기 위해 주석을 남겼습니다. 처리되지 않았으므로 Elmah 모듈에 의해 로그되어야하지만 다음 필터는 예외를 처리 된 것으로 표시하고 모듈은이를 무시하므로 예외는 elmah에 들어 가지 않습니다.

이제 webconfig의 elmah에 대한 appsettings가 다음과 같이 보이는지 확인하십시오.

<add key="elmah.mvc.disableHandler" value="false" /> <!-- This handles elmah controller pages, if disabled elmah pages will not work -->
<add key="elmah.mvc.disableHandleErrorFilter" value="true" /> <!-- This uses the default filter for elmah, set to disabled to use our own -->
<add key="elmah.mvc.requiresAuthentication" value="false" /> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.allowedRoles" value="*" /> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.route" value="errortracking" /> <!-- Base route for elmah pages -->

여기서 중요한 것은 "elmah.mvc.disableHandleErrorFilter"입니다. 이것이 틀리면 elmah.mvc 내부의 핸들러를 사용합니다.이 핸들러는 customError 설정을 무시할 기본 HandleErrorHandler를 사용하여 실제로 예외를 처리합니다

이 설정을 사용하면 클래스 및 뷰에서 자체 ErrorHandler 태그를 설정하면서 ElmahMVCErrorFilter를 통해 해당 오류를 로깅하고 elmah 모듈을 통해 web.config에 customError 구성을 추가 할 수 있으며 자체 오류 처리기를 작성할 수도 있습니다. 우리가 작성한 elmah 필터를 사용하기 전에 실제로 오류를 처리 할 필터를 추가하지 않는 것이 좋습니다. 그리고 저는 언급하기를 잊어 버렸습니다 : 엘마 (Elmah)에는 중복이 없습니다.


완전히 다른 대안은 MVC HandleErrorAttribute 사용하지 않고 대신 Elmah가 작동하도록 설계된 ASP.Net 오류 처리에 의존하는 것입니다.

App_Start \ FilterConfig (또는 Global.asax)에서 기본 전역 HandleErrorAttribute 를 제거한 다음 Web.config에 오류 페이지를 설정해야합니다.

<customErrors mode="RemoteOnly" defaultRedirect="~/error/" />

참고 :이 URL은 MVC 라우트 된 URL 일 수 있으므로 오류가 발생하면 위의 코드는 ErrorController.Index 액션으로 리디렉션됩니다.


이것이 바로 MVC 사이트 구성에 필요한 것입니다!

Atif Aziz가 제안한대로 여러 HandleErrorAttribute 인스턴스를 처리하기 위해 OnException 메서드에 약간의 수정을 추가했습니다.

여러 개의 HandleErrorAttribute 인스턴스가 유효한 경우 중복 로깅이 발생하지 않도록주의해야 할 수도 있습니다.

나는 단순히 context.ExceptionHandled 를 확인합니다. 기본 클래스를 호출하기 전에 예외 처리했습니다. 다른 누군가가 현재 처리기 전에 예외를 처리했는지 알기 위해서입니다.
그것은 나를 위해 작동하고 누군가 다른 사람이 필요로 할 경우를 대비해 코드를 게시하고 누군가가 간과했는지 아는 사람이 있는지 물어 봅니다.

희망은 유용합니다 :

public override void OnException(ExceptionContext context)
{
    bool exceptionHandledByPreviousHandler = context.ExceptionHandled;

    base.OnException(context);

    Exception e = context.Exception;
    if (exceptionHandledByPreviousHandler
        || !context.ExceptionHandled  // if unhandled, will be logged anyhow
        || RaiseErrorSignal(e)        // prefer signaling, if possible
        || IsFiltered(context))       // filtered?
        return;

    LogException(e);
}

저는 ASP.NET MVC에 익숙합니다. 나는 같은 문제에 직면했다, 다음은 내 Erorr.vbhtml에서 작동 가능하다 (Elmah 로그를 사용하여 오류를 기록하기 만하면된다)

@ModelType System.Web.Mvc.HandleErrorInfo

    @Code
        ViewData("Title") = "Error"
        Dim item As HandleErrorInfo = CType(Model, HandleErrorInfo)
        //To log error with Elmah
        Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(New Elmah.Error(Model.Exception, HttpContext.Current))
    End Code

<h2>
    Sorry, an error occurred while processing your request.<br />

    @item.ActionName<br />
    @item.ControllerName<br />
    @item.Exception.Message
</h2> 

그것은 간단합니다!


죄송하지만, 받아 들인 대답은 과잉이라고 생각합니다. 당신이해야 할 일은 다음과 같습니다 :

public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
    public void OnException (ExceptionContext context)
    {
        // Log only handled exceptions, because all other will be caught by ELMAH anyway.
        if (context.ExceptionHandled)
            ErrorSignal.FromCurrentContext().Raise(context.Exception);
    }
}

Global.asax.cs에 등록하십시오 (순서는 중요합니다) :

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

HandleErrorAttribute 하위 클래스를 만들고 OnException 멤버를 재정의하면 (복사 할 필요가 없음) 기본 구현에서 ELMAH를 처리하는 경우에만 예외를 기록 할 수 있습니다. 필요한 최소한의 코드 양은 다음과 같습니다.

using System.Web.Mvc;
using Elmah;

public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        base.OnException(context);
        if (!context.ExceptionHandled) 
            return;
        var httpContext = context.HttpContext.ApplicationInstance.Context;
        var signal = ErrorSignal.FromContext(httpContext);
        signal.Raise(context.Exception, httpContext);
    }
}

기본 구현이 먼저 호출되어 예외를 처리 대상으로 표시 할 수 있습니다. 그래야만 예외가 신호됩니다. 위의 코드는 간단하며 테스트와 같이 HttpContext 사용할 수없는 환경에서 사용하면 문제가 발생할 수 있습니다. 결과적으로, 약간 더 오래 걸리는 대신 더 방어적인 코드가 필요할 것입니다.

using System.Web;
using System.Web.Mvc;
using Elmah;

public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        base.OnException(context);
        if (!context.ExceptionHandled       // if unhandled, will be logged anyhow
            || TryRaiseErrorSignal(context) // prefer signaling, if possible
            || IsFiltered(context))         // filtered?
            return;

        LogException(context);
    }

    private static bool TryRaiseErrorSignal(ExceptionContext context)
    {
        var httpContext = GetHttpContextImpl(context.HttpContext);
        if (httpContext == null)
            return false;
        var signal = ErrorSignal.FromContext(httpContext);
        if (signal == null)
            return false;
        signal.Raise(context.Exception, httpContext);
        return true;
    }

    private static bool IsFiltered(ExceptionContext context)
    {
        var config = context.HttpContext.GetSection("elmah/errorFilter")
                        as ErrorFilterConfiguration;

        if (config == null)
            return false;

        var testContext = new ErrorFilterModule.AssertionHelperContext(
                              context.Exception, 
                              GetHttpContextImpl(context.HttpContext));
        return config.Assertion.Test(testContext);
    }

    private static void LogException(ExceptionContext context)
    {
        var httpContext = GetHttpContextImpl(context.HttpContext);
        var error = new Error(context.Exception, httpContext);
        ErrorLog.GetDefault(httpContext).Log(error);
    }

    private static HttpContext GetHttpContextImpl(HttpContextBase context)
    {
        return context.ApplicationInstance.Context;
    }
}

이 두 번째 버전은 로깅, 메일 링, 필터링과 같이 완전히 구성된 파이프 라인을 포함하는 ELMAH의 오류 신호 를 먼저 사용하려고 시도합니다. 실패하면 오류를 필터링해야하는지 여부를 확인합니다. 그렇지 않은 경우 오류는 단순히 기록됩니다. 이 구현은 메일 알림을 처리하지 않습니다. 예외가 신호화될 수 있으면 그렇게하도록 구성된 경우 메일이 전송됩니다.

또한 여러 HandleErrorAttribute 인스턴스가 유효하고 중복 로깅이 발생하지 않지만 위의 두 예제가 시작되도록주의해야 할 수도 있습니다.





elmah