[asp.net-mvc] ELMAH가 ASP.NET MVC [HandleError] 특성과 작동하게하는 방법?

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

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

ELMAH가 오류가 있음을 알고 기록 할 수 있도록 속성을 수정하거나 어떻게 수정합니까?

편집 : 모두가 이해하도록하십시오. 제가 묻는 질문이 아닌 속성을 수정할 수 있음을 알고 있습니다. handleerror 속성을 사용할 때 ELMAH가 무시됩니다. 즉, 처리 되었기 때문에 오류가 발생하지 않았습니다. 이미 속성에 의해 … 내가 묻는 것은 속성이 처리했지만 ELMAH가 오류를보고 기록하도록하는 방법이 있습니다 … 나는 그것을 검색하기 위해 호출 할 메소드를 보지 못했습니다. 오류….



답변

기본 구현이 처리하는 경우에만 ELMAH를 사용하여 예외를 기록하도록 복사 할 필요없이 멤버를 서브 클래스 화 HandleErrorAttribute하고 대체 할 수 있습니다 OnException. 필요한 최소한의 코드는 다음과 같습니다.

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인스턴스가 적용되는 경우 중복 로깅이 발생하지 않지만 위의 두 가지 예를 시작해야합니다.


답변

죄송하지만 허용되는 답변은 과도하다고 생각합니다. 당신이해야 할 일은 이것입니다 :

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


답변

NuGet에는 Atif의 개선 된 솔루션과 MVC 라우팅 내에서 elmah 인터페이스를 처리하는 컨트롤러 (더 이상 axd를 사용할 필요가 없음)를 포함하는 ELMAH.MVC 패키지가 있습니다.
해당 솔루션의 문제 (여기의 모든 문제 ) )는 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에 대한 설정이 다음과 같은지 확인하십시오.

<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 내부의 핸들러를 사용하여 실제로는 handleErrorHandler를 사용하여 예외를 처리하는 customError 설정을 무시합니다.

이 설정을 사용하면 ElmahMVCErrorFilter를 통해 오류를 계속 기록하면서 elmah 모듈을 통해 web.config에 customError 구성을 추가하고 고유 한 Error Handler를 작성하여 클래스 및 뷰에서 고유 한 ErrorHandler 태그를 설정할 수 있습니다. 당신이해야 할 유일한 것은 우리가 작성한 elmah 필터 전에 실제로 오류를 처리하는 필터를 추가하지 않는 것입니다. 그리고 나는 언급하지 않았습니다 : elmah에는 중복이 없습니다.


답변

모든 컨트롤러에 HandleErrorWithElmah 속성을 주입하는 사용자 정의 컨트롤러 팩토리를 도입하여 위의 코드를 가져와 한 단계 더 나아갈 수 있습니다.

자세한 내용은 MVC 로그인에 대한 내 블로그 시리즈를 확인하십시오. 첫 번째 기사에서는 Elmah를 MVC에 설치하고 실행하는 방법에 대해 설명합니다.

기사 끝에 다운로드 가능한 코드에 대한 링크가 있습니다. 희망이 도움이됩니다.

http://dotnetdarren.wordpress.com/


답변

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> 

간단합니다!


답변

완전히 대안적인 솔루션은 MVC를 사용하지 HandleErrorAttribute않고 Elmah가 설계 한 ASP.Net 오류 처리에 의존하는 것입니다.

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

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

이는 MVC 라우팅 URL 일 수 있으므로 ErrorController.Index오류가 발생 하면 위의 작업으로 리디렉션됩니다 .


답변

저에게는 이메일 로깅을 작동시키는 것이 매우 중요했습니다. 얼마 후 Atif 예제 에서이 코드가 2 줄 더 필요하다는 것을 알았습니다.

public class HandleErrorWithElmahAttribute : HandleErrorAttribute
{
    static ElmahMVCMailModule error_mail_log = new ElmahMVCMailModule();

    public override void OnException(ExceptionContext context)
    {
        error_mail_log.Init(HttpContext.Current.ApplicationInstance);
        [...]
    }
    [...]
}

나는 이것이 누군가를 도울 수 있기를 바랍니다 🙂