Использование ELMAH в консольном приложении

Я только начал пользоваться ELMAH и являюсь его фанатом. Моя команда поддерживает большое количество веб-приложений, и я особенно рад тому, что ELMAH позволяет нам сохранять исключения из каждого приложения в одну и ту же таблицу базы данных MS SQL.

Мы также поддерживаем несколько консольных, DLL и настольных приложений. Можно ли использовать DLL ELMAH для регистрации исключений в этих приложениях в том же месте?


person Michael La Voie    schedule 08.05.2009    source источник
comment
Я также планирую реализовать это в службе Windows. Просто хотел проверить, не возникнут ли какие-либо проблемы с производительностью / какие-либо другие проблемы, если мы это сделаем? Мне кажется, что это в первую очередь для веб-приложений. Я не нашел слишком много материала о том, как реализовать это в приложениях Windows. Спасибо Сони   -  person hangar18    schedule 13.07.2011


Ответы (7)


У нас здесь точно такая же ситуация. Запуск ELMAH для всех наших веб-приложений. У некоторых из них есть консольные планировщики.

После некоторого покопания в исходном коде, похоже, работает следующий код:

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

Единственная реальная проблема с приведенным выше состоит в том, что вам нужно сохранить имя приложения где-нибудь в вашей конфигурации, чтобы иметь возможность видеть записи в программе просмотра ELMAH.axd.

Итак, в нашем общем коде обработки ошибок мы делаем:

        if (HttpContext.Current != null)
            ErrorSignal.FromCurrentContext().Raise(ex);
        else
        {
            ErrorLog errorLog = ErrorLog.GetDefault(null);
            errorLog.ApplicationName = ErrorHandling.Application;
            errorLog.Log(new Error(ex));
        }
person Neil Bostrom    schedule 01.07.2009
comment
Хм - довольно круто, но я не могу заставить его отправлять электронные письма, когда в консольном приложении возникает ошибка. Любые идеи? - person teedyay; 12.03.2010
comment
Маловероятно, что errorLog.Log обходит всех остальных слушателей. Кто-нибудь знает лучше? - person Neil Bostrom; 15.03.2010
comment
@Duke Мне понравился этот подход, но, к сожалению, мой модуль находится в отдельном проекте. Я понял, если вы ссылаетесь на elmah таким образом, чтобы использовать его в не веб-приложении, он не будет компилироваться, пока вы не добавите к нему System.Web Dll. - person Joy; 12.06.2014

Нам нужна была возможность входа из консольного приложения и службы Windows в дополнение к нашему сайту ASP.NET. Я использовал ответ (ErrorLog.GetDefault(null);), который работал хорошо, пока мне тоже не понадобилось написать по электронной почте.

Итак, вот мое решение. Он обрабатывает журнал, электронную почту, твиты и фильтрацию (как в файле конфигурации, так и в коде). Я также обернул основной вызов как расширение Exception, чтобы его можно было вызывать так: 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 в вашем проекте, чтобы это работало.

РЕДАКТИРОВАТЬ: согласно комментариям, этот код будет отправлять электронные письма только в том случае, если в вашем файле конфигурации есть <errorMail async="false"/>. Обратитесь к этому фрагменту кода, если вы хотите сохранить <errorMail async="true"/> в своем файле конфигурации (для использования, когда доступен HttpContext.Current. ).

person Brian Chance    schedule 18.03.2010
comment
Классный пост. Это отлично сработало для меня. Просто нужно было поместить обычные вещи из web.config в мой app.config и гладко! - person Chris Kooken; 09.11.2010
comment
Это не работало для меня в модульном тесте, пока я не установил ‹elmah› ‹errorMail async = false /› ‹/elmah›. У меня ранее для async было установлено значение true. - person Todd Smith; 23.02.2011
comment
Спасибо за сообщение - отлично поработали! Мы подключили множество событий, включая ErrorLog_Filtering, ErrorLog_Logged, ErrorMail_Filtering, ErrorMail_Mailing, ErrorMail_Mailed, ErrorMail_DisposingMail, используя соответствующие классы (ExceptionFilterEventHandler, ErrorLoggedEventHandler и т. Д.) - person Zugwalt; 13.05.2011
comment
Я скопировал ваш код и в своем исключении делаю это ex.LogToElmah (); и он проходит через код, но когда я смотрю в elmah.axd, ничего не регистрируется. На локальном хосте я не использую отправку электронной почты или что-то еще, поэтому я не уверен, является ли это причиной или нет. Но ничего не вылетает. Мне нужно что-то еще подключить? - person chobo2; 08.06.2011
comment
Используя это расширение. Добавление configsection и конфигурации elmah в app.config, установив ‹errorMail async = false /›, заставило меня работать. - person Jim Wolff; 26.06.2012
comment
В моем журнале ошибок тоже не было (я использую журнал SQL-сервера). Мне пришлось установить атрибут applicationName в моем файле App.config, чтобы он заработал. Т.е. <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" applicationName="/LM/W3SVC/3/ROOT" /> - person asgeo1; 01.08.2012
comment
Я получаю такую ​​ошибку: System.ArgumentException: Path cannot be the empty string or all whitespace., кто-нибудь знает почему? Для этого нет записей поиска в Google !! - person Ashkan; 02.07.2014
comment
Немного запутался, я просто добавляю отдельный класс с приведенным выше кодом, добавляю errorlog настройки в App.config. Что еще мне нужно сделать? Более того, я не могу найти applicationName в основном Project Web.Config для включения в App.config консольного приложения. - person Shyamal Parikh; 09.10.2017

Если вы просто хотите отправить журнал по электронной почте без 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="[email protected]" to="[email protected]" />
  </elmah>

И настройки smtp на ваш выбор.

Все сделано. :-)

person Jeff    schedule 20.06.2012
comment
Руки вниз ответ! после попытки eeeeverything это сработало сначала попробуйте! - person Egli Becerra; 28.10.2016

Изменить: это МОЖНО сделать - см. этот ответ.


Я почти уверен, что ты не сможешь этого сделать. Попробую раскопать соответствующий материал.

com / group / elmah / browse_thread / thread / f214c4f782dc2bf4 / d96fe43b60765f0c? lnk = gst & q = app # d96fe43b60765f0c

Итак, из того, что я могу найти в группе Google, так это то, что это невозможно ... Поскольку ELMAH работает с HttpHandlers (конструкция asp.net), это только ASP.NET.

С учетом сказанного, есть способы использовать его в консольном приложении. ELMAH предоставляет метод для возникновения ошибок, поэтому вы можете обернуть ELMAH в свою обработку исключений, а затем сигнализировать об ошибке с помощью:

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

Это означало бы обернуть все ваше приложение обработчиком исключений и сигнализацией. Вам может потребоваться некоторая настройка, чтобы разобраться с этим, но я думаю, что это вполне возможно.

Если вам это нужно, это ссылка на ELMAH репозиторий кода.

person Gavin Miller    schedule 08.05.2009
comment
Спасибо. Я понимаю, что это не было построено вокруг этого, но похоже, что у других может быть потребность поделиться общей ошибкой db - person Michael La Voie; 08.05.2009

Для тех, кому нужен ответ Брайана Чанса, перенесенный на 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

Однако для записи ошибок в базу данных этого будет достаточно:

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

Как полное решение:

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 ()

person Stefan Steiger    schedule 08.01.2013

Ну, так как я не могу комментировать, я отправлю это здесь, и, возможно, кто-то это увидит.

Следуя методу Брайана и комментаторам, я смог заставить электронную почту работать, но я все еще не видел, чтобы сообщения SQL регистрировались, хотя я установил applicationName. Чего я не понимал, так это того, что они на самом деле регистрировались, я просто их не видел, потому что applicationName должно быть таким же, как ваш web.config, чтобы иметь возможность его просматривать.

В моем web.config не было указано applicationName, поэтому по умолчанию было указано «/ LM / W3SVC / 2 / ROOT», что, по сути, и прокомментировал asgeo1, хотя я не понимал, что это должно быть то же самое.

Поскольку на самом деле у меня не было никаких ошибок, которые меня беспокоили, я настроил applicationName в моем web.config и моем app.config, чтобы они были одинаковыми, и теперь все отображается как чемпион.

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" />
person John W.    schedule 23.01.2013

ELMAH расшифровывается как «Модули регистрации ошибок и обработчики», что, конечно же, относится к IHttpModule и IHttpHandler.

Консольные приложения не используют HTTP, поэтому обычно не могут получить много преимуществ от модулей и обработчиков, созданных для HTTP.

person yfeldblum    schedule 01.07.2009