ELMAH가 ASP.NET MVC [HandleError] 특성과 함께 작동하도록하는 방법은 무엇입니까?
내 ASP.NET MVC 응용 프로그램에서 오류를 기록하기 위해 ELMAH를 사용하려고하지만 컨트롤러에서 [HandleError] 특성을 사용할 때 ELMAH는 오류가 발생할 때 어떤 오류도 기록하지 않습니다.
ELMAH는 처리되지 않은 오류 만 기록하고 [HandleError] 속성이 오류를 처리하므로 기록 할 필요가 없기 때문에 추측하고 있습니다.
ELMAH가 오류가 있음을 인식하고 기록 할 수 있도록 어떻게 수정하거나 속성을 수정하는 방법에 대해 설명합니다.
편집 : 모두가 이해하는지 확인하겠습니다. 제가 묻는 질문이 아닌 속성을 수정할 수 있다는 것을 알고 있습니다. ELMAH는 handleerror 속성을 사용할 때 무시됩니다. 즉, 처리 되었기 때문에 오류가 있다는 것을 알 수 없습니다. 이미 속성에 의해 ... 내가 요청하는 것은 속성이 처리하더라도 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의 오류 신호 를 먼저 사용하려고 시도 합니다. 실패하면 오류를 필터링해야하는지 여부를 확인합니다. 그렇지 않은 경우 오류가 단순히 기록됩니다. 이 구현은 메일 알림을 처리하지 않습니다. 예외가 신호를받을 수있는 경우 그렇게하도록 구성된 경우 메일이 전송됩니다.
You may also have to take care that if multiple HandleErrorAttribute
instances are in effect then duplicate logging does not occur, but the above two examples should get your started.
Sorry, but I think the accepted answer is an overkill. All you need to do is this:
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);
}
}
and then register it (order is important) in Global.asax.cs:
public static void RegisterGlobalFilters (GlobalFilterCollection filters)
{
filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new HandleErrorAttribute());
}
There is now an ELMAH.MVC package in NuGet that includes an improved solution by Atif and also a controller that handles the elmah interface within MVC routing (no need to use that axd anymore)
The problem with that solution (and with all the ones here) is that one way or another the elmah error handler is actually handling the error, ignoring what you might want to set up as a customError tag or through ErrorHandler or your own error handler
The best solution IMHO is to create a filter that will act at the end of all the other filters and log the events that have been handled already. The elmah module should take care of loging the other errors that are unhandled by the application. This will also allow you to use the health monitor and all the other modules that can be added to asp.net to look at error events
I wrote this looking with reflector at the ErrorHandler inside elmah.mvc
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;
}
}
Now, in your filter config you want to do something like this:
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());
}
Notice that I left a comment there to remind people that if they want to add a global filter that will actually handle the exception it should go BEFORE this last filter, otherwise you run into the case where the unhandled exception will be ignored by the ElmahMVCErrorFilter because it hasn't been handled and it should be loged by the Elmah module but then the next filter marks the exception as handled and the module ignores it, resulting on the exception never making it into elmah.
Now, make sure the appsettings for elmah in your webconfig look something like this:
<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 -->
The important one here is "elmah.mvc.disableHandleErrorFilter", if this is false it will use the handler inside elmah.mvc that will actually handle the exception by using the default HandleErrorHandler that will ignore your customError settings
This setup allows you to set your own ErrorHandler tags in classes and views, while still loging those errors through the ElmahMVCErrorFilter, adding a customError configuration to your web.config through the elmah module, even writing your own Error Handlers. The only thing you need to do is remember to not add any filters that will actually handle the error before the elmah filter we've written. And I forgot to mention: no duplicates in elmah.
You can take the code above and go one step further by introducing a custom controller factory that injects the HandleErrorWithElmah attribute into every controller.
For more infomation check out my blog series on logging in MVC. The first article covers getting Elmah set up and running for MVC.
There is a link to downloadable code at the end of the article. Hope that helps.
http://dotnetdarren.wordpress.com/
I'm new in ASP.NET MVC. I faced the same problem, the following is my workable in my Erorr.vbhtml (it work if you only need to log the error using Elmah log)
@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>
It is simply!
A completely alternative solution is to not use the MVC HandleErrorAttribute
, and instead rely on ASP.Net error handling, which Elmah is designed to work with.
You need to remove the default global HandleErrorAttribute
from App_Start\FilterConfig (or Global.asax), and then set up an error page in your Web.config:
<customErrors mode="RemoteOnly" defaultRedirect="~/error/" />
Note, this can be an MVC routed URL, so the above would redirect to the ErrorController.Index
action when an error occurs.
For me it was very important to get email logging working. After some time I discover that this need only 2 lines of code more in Atif example.
public class HandleErrorWithElmahAttribute : HandleErrorAttribute
{
static ElmahMVCMailModule error_mail_log = new ElmahMVCMailModule();
public override void OnException(ExceptionContext context)
{
error_mail_log.Init(HttpContext.Current.ApplicationInstance);
[...]
}
[...]
}
I hope this will help someone :)
This is exactly what I needed for my MVC site configuration!
I added a little modification to the OnException
method to handle multiple HandleErrorAttribute
instances, as suggested by Atif Aziz:
bear in mind that you may have to take care that if multiple
HandleErrorAttribute
instances are in effect then duplicate logging does not occur.
I simply check context.ExceptionHandled
before invoking the base class, just to know if someone else handled the exception before current handler.
It works for me and I post the code in case someone else needs it and to ask if anyone knows if I overlooked anything.
Hope it is useful:
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);
}
'Nice programing' 카테고리의 다른 글
파이썬 모듈의 버전을 확인하는 방법은 무엇입니까? (0) | 2020.10.03 |
---|---|
iostream :: eof가 루프 조건 (예 :`while (! stream.eof ())`) 내부에서 잘못된 것으로 간주되는 이유는 무엇입니까? (0) | 2020.10.03 |
파이썬에서 단일 밑줄“_”변수의 목적은 무엇입니까? (0) | 2020.10.03 |
자바 스크립트 '바인딩'방법의 사용은 무엇입니까? (0) | 2020.10.03 |
datetime을 날짜로 어떻게 변환합니까 (Python에서)? (0) | 2020.10.03 |