2009-05-08 14 views
56

Acabo de empezar 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.Usando ELMAH en una aplicación de consola

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?

+0

Estoy planeando implementar esto en un servicio de Windows también. ¿Solo quería verificar si hay problemas de rendimiento/algún otro problema si lo hacemos? Me parece que esto es principalmente para aplicaciones basadas en web. No he encontrado demasiado material sobre cómo implementarlo en aplicaciones de Windows.Gracias Soni – hangar18

Respuesta

64

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 hacer algo de investigación a través del código fuente, el siguiente código parece funcionar:

  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 se necesita para mantener el nombre de la aplicación en algún lugar de su configuración para poder para ver las entradas en el visor ELMAH.axd.

Así que en nuestro código de control de error genérico que hacemos:

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

Muy bien, voy a probar esto. –

+2

Hmm, es genial, pero parece que no puedo enviar correos electrónicos cuando ocurre el error en la aplicación de la consola. ¿Algunas ideas? – teedyay

+3

Improbable, el error Log.Log parece omitir todos los otros oyentes. Alguien sabe mejor? –

5

Editar: Este CAN hacerse - Ver this 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

Así que de lo que puedo encontrar buscando en el grupo de Google es que no es posible ... Desde ELMAH trabaja fuera 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 aumentar los errores, por lo que podría envolver 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 excepciones y la señalización. Podría necesitar algunos ajustes para bajarlo, pero creo que es totalmente posible.

En caso de que lo necesite, este es el enlace al ELMAH code repository.

+0

Gracias. Entiendo que no fue en torno a esto, pero parece una necesidad que otros puedan tener, compartir un error común db –

-5

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.

75

Necesitamos 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 envuelto la llamada principal como una extensión a Excepción para que pueda llamarse como: catch(Exception ex) { ex.LogToElmah(); }

Para filtrar el código, enganche el correspondiente.Filtrado de sucesos: 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, tendrá que añadir una referencia a la System.Web.dll en su proyecto para que esto funcione.

EDIT: Según los comentarios, este código enviará correos electrónicos solo si su archivo de configuración tiene <errorMail async="false"/>. Consulte this code snippet si desea mantener <errorMail async="true"/> en su archivo de configuración (para ser utilizado cuando HttpContext.Current esté disponible).

+0

Awesome post. Esto funcionó perfectamente para mí. Solo tuve que poner las cosas normales de la web.config en mi app.config y navegando sin problemas. –

+6

Esto no funcionaba para mí en una prueba unitaria hasta que configuré . Anteriormente había configurado la asincronía como verdadera. –

+0

¡Gracias por el trabajo excelente! Conectamos muchos eventos incluyendo ErrorLog_Filtering, ErrorLog_Logged, ErrorMail_Filtering, ErrorMail_Mailing, ErrorMail_Mailed, ErrorMail_DisposingMail usando las clases apropiadas (ExceptionFilterEventHandler, ErrorLoggedEventHandler, etc.) – Zugwalt

9

Si lo que desea es enviar el registro sin http usted puede hacer así:

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 smtp configuración de su elección.

Todo listo. :-)

+1

Sin duda la respuesta! ¡Después de probar eeeeverything, esto funcionó primero, intente! –

2

Para aquellos que necesitan respuesta de Brian Probabilidad portado 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, por sólo el registro de errores de 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.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 Initialize()

1

Bueno, ya que no puedo comentar voy a publicar esto aquí y tal vez alguien lo verá.

Después de seguir el método de Brian y los comentarios, 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 applicationName especificado, por lo que estaba predeterminado en "/ LM/W3SVC/2/ROOT", que es básicamente lo que "asgeo1" comentó, aunque no me di cuenta de que tenía que ser lo mismo.

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

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" /> 
Cuestiones relacionadas