2009-05-08 4 views
56

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

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

+0

Я также планирую реализовать это в службе Windows. Просто хотелось проверить, могут ли быть проблемы с производительностью/любые другие проблемы, если мы это сделаем? Мне кажется, что это в первую очередь для веб-приложений. Я не нашел слишком много материала о том, как реализовать его в приложениях Windows.Спасибо Soni – hangar18

ответ

64

У нас точно такая же ситуация и здесь. Запуск 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)); 
     } 
+0

Очень круто, я попробую это. –

+2

Хм - довольно круто, но я не могу заставить его отправлять электронные письма, когда ошибка возникает в консольном приложении. Есть идеи? – teedyay

+3

Вряд ли ошибкаLog.Log, похоже, обходит всех остальных слушателей. Кто-нибудь знает лучше? –

5

Edit: Это CAN быть сделано - См this ответ.


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

http://groups.google.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 code repository.

+0

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

-5

ELMAH стенды для модулей протоколирования ошибок и обработчиков - в виду, конечно, к IHttpModule и IHttpHandler.

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

75

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

Итак, вот мое решение. Он обрабатывает журнал, электронную почту, чириканье и фильтрацию (как в файле конфигурации, так и в коде). Я также завернул главный вызов в качестве расширения к исключению, поэтому его можно назвать похожим: catch(Exception ex) { ex.LogToElmah(); }

Чтобы отфильтровать в коде, подключите соответствующий.Фильтрация событий: 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 в проекте для этой работы.

EDIT: Согласно комментариям, этот код будет отправлять электронные письма только в том случае, если ваш файл конфигурации имеет <errorMail async="false"/>. Обратитесь к this code snippet, если вы хотите сохранить <errorMail async="true"/> в вашем файле конфигурации (который будет использоваться, когда доступен HttpContext.Current).

+0

Удивительный пост. Это отлично сработало для меня. Просто нужно было положить нормальный материал из web.config в мой app.config и плавное плавание! –

+6

Это не работало для меня в модульном тесте, пока я не установил . Раньше у меня была асинхронная установка true. –

+0

Спасибо за пост - отлично! Мы подключили много событий, включая ErrorLog_Filtering, ErrorLog_Logged, ErrorMail_Filtering, ErrorMail_Mailing, ErrorMail_Mailed, ErrorMail_DisposingMail с использованием соответствующих классов (ExceptionFilterEventHandler, ErrorLoggedEventHandler и т. Д.). – Zugwalt

9

Если вы просто хотите отправить журнал без 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 по вашему выбору.

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

+1

Руки вниз ответ! после попытки eeeeverything это работало в первую очередь! –

2

Для тех, кто нуждается ответ 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 

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

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

1

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

После того, как мы выполнили метод Брайана и комментаторы, я смог работать с электронной почтой, но я все еще не видел записи SQL-сообщений, даже если я установил имя приложения. То, что я не понимал, это то, что они были фактически зарегистрированы. Я просто не видел их, потому что имя приложения должно быть таким же, как ваш web.config, чтобы иметь возможность просматривать его.

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

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

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" /> 
Смежные вопросы