Utiliser ELMAH dans une application console
-
20-08-2019 - |
Question
Je viens de commencer à utiliser ELMAH et je suis un fan. Mon équipe prend en charge un grand nombre d'applications Web et je suis particulièrement heureux que ELMAH nous permette de sauvegarder les exceptions de chaque application dans la même table de base de données MS SQL.
Nous prenons également en charge quelques applications de console, de DLL et de bureau. Est-il possible d'utiliser la DLL ELMAH pour consigner les exceptions dans ces applications au même endroit?
La solution
Nous avons exactement la même situation ici. Exécuter ELMAH pour toutes nos applications Web. Certains d'entre eux ont des planificateurs basés sur la console.
Après avoir fouillé dans le code source, le code suivant semble fonctionner:
ErrorLog errorLog = ErrorLog.GetDefault(null);
errorLog.ApplicationName = "/LM/W3SVC/1/ROOT/AppName";
errorLog.Log(new Error(ex));
Le seul problème réel avec ce qui précède est que vous devez conserver le nom de l'application quelque part dans votre configuration pour pouvoir voir les entrées sur le visualiseur ELMAH.axd.
Donc, dans notre code de traitement d'erreur générique, nous faisons:
if (HttpContext.Current != null)
ErrorSignal.FromCurrentContext().Raise(ex);
else
{
ErrorLog errorLog = ErrorLog.GetDefault(null);
errorLog.ApplicationName = ErrorHandling.Application;
errorLog.Log(new Error(ex));
}
Autres conseils
Nous avions besoin de pouvoir nous connecter à partir d'une application console et d'un service Windows en plus de notre site ASP.NET. J’ai utilisé la réponse (ErrorLog.GetDefault(null);
) qui a bien fonctionné jusqu’à ce que j’ai eu besoin d’envoyer un e-mail également.
Donc, voici ma solution. Il gère le journal, email, tweet et filtrage (à la fois dans le fichier de configuration et dans le code). J'ai également enveloppé l'appel principal en tant qu'extension à Exception afin qu'il puisse être appelé comme suit: catch(Exception ex) { ex.LogToElmah(); }
Pour filtrer dans le code, décrochez l'événement .Filtering correspondant: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);
Code:
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);
}
}
}
}
De plus, vous devrez ajouter une référence au System.Web.dll
dans votre projet pour que cela fonctionne.
MODIFIER : selon les commentaires, ce code n'enverra des e-mails que si votre fichier de configuration contient <errorMail async="false"/>
. Reportez-vous à cet extrait de code si vous souhaitez conserver <errorMail async="true"/>
dans votre fichier de configuration (à utiliser lorsque HttpContext.Current est disponible).
Si vous souhaitez simplement envoyer le journal par courrier électronique sans http, procédez comme suit:
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
Et en termes d'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>
Et
<elmah>
<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="C:\Elmah.Error" applicationName="MyAwesomeApp" />
<errorMail from="from@email.com" to="to@email.com" />
</elmah>
Et les paramètres smtp de votre choix.
Tout est fait. : -)
Modifier : cela PEUT être réalisé - Voir this . répondre.
Je suis sûr que vous ne pouvez pas faire ça. Je vais essayer de trouver le matériel pertinent.
Pour ceux qui ont besoin que la réponse de Brian Chance soit transférée sur 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
Toutefois, pour consigner uniquement les erreurs dans la base de données, cela suffira:
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
En tant que solution complète:
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
Et
Elmah.ErrorSignal.FromCurrentContext().Raise(New NotImplementedException("Test"))
fonctionnera s'il est appelé après Initialize ()
Eh bien, comme je ne peux pas commenter, je vais poster ceci ici et peut-être que quelqu'un le verra.
Après avoir suivi la méthode de Brian et les commentateurs, j'ai réussi à faire fonctionner l'e-mail, mais je ne voyais toujours pas les messages SQL en cours de journalisation, même si j'avais défini le nom d'application. Ce que je ne savais pas, c’est qu’ils étaient en train d’être enregistrés. Je ne les voyais tout simplement pas, car le nom de l’application doit être identique à votre fichier web.config pour pouvoir le visualiser.
Mon nom de domaine n'a pas été spécifié dans nom.config. Le nom par défaut était donc & "; / LM / W3SVC / 2 / ROOT &" ;, ce qui est essentiellement ce que & "; asgeo1 quot; a commenté, bien que je n’aie pas réalisé que ça devait être pareil.
Comme je ne rencontrais pas vraiment d'erreurs, j'ai configuré applicationName dans mon web.config et mon app.config est identique, et maintenant tout se présente comme un champion.
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" />
ELMAH signifie "Logging Modules and Handlers" (Gestion et consignation des erreurs), faisant référence à IHttpModule
et à IHttpHandler
.
Les applications de console n'utilisant pas HTTP, elles ne pourraient donc généralement pas tirer grand profit des modules et des gestionnaires conçus pour HTTP.