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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/841451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:39:43  来源:igfitidea点击:

Using ELMAH in a console application

.netdesktop-applicationconsole-applicationelmah

提问by Michael La Voie

I just started using ELMAH and am a fan. My team supports a large number of web applications and I'm particularly excited that ELMAH lets us save exceptions from each application to the same MS SQL database table.

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

We also support a few console, DLL and desktop applications. Is it possible to use the ELMAH DLL to log exceptions in these apps to that same location?

我们还支持一些控制台、DLL 和桌面应用程序。是否可以使用 ELMAH DLL 将这些应用程序中的异常记录到同一位置?

回答by Brian Chance

We needed the ability to log from a console app and a windows service in addition to our ASP.NET site. I used the answer (ErrorLog.GetDefault(null);) which worked well until I needed to email too.

除了我们的 ASP.NET 站点之外,我们还需要能够从控制台应用程序和 Windows 服务进行登录。我使用的答案 ( ErrorLog.GetDefault(null);) 效果很好,直到我也需要发送电子邮件。

So, here is my solution. It handles the log, email, tweet and filtering (both in the config file and in code). I have also wrapped the main call as an extension to Exception so it can be called like: catch(Exception ex) { ex.LogToElmah(); }

所以,这是我的解决方案。它处理日志、电子邮件、推文和过滤(在配置文件和代码中)。我还将主调用包装为 Exception 的扩展,因此可以像这样调用它:catch(Exception ex) { ex.LogToElmah(); }

To filter in code, hook the corresponding .Filtering event: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);

要在代码中进行过滤,请挂钩相应的 .Filtering 事件: 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);
                }
            }
    }
}

In addition, you will need to add a reference to the System.Web.dllin your project for this to work.

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

EDIT: As per the comments, this code will send emails only if your config file has <errorMail async="false"/>. Refer to this code snippetshould you want to keep <errorMail async="true"/>in your config file (to be used when HttpContext.Current is available).

编辑:根据评论,此代码仅当您的配置文件具有<errorMail async="false"/>. 如果您想保留在配置文件中(在 HttpContext.Current 可用时使用),请参阅此代码片段<errorMail async="true"/>

回答by Neil Bostrom

We have exactly the same situation here. Running ELMAH for all our web applications. A few of them have console based schedulers.

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

After doing some digging through the source code, the following code seems to work:

在对源代码进行了一些挖掘之后,以下代码似乎有效:

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

The only real problem with the above is that you need to keep the application name somewhere in your config to be able to see the entries on the ELMAH.axd viewer.

上述唯一真正的问题是您需要将应用程序名称保留在配置中的某个位置,以便能够在 ELMAH.axd 查看器上看到条目。

So in our generic error handling code we do:

所以在我们的通用错误处理代码中,我们这样做:

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

回答by Jeff

If you just want to email the log without http you can do like this:

如果您只想在没有 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

And in terms of app.config

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

And

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

And smtp settings of your choice.

以及您选择的 smtp 设置。

All done. :-)

全部完成。:-)

回答by Gavin Miller

Edit: This CANbe done - See thisanswer.

编辑:这CAN做-见这个答案。



I'm pretty sure you can't do this. I'll try and dig up the relevant material.

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

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

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

So from what I can find searching the Google group is that it's not possible... Since ELMAH works off of HttpHandlers (an asp.net construct) it is ASP.NET only.

因此,从我在 Google 群组中搜索到的信息来看,这是不可能的……由于 ELMAH 使用 HttpHandlers(一个 asp.net 构造),因此它仅适用于 ASP.NET。

With that said, there are ways that you could utilize it on a console application. ELMAH provides a method to raise errors, so you could wrap ELMAH in your exception handling and then signal an error via:

话虽如此,您可以通过多种方式在控制台应用程序上使用它。ELMAH 提供了一种引发错误的方法,因此您可以将 ELMAH 包装在您的异常处理中,然后通过以下方式发出错误信号:

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

This would mean wrapping your entire application in an exception handler and signaling. It might take you some tweaking to get it down, but I think it's totally possible.

这意味着将整个应用程序包装在异常处理程序和信号中。您可能需要进行一些调整才能将其关闭,但我认为这是完全可能的。

In case you require it, this is the link to the ELMAH code repository.

如果您需要,这是指向ELMAH 代码存储库的链接。

回答by Stefan Steiger

For those that need Brian Chance's answer ported to VB.NET:

对于那些需要将 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

However, for just logging errors to the database, this will be sufficient:

但是,对于仅将错误记录到数据库中,这已经足够了:

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

As a complete solution:

作为一个完整的解决方案:

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

And

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

will work if it is called after Initialize()

如果在 Initialize() 之后调用它会起作用

回答by John W.

Well, since I can't comment I'll post this down here and maybe someone will see it.

好吧,既然我不能发表评论,我会把它贴在这里,也许有人会看到。

After following Brian's method and the commentors I was able to get email working but I still wasn't seeing the SQL messages being logged, even though I had set the applicationName. What I didn't realize is that they were actually being logged I just wasn't seeing them because the applicationName must be the same as your web.config in order to be able to view it.

在遵循 Brian 的方法和评论者之后,我能够使电子邮件正常工作,但我仍然没有看到 SQL 消息被记录,即使我已经设置了 applicationName。我没有意识到它们实际上被记录了我只是没有看到它们,因为 applicationName 必须与您的 web.config 相同才能查看它。

My web.config didn't have applicationName specified, so it was defaulting to "/LM/W3SVC/2/ROOT", which is basically what "asgeo1" commented, though I didn't realize it had to be the same.

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

Since I didn't really have any errors I was concerned with, I configured applicationName in my web.config and my app.config to be the same and now everything shows up like a champ.

由于我没有真正关心的任何错误,我在我的 web.config 和我的 app.config 中将 applicationName 配置为相同,现在一切都像冠军一样显示。

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

回答by yfeldblum

ELMAH stands for Error Logging Modules and Handlers - referring, of course, to IHttpModuleand IHttpHandler.

ELMAH 代表错误日志模块和处理程序 - 当然,指的是IHttpModuleIHttpHandler

Console applications do not use HTTP, so would typically not be able to benefit much from Modules and Handlers built for HTTP.

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