views:

86

answers:

2

I have a console application (VB.NET). When it is started, it spawns worker threads to find work in the database and do the task, then look for the next task (A workflow basically).

The problem that I have is that I have my Event Handler in the main thread that spawns the worker threads. Those workers, if they error, raise an event to a public delegate. However my main thread is not detecting these events, and I cannot figure out how to make it. My intention is to do all logging (text/database), email alerts, and restarting the worker to find another task that is not errored. (This will be expanded in the LogErrorMessage routine and such, for now I am just keeping it a simple Console.Writeline so that I can see if the method is being fired or not)

Can this be done? And if so... what am I missing?

Here is the code around what I am trying to do:

Logger Class:

Public Delegate Sub LogDelegateError(ByVal Ex As Exception)

Public Class EventLogger
    Public Event EventError As LogDelegateError

    Public Sub New()
    End Sub

    Public Sub LogError(ByVal ex As Exception)
        RaiseEvent EventError(ex)
    End Sub
End Class

Main Thread:

Private WithEvents _ErrorLogger As EventLogger

Public Sub Process()
     _ErrorLogger = New EventLogger
     AddHandler _ErrorLogger.EventError, New LogDelegateError(AddressOf LogErrorMessage)

     [Loop]
     Dim tWorker As Thread = New Thread(AddressOf oWorker.MainProcess)
     tWorker.Priority = WorkerNode.Attributes(SETTING_NAME_PRIORITY).Value
     tWorker.Start()
     [End Loop]

     [In Finally]
     RemoveHandler _ErrorLogger.EventError, New LogDelegateError(AddressOf LogErrorMessage)
End Sub

Private Sub LogErrorMessage(ByVal ex As Exception) Handles _ErrorLogger.EventError
     Console.WriteLine()
     Console.WriteLine("INTERNAL ERROR:")
     Console.WriteLine(ex.ToString())
     Console.WriteLine()
End Sub

WorkerBase:

Private _Log As New EventLogger
Public Sub MainProcess()
     Try
           [SOME WORK]
     Catch ex As Exception
           Me._Log.LogError(ex)
     End Try
End Sub

I am currently getting no errors that something is wrong, nor is the application hitting the expected handler in the main thread.

+1  A: 

I use a static event do accomplish what you want.

Code example in C#, Sorry. Just remember to remove the event if you are done using a object (Main in the example below) otherwise it'll cause a memory leak and it'll never get garbage collected.

public class WorkerClass
{
    public static event ProgressInfoEventHandler ProgressInfo;

    private static void OnProgressInfo(string message)
    {
        if (ProgressInfo != null)
            ProgressInfo(new ProgressInfoEventArgs(message));
    }

    private void DoWork()
    {
          OnProgressInfo("Doing some work");
    }

}

Main or Logging thread/class:

public class Main
{
   public Main()
   {
        WorkerClass.ProgressInfo += 
             new ProgressInfoEventHandler(WorkerClass_ProgressInfo);
   }

    void WorkerClass_ProgressInfo(ProgressInfoEventArgs e)
    {
        //LogMessage(e.Message);
    }


}
Chris Persichetti
C# is fine, I prefer it, employer chose VB for some reason. Let me give this a try!
IPX Ares
The event will be raised and handled, although it won't be handled in the main thread but in the thread that raised it.
Yann Schwartz
@Yann, that is perfectly fine.@Chris, that worked! Thank you.
IPX Ares
A: 

In WorkerBase: Private _Log As **New** EventLogger

You need to pass a reference of _ErrorLogger to the WorkerBase instance or pass the address of the handler. Since you are automatically creating a new instance of EventLogger in the WorkerBase, the new _Log instance does not have the event handler hooked up. Just be aware that there could be multi-threading issues in the handler that you would have to handle.

Ryan
Again, my omission. The constructor passes in the logger and sets the private object to that instance.
IPX Ares