Usando ELMAH en una aplicación de consola

Empecé a usar ELMAH y soy fan. Mi equipo es compatible con una gran cantidad de aplicaciones web y estoy particularmente emocionado de que ELMAH nos permita guardar las excepciones de cada aplicación en la misma tabla de base de datos MS SQL.

También admitimos algunas consolas, DLL y aplicaciones de escritorio. ¿Es posible utilizar el DLL ELMAH para registrar excepciones en estas aplicaciones en esa misma ubicación?

Tenemos exactamente la misma situación aquí. Ejecutar ELMAH para todas nuestras aplicaciones web. Algunos de ellos tienen progtwigdores basados ​​en consola.

Después de investigar el código fuente, parece que el siguiente código funciona:

ErrorLog errorLog = ErrorLog.GetDefault(null); errorLog.ApplicationName = "/LM/W3SVC/1/ROOT/AppName"; errorLog.Log(new Error(ex)); 

El único problema real con lo anterior es que debe mantener el nombre de la aplicación en algún lugar de su configuración para poder ver las entradas en el visor ELMAH.axd.

Entonces en nuestro código genérico de manejo de errores lo hacemos:

  if (HttpContext.Current != null) ErrorSignal.FromCurrentContext().Raise(ex); else { ErrorLog errorLog = ErrorLog.GetDefault(null); errorLog.ApplicationName = ErrorHandling.Application; errorLog.Log(new Error(ex)); } 

Necesitábamos la capacidad de iniciar sesión desde una aplicación de consola y un servicio de Windows además de nuestro sitio ASP.NET. Utilicé la respuesta ( ErrorLog.GetDefault(null); ) que funcionó bien hasta que necesité un correo electrónico también.

Entonces, aquí está mi solución. Maneja el registro, el correo electrónico, el tweet y el filtrado (tanto en el archivo de configuración como en el código). También he ajustado la llamada principal como una extensión a Exception para que se pueda llamar como: catch(Exception ex) { ex.LogToElmah(); } catch(Exception ex) { ex.LogToElmah(); }

Para filtrar el código, enganche el evento .Filtering correspondiente: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);

Código:

 using System; using System.Web; using Elmah; namespace System { public static class ElmahExtension { public static void LogToElmah(this Exception ex) { if (HttpContext.Current != null) { ErrorSignal.FromCurrentContext().Raise(ex); } else { if (httpApplication == null) InitNoContext(); ErrorSignal.Get(httpApplication).Raise(ex); } } private static HttpApplication httpApplication = null; private static ErrorFilterConsole errorFilter = new ErrorFilterConsole(); public static ErrorMailModule ErrorEmail = new ErrorMailModule(); public static ErrorLogModule ErrorLog = new ErrorLogModule(); public static ErrorTweetModule ErrorTweet = new ErrorTweetModule(); private static void InitNoContext() { httpApplication = new HttpApplication(); errorFilter.Init(httpApplication); (ErrorEmail as IHttpModule).Init(httpApplication); errorFilter.HookFiltering(ErrorEmail); (ErrorLog as IHttpModule).Init(httpApplication); errorFilter.HookFiltering(ErrorLog); (ErrorTweet as IHttpModule).Init(httpApplication); errorFilter.HookFiltering(ErrorTweet); } private class ErrorFilterConsole : ErrorFilterModule { public void HookFiltering(IExceptionFiltering module) { module.Filtering += new ExceptionFilterEventHandler(base.OnErrorModuleFiltering); } } } } 

Además, deberá agregar una referencia a System.Web.dll en su proyecto para que esto funcione.

EDITAR : según los comentarios, este código enviará correos electrónicos solo si su archivo de configuración tiene . Consulte este fragmento de código si desea mantener en su archivo de configuración (para ser utilizado cuando HttpContext.Current esté disponible).

Si solo desea enviar un correo electrónico al registro sin http, puede hacer esto:

  public class MyElmahMail: ErrorMailModule { public MyElmahMail() { //this basically just gets config from errorMail (app.config) base.OnInit(new HttpApplication()); } public void Log(Error error) { //just send the email pls base.ReportError(error); } } //to call it var mail = new MyElmahMail(); mail.Log(new Error(new NullReferenceException()));//whatever exception u want to log 

Y en términos de app.config

 //Under configSections  

Y

      

Y la configuración smtp de su elección.

Todo listo. 🙂

Editar : Esto PUEDE hacerse – Ver esta respuesta.


Estoy bastante seguro de que no puedes hacer esto. Intentaré desenterrar el material relevante.

http://groups.google.com/group/elmah/browse_thread/thread/f214c4f782dc2bf4/d96fe43b60765f0c?lnk=gst&q=app#d96fe43b60765f0c

Entonces, de lo que puedo encontrar buscando en el grupo de Google es que no es posible … Dado que ELMAH funciona a partir de HttpHandlers (una construcción asp.net), es ASP.NET solamente.

Dicho esto, hay formas en que puede utilizarlo en una aplicación de consola. ELMAH proporciona un método para generar errores, por lo que puede ajustar ELMAH en su manejo de excepciones y luego señalar un error a través de:

 ErrorSignal.FromCurrentContext().Raise(new NotSupportedException()); 

Esto significaría envolver toda su aplicación en un controlador de excepción y señalización. Podría necesitar algunos ajustes para bajarlo, pero creo que es totalmente posible.

En caso de que lo requiera, este es el enlace al repository de códigos ELMAH .

Para aquellos que necesitan la respuesta de Brian Chance portada a VB.NET:

 Imports System Imports System.Web Imports Elmah Namespace System Public NotInheritable Class ElmahExtension Private Sub New() End Sub  _ Public Shared Sub LogToElmah(ex As Exception) If HttpContext.Current IsNot Nothing Then ErrorSignal.FromCurrentContext().Raise(ex) Else If httpApplication Is Nothing Then InitNoContext() End If ErrorSignal.[Get](httpApplication).Raise(ex) End If End Sub Private Shared httpApplication As HttpApplication = Nothing Private Shared errorFilter As New ErrorFilterConsole() Public Shared ErrorEmail As New ErrorMailModule() Public Shared ErrorLog As New ErrorLogModule() Public Shared ErrorTweet As New ErrorTweetModule() Private Shared Sub InitNoContext() httpApplication = New HttpApplication() errorFilter.Init(httpApplication) TryCast(ErrorEmail, IHttpModule).Init(httpApplication) errorFilter.HookFiltering(ErrorEmail) TryCast(ErrorLog, IHttpModule).Init(httpApplication) errorFilter.HookFiltering(ErrorLog) TryCast(ErrorTweet, IHttpModule).Init(httpApplication) errorFilter.HookFiltering(ErrorTweet) End Sub Private Class ErrorFilterConsole Inherits Elmah.ErrorFilterModule Public Sub HookFiltering([module] As Elmah.IExceptionFiltering) AddHandler [module].Filtering, New Elmah.ExceptionFilterEventHandler(AddressOf MyBase.OnErrorModuleFiltering) End Sub End Class End Class End Namespace 

Sin embargo, solo para registrar errores en la base de datos, esto será suficiente:

 If System.Web.HttpContext.Current Is Nothing Then Dim req As System.Web.HttpRequest = New System.Web.HttpRequest(String.Empty, "https://www.domain.tld", Nothing) Dim res As System.Web.HttpResponse = New System.Web.HttpResponse(Nothing) System.Web.HttpContext.Current = New System.Web.HttpContext(req, res) 'Dim request As System.Web.Hosting.SimpleWorkerRequest = New System.Web.Hosting.SimpleWorkerRequest("/blah", "c:\inetpub\wwwroot\blah", "blah.html", Nothing, New System.IO.StringWriter()) 'System.Web.HttpContext.Current = New System.Web.HttpContext(request) System.Web.HttpContext.Current.ApplicationInstance = New System.Web.HttpApplication() Dim ErrorLog As New Elmah.ErrorLogModule() TryCast(ErrorLog, System.Web.IHttpModule).Init(System.Web.HttpContext.Current.ApplicationInstance) End If 

Como una solución completa:

 Public parent As Elmah.ServiceProviderQueryHandler = Nothing ' http://stackoverflow.com/questions/5981750/configuring-elmah-with-sql-server-logging-with-encrypted-connection-string Public Function Elmah_MS_SQL_Callback(objContext As Object) As System.IServiceProvider Dim container As New System.ComponentModel.Design.ServiceContainer(parent(objContext)) Dim strConnectionString As String = COR.SQL.MS_SQL.GetConnectionString() Dim log As Elmah.SqlErrorLog = New Elmah.SqlErrorLog(strConnectionString) 'Dim strApplicationName = System.Web.Comstacktion.BuildManager.GetGlobalAsaxType().BaseType.Assembly().FullName Dim strApplicationName As String = System.Reflection.Assembly.GetExecutingAssembly().FullName If Not String.IsNullOrEmpty(strApplicationName) Then log.ApplicationName = strApplicationName.Substring(0, strApplicationName.IndexOf(",")) End If container.AddService(GetType(Elmah.ErrorLog), log) Return container End Function ' Elmah_MS_SQL_Callback Public Function Elmah_PG_SQL_Callback(objContext As Object) As System.IServiceProvider Dim container As New System.ComponentModel.Design.ServiceContainer(parent(objContext)) Dim strConnectionString As String = COR.SQL.MS_SQL.GetConnectionString() Dim log As Elmah.PgsqlErrorLog = New Elmah.PgsqlErrorLog(strConnectionString) 'Dim strApplicationName = System.Web.Comstacktion.BuildManager.GetGlobalAsaxType().BaseType.Assembly().FullName Dim strApplicationName As String = System.Reflection.Assembly.GetExecutingAssembly().FullName If Not String.IsNullOrEmpty(strApplicationName) Then log.ApplicationName = strApplicationName.Substring(0, strApplicationName.IndexOf(",")) End If container.AddService(GetType(Elmah.ErrorLog), log) Return container End Function ' Elmah_PG_SQL_Callback ' http://weblogs.asp.net/stevewellens/archive/2009/02/01/debugging-a-deployed-site.aspx Public Sub Initialize() If System.Web.HttpContext.Current Is Nothing Then Dim req As System.Web.HttpRequest = New System.Web.HttpRequest(String.Empty, "https://www.domain.tld", Nothing) Dim res As System.Web.HttpResponse = New System.Web.HttpResponse(Nothing) System.Web.HttpContext.Current = New System.Web.HttpContext(req, res) 'Dim request As System.Web.Hosting.SimpleWorkerRequest = New System.Web.Hosting.SimpleWorkerRequest("/blah", "c:\inetpub\wwwroot\blah", "blah.html", Nothing, New System.IO.StringWriter()) 'System.Web.HttpContext.Current = New System.Web.HttpContext(request) System.Web.HttpContext.Current.ApplicationInstance = New System.Web.HttpApplication() Dim ErrorLog As New Elmah.ErrorLogModule() TryCast(ErrorLog, System.Web.IHttpModule).Init(System.Web.HttpContext.Current.ApplicationInstance) End If parent = Elmah.ServiceCenter.Current If SQL.IsMsSql Then Elmah.ServiceCenter.Current = AddressOf Elmah_MS_SQL_Callback End If If SQL.IsPostGreSql Then Elmah.ServiceCenter.Current = AddressOf Elmah_PG_SQL_Callback End If End Sub ' InitializeElmah 

Y

 Elmah.ErrorSignal.FromCurrentContext().Raise(New NotImplementedException("Test")) 

funcionará si se llama después de Inicializar ()

Bueno, como no puedo comentar, publicaré esto aquí y tal vez alguien lo vea.

Después de seguir el método de Brian y los comentaristas, pude hacer que el correo electrónico funcionara, pero todavía no veía los mensajes SQL que se estaban registrando, aunque había establecido el nombre de la aplicación. Lo que no me di cuenta es que en realidad estaban siendo registrados, simplemente no los veía porque el nombre de la aplicación debe ser el mismo que el de su web.config para poder verlo.

Mi web.config no tenía especificado applicationName, por lo que estaba predeterminado en “/ LM / W3SVC / 2 / ROOT”, que es básicamente lo que comentó “asgeo1”, aunque no me di cuenta de que tenía que ser el mismo.

Como realmente no tenía ningún error que me preocupara, configuré applicationName en mi web.config y mi app.config para que fuera el mismo y ahora todo aparece como un campeón.

  

ELMAH significa Módulos de registro de errores y controladores – refiriéndose, por supuesto, a IHttpModule y IHttpHandler .

Las aplicaciones de consola no usan HTTP, por lo que normalmente no podrían beneficiarse mucho de los Módulos y Controladores creados para HTTP.