在控制台应用程序中使用ELMAH

我刚开始使用ELMAH,是一个粉丝。 我的团队支持大量的Web应用程序,对于ELMAH允许我们将每个应用程序的exception保存到同一个MS SQL数据库表中,我感到特别兴奋。

我们也支持一些控制台,DLL和桌面应用程序。 是否可以使用ELMAH DLL将这些应用程序中的exceptionlogging到同一位置?

我们在这里的情况完全一样。 为我们所有的Web应用程序运行ELMAH。 其中一些具有基于控制台的调度器。

在通过源代码进行一些挖掘之后,下面的代码似乎工作:

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

上述唯一真正的问题是,您需要将configuration文件中的应用程序名称保存在ELMAH.axd查看器中。

所以在我们的通用error handling代码中,我们做:

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

除了我们的ASP.NET网站,我们还需要能够从控制台应用程序和Windows服务login。 我使用了( ErrorLog.GetDefault(null); )的答案,直到我需要发送电子邮件。

所以,这是我的解决scheme。 它处理日志,电子邮件,推特和过滤(在configuration文件和代码中)。 我也包装了主要调用作为扩展到exception,所以它可以被称为像: catch(Exception ex) { ex.LogToElmah(); } catch(Exception ex) { ex.LogToElmah(); }

要在代码中进行筛选,请勾选相应的.Filtering事件: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);

码:

 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); } } } } 

另外,您需要在项目中添加一个对System.Web.dll的引用,才能正常工作。

编辑 :根据评论,这个代码将发送电子邮件只有当你的configuration文件<errorMail async="false"/> 。 如果你想在你的configuration文件中保留<errorMail async="true"/> (在HttpContext.Current可用时使用),请参考这段代码 。

如果你只是想没有http的电子邮件日志,你可以这样做:

  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 

而在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> 

  <elmah> <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="C:\Elmah.Error" applicationName="MyAwesomeApp" /> <errorMail from="from@email.com" to="to@email.com" /> </elmah> 

和你select的SMTP设置。

全做完了。 🙂

编辑 :这可以完成 – 看到这个答案。


我很确定你不能这样做。 我会尽力挖掘相关材料。

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

因此,从我所能find的searchGoogle组是不可能的…因为ELMAH从HttpHandlers(一个asp.net构造)工作,它只是ASP.NET。

这就是说,有一些方法可以在控制台应用程序中使用它。 ELMAH提供了一种引发错误的方法,所以你可以在你的exception处理中包装ELMAH,然后通过以下方式发出错误信号:

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

这意味着将您的整个应用程序封装在exception处理程序和信号中。 它可能需要你调整一下,但我认为这是完全可能的。

如果你需要,这是链接到ELMAH代码库 。

对于需要将Brian Chance的答案移植到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 

但是,只要将错误logging到数据库,就足够了:

 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 

作为完整的解决scheme:

 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 

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

将在Initialize()之后调用

那么,因为我不能评论我会在这里下载,也许有人会看到它。

在遵循Brian的方法和注释器之后,我可以使电子邮件工作,但是我仍然没有看到正在logging的SQL消息,即使我已经设置了applicationName。 我没有意识到的是,他们实际上被logging,我只是没有看到他们,因为applicationName必须是你的web.config相同,才能够查看它。

我的web.config没有指定applicationName,所以默认为“/ LM / W3SVC / 2 / ROOT”,这基本上是“asgeo1”所评论的,尽pipe我没有意识到它必须是相同的。

由于我真的没有任何错误,我担心,我configurationapplicationName在我的web.config和我的app.config是相同的,现在一切都显示出像一个冠军。

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

ELMAH代表错误logging模块和处理程序 – 当然是指IHttpModuleIHttpHandler

控制台应用程序不使用HTTP,因此通常无法从为HTTP构build的模块和处理程序中获益。