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에 설치하고 실행하는 방법에 대해 설명합니다.
기사 끝에 다운로드 가능한 코드에 대한 링크가 있습니다. 희망이 도움이됩니다.
답변
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 오류 처리에 의존하는 것입니다.
HandleErrorAttribute
App_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);
[...]
}
[...]
}
나는 이것이 누군가를 도울 수 있기를 바랍니다 🙂