.net - Usando ELMAH en una aplicación de consola
desktop-application console-application (7)
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?
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.
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" />
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.
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 <errorMail async="false"/>
. Consulte este fragmento de código si desea mantener <errorMail async="true"/>
en su archivo de configuración (para ser utilizado cuando HttpContext.Current esté disponible).
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
<System.Runtime.CompilerServices.Extension> _
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://.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.Compilation.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.Compilation.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 ()
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
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
Y
<elmah>
<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="C:/Elmah.Error" applicationName="MyAwesomeApp" />
<errorMail from="[email protected]" to="[email protected]" />
</elmah>
Y la configuración smtp de su elección.
Todo listo. :-)
Tenemos exactamente la misma situación aquí. Ejecutar ELMAH para todas nuestras aplicaciones web. Algunos de ellos tienen programadores 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));
}
Editar : Esto PUEDE hacerse - Ver this respuesta.
Estoy bastante seguro de que no puedes hacer esto. Intentaré desenterrar el material relevante.
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 repositorio de códigos ELMAH .