views:

248

answers:

2

I'm reading up on event-driven design. I am having trouble getting my head around some of it in practice. I'm considering using this for a windows service that monitors, parses, and handles information coming from a 3rd party TCP stream. Is the following a decent approach, or am I missing something?

My plan is to have a the main service be simply a container for events:

public class MyService
{                      

    public void RegisterAgent(ServiceAgent agent)
    {
        Log("Initializing agent " + agent);
        agent.Initialize(this);
        Log("Done intializing agent " + agent);
    }

    public void Log(string messageText)
    {
        OnSimpleLogEventLogged(this, new SimpleLogEventArgs(messageText));
    }

    protected void Raise<T>(EventHandler<T> eventHandler, object sender, T args) where T : EventArgs
    {
        var handler = eventHandler;
        if (handler == null) return;                       
        handler(sender, args);

    }

    public event EventHandler<SimpleLogEventArgs> SimpleLogEventLogged;
    protected void OnSimpleLogEventLogged(object sender, SimpleLogEventArgs args)
    {
        Raise(SimpleLogEventLogged, sender, args);
    }

    public event EventHandler<TextRecievedEventArgs > TextRecieved;
    public void OnTextRecieved(object sender, TextRecievedEventArgs args)
    {
        Raise(TextRecieved, sender, args);            
    }

    public event EventHandler<TextParsedEventArgs> TextParsed;
    public void OnTextParsed(object sender, TextParsedEventArgs args)
    {
        Raise(TextParsed, sender, args);            
    }

    ...
}

Then, using MEF or similar, I'll register "ServiceAgent" instances, which simply handle and/or raise events, optionally doing so on a background thread. For example:

public class TextParsingAgent : ServiceAgent
{

    public override void Initialize(MyService service)
    {
        service.TextRecieved += TextRecieved;
        base.Initialize(service);
    }

    void TextRecieved(object sender, TextRecievedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(TextRecievedAsync, e);
    }

    private void TextRecieved(object state)
    {
        var e = (TextRecievedEventArgs)state;
        //TODO:Parse text into something meaningful and store in textParseEventArgs
        service.OnTextParsed(textParseEventArgs);
    }
}
+1  A: 

I personally think that it is a fairly good overall structue to your code, it easily separates logical units into their own operations, and by notifying out of the service it allows you good expandability in the future if you need to setup different serviceagents later.

Mitchel Sellers
+1  A: 

If the Raise() method is there only to simplify the null checking, you might want to initialize event handlers to non-null instead using a lambda expression, like so:

public event EventHandler<TextParsedEventArgs> TextParsed = (sender, e) => { };

Then you could call TextParsed(...) without the null check, which might make the code easier to follow.

bzlm