2009-05-08 22 views
56

Właśnie zacząłem używać ELMAH i jestem fanem. Mój zespół obsługuje dużą liczbę aplikacji internetowych i jestem szczególnie podekscytowany tym, że ELMAH pozwala nam zapisywać wyjątki z każdej aplikacji do tej samej tabeli bazy danych MS SQL.Używanie ELMAH w aplikacji konsolowej

Obsługujemy również kilka aplikacji konsolowych, DLL i stacjonarnych. Czy jest możliwe użycie biblioteki DLL ELMAH do rejestrowania wyjątków w tych aplikacjach w tej samej lokalizacji?

+0

Mam zamiar wdrożyć to również w usłudze systemu Windows. Chciałem tylko sprawdzić, czy mogą wystąpić jakieś problemy z wydajnością/inne problemy, jeśli to zrobimy? Wydaje mi się, że jest to przede wszystkim dla aplikacji internetowych. Nie znalazłem zbyt wiele materiałów na temat tego, jak go wdrożyć w aplikacjach Windows.Dzięki Soni – hangar18

Odpowiedz

64

Mamy dokładnie tę samą sytuację tutaj. Uruchamianie ELMAH dla wszystkich naszych aplikacji internetowych. Niektóre z nich mają harmonogramy oparte na konsoli.

Po wykonaniu niektórych Kopanie poprzez kod źródłowy, następujący kod wydaje się działać:

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

Jedynym problemem z powyższego jest to, że trzeba zachować nazwę aplikacji gdzieś w config, aby móc aby wyświetlić wpisy w przeglądarce ELMAH.axd.

Więc w naszym rodzajowego kodu obsługi błędów robimy:

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

Bardzo fajnie, spróbuję tego. –

+2

Hmm - całkiem fajnie, ale wydaje mi się, że nie mogę wysłać e-maili, gdy błąd wystąpi w aplikacji konsolowej. Jakieś pomysły? – teedyay

+3

Mało prawdopodobne, errorLog.Log wydaje się ominąć wszystkie inne słuchaczy. Ktoś wie lepiej? –

5

Edit: Ten CAN być zrobione - Zobacz this odpowiedź.


Jestem prawie pewien, że nie możesz tego zrobić. Spróbuję wykopać odpowiedni materiał.

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

więc od tego, co można znaleźć przeszukując grupę Google jest to, że nie jest to możliwe ... Ponieważ ELMAH działa off HttpHandlers (konstruktem ASP.NET) to tylko ASP.NET.

Dzięki tym rzeczom istnieją sposoby na wykorzystanie jej w aplikacji konsolowej. ELMAH zapewnia sposób podnieść błędy, więc można owinąć ELMAH w obsługę wyjątków, a następnie sygnalizuje błąd poprzez:

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

Oznaczałoby to owijanie całą aplikację w module obsługi i sygnalizacji wyjątków. Może to wymagać pewnych ulepszeń, ale wydaje mi się, że jest to całkowicie możliwe.

Jeśli jest to wymagane, jest to link do ELMAH code repository.

+0

Dziękuję. Rozumiem, że nie było tego zbudowane, ale wygląda na to, że potrzebują inni, aby podzielić się wspólnym błędem db –

-5

ELMAH stoi na błędy modułów rejestrowania i teleskopowe - odnosząc się oczywiście do IHttpModule i IHttpHandler.

Aplikacje konsolowe nie używają protokołu HTTP, dlatego zazwyczaj nie można wiele skorzystać z modułów i procedur zbudowanych dla protokołu HTTP.

75

Potrzebowaliśmy możliwości logowania się z aplikacji konsoli i usługi Windows oprócz naszej witryny ASP.NET. Użyłem odpowiedzi (ErrorLog.GetDefault(null);), która działała dobrze, dopóki nie musiałem wysyłać e-maili.

Oto moje rozwiązanie. Obsługuje log, email, tweet i filtrowanie (zarówno w pliku konfiguracyjnym, jak iw kodzie). Zawarłem również główne wywołanie jako rozszerzenie wyjątku, aby można było je nazwać: catch(Exception ex) { ex.LogToElmah(); }

Aby przefiltrować w kodzie, zaczep odpowiednie.Filtrowanie zdarzeń: ElmahExtension.ErrorLog.Filtering += new ExceptionFilterEventHandler(ErrorLog_Filtering);

Kod:

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

Ponadto trzeba dodać odwołanie do System.Web.dll w projekcie dla tej pracy.

EDIT: Zgodnie z komentarzami, ten kod będzie wysyłać wiadomości e-mail tylko, jeśli plik konfiguracyjny ma <errorMail async="false"/>. Zapoznaj się z this code snippet, jeśli chcesz zachować <errorMail async="true"/> w swoim pliku konfiguracyjnym (do użycia, gdy dostępny jest HttpContext.Current).

+0

Awesome post. To działało idealnie dla mnie. Po prostu musiałem umieścić normalne rzeczy z web.config w moim app.config i płynne żeglowanie! –

+6

To nie działało dla mnie podczas testu jednostkowego, dopóki nie ustawię wartości . Poprzednio ustawiłem asynchronię na wartość true. –

+0

Dzięki za post - pracował świetnie! Podłączyliśmy wiele zdarzeń, w tym ErrorLog_Filtering, ErrorLog_Logged, ErrorMail_Filtering, ErrorMail_Mailing, ErrorMail_Mailed, ErrorMail_DisposingMail przy użyciu odpowiednich klas (ExceptionFilterEventHandler, ErrorLoggedEventHandler, itp.) – Zugwalt

9

Jeśli chcesz po prostu napisz do dziennika bez http można zrobić tak:

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 

A jeśli chodzi o 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> 

I

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

I ustawienia smtp do wyboru.

Wszystko gotowe. :-)

+1

Rozwiązuje problem! po wypróbowaniu eeeeverything to działało najpierw spróbować! –

2

Dla tych, którzy potrzebują odpowiedź Brian Chance'a przeniesione do 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 

Jednak za jedyne zalogowaniu błędy w bazie danych, to będzie wystarczające:

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 

Jak kompletne rozwiązanie:

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 

I

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

będzie działać, jeśli to się nazywa po Initialize()

1

cóż, skoro nie mogę komentować tego będę tu pisać, a może ktoś będzie go zobaczyć.

Po zastosowaniu metody Briana i komentatorów udało mi się uzyskać pocztę e-mail, ale nadal nie widziałem komunikatów SQL, które były rejestrowane, mimo że ustawiłem nazwę aplikacji. Nie zdawałem sobie sprawy z tego, że faktycznie były one rejestrowane. Po prostu ich nie widziałem, ponieważ applicationName musi być taki sam jak plik web.config, aby móc go wyświetlić.

Mój web.config nie miał podanego applicationName, więc domyślnie było to "/ LM/W3SVC/2/ROOT", co jest w zasadzie tym, co "asgeo1" skomentował, chociaż nie zdawałem sobie sprawy, że musi to być to samo.

Ponieważ nie miałem żadnych błędów, które mnie interesowały, skonfigurowałem applicationName w moim pliku web.config i my app.config, aby były takie same i teraz wszystko pokazuje się jak mistrz.

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="MyAppName" /> 
Powiązane problemy