Events with Return Values

I was working with a team on an interface project that allowed for the transferring of records between N different systems. Once the record was transferred, updates can flow in both directions. I suggested that we use events to begin transactions from source systems, and the event arguments would contain the necessary routing information to help get the data to the correct destination.

Great plan, but we ran into a problem because one of the systems involved uses asynchronous operations for its transactions and another uses synchronous operations. No problem, though. We can get around this with the creative use of callbacks and wait handles.

Let’s look at an example. In the code below, the application calls a method that raises an event. The method needs to return a response, and the event handler produces a response, but there is no way to return the response from the event handler to the method.

class Program
{
    static event EventHandler<SampleEventArgs> Sample;

    static void Main(string[] args)
    {
        Sample += SampleEventHandler;
        var response = RaiseAnEvent();
        Console.WriteLine("Response: {0}", response);
        Console.ReadLine();
    }

    static string RaiseAnEvent()
    {
        if (Sample != null)
        {
            var args = new SampleEventArgs();
            Sample(null, args);
        }
        return null; // need the response!
    }

    static void SampleEventHandler(object sender, SampleEventArgs e)
    {
        string response = "foo";
    }
}

public class SampleEventArgs : EventArgs
{
}

When program runs, the following output is produced:

Response: 

The first problem we need to deal with is that the event handler needs a way to provide its response to the calling code. This could be accomplished by adding a response property to the event argument OR by adding a callback to the event argument. I prefer the latter because the former will require me to know when it is safe to retrieve the value from the event argument whereas the callback is more like a “push.” So, let’s add a callback!

public class SampleEventArgs : EventArgs
{
    public Action<string> SampleCompleted { get; set; }
}

Now that we have the ability to specify a callback to capture the response, guess what the next step is. That’s, right: create the callback method! This is also our opportunity to block execution while we wait for a response. I’ll use a ManualResetEvent to block execution, and I’ll set it in the callback. Perfect, and lambdas make the whole thing a breeze!

static string RaiseAnEvent()
{
    string response = null;
    if (Sample != null)
    {
        var args = new SampleEventArgs();
        var manualResetEvent = new ManualResetEvent(false);
        args.SampleCompleted = r =>
            {
                response = r;
                manualResetEvent.Set();
            };
        Sample(null, args);

        if (!manualResetEvent.WaitOne(1000))
        {
            // timeout waiting for response
        }
    }
    return response;
}

Now that we’ve got our callback created and defined, we just need the event handler to invoke it.

static void SampleEventHandler(object sender, SampleEventArgs e)
{
    string response = "foo";
    if (e.SampleCompleted != null)
    {
        e.SampleCompleted(response);
    }
}

And with that, we’re done! We run the application, and we get the expected output.

Response: foo

Complete sample:

namespace EventsWithReturnValues
{
    using System;
    using System.Threading;

    class Program
    {
        static event EventHandler<SampleEventArgs> Sample;

        static void Main(string[] args)
        {
            Sample += SampleEventHandler;
            var response = RaiseAnEvent();
            Console.WriteLine("Response: {0}", response);
            Console.ReadLine();
        }

        static string RaiseAnEvent()
        {
            string response = null;
            if (Sample != null)
            {
                var args = new SampleEventArgs();
                var manualResetEvent = new ManualResetEvent(false);
                args.SampleCompleted = r =>
                    {
                        response = r;
                        manualResetEvent.Set();
                    };
                Sample(null, args);

                if (!manualResetEvent.WaitOne(1000))
                {
                    // timeout waiting for response
                }
            }
            return response;
        }

        static void SampleEventHandler(object sender, SampleEventArgs e)
        {
            string response = "foo";
            if (e.SampleCompleted != null)
            {
                e.SampleCompleted(response);
            }
        }
    }

    public class SampleEventArgs : EventArgs
    {
        public Action<string> SampleCompleted { get; set; }
    }
}

.NET Rocks! Road Trip

.NET Rocks! is a popular internet talk show, and they’re taking the show on the road. Carl Franklin and Richard Campbell are traversing the country on their .NET Rocks! Visual Studio 2012 Launch Road Trip, making stops in over 37 different cities. I was able to attend their Detroit session in Southfield, MI yesterday. The event was hosted by the Great Lakes Area .NET User Group (with yummy BBQ provided by sponsor New World Systems), and it was a good time!

Carl gave a good talk and demo on creating modern, Windows Store app-style (formerly “metro-style”) apps. In the demo, a slick app was built to display and listen to .NET Rocks! shows using a simple web service. The code was minimal, but the app looked great thanks to the built-in styles–it was impressive to see how little code it takes to make a great looking Windows Store app.

Richard then took over and gave a talk about DevOps. DevOps blurs the line between IT professionals and developers, allowing them to coordinate efforts to evolve and improve applications over time. A big focus of this talk was on Microsoft System Center, Microsoft’s enterprise resource monitoring tool. System Center allows you to collect logs and events from different resources across the network and puts them into a consolidated view. New to System Center is the ability to hook into .NET apps, allowing you to specify and create events for things like methods that take too long. System Center can tie into TFS, so when an application event occurs, a work item can be created.

Third to take the stage was Microsoft’s Jeff Wilcox, independent creator of the popular Foursquare client 4th & Mayor. Jeff talked to us his experience with Microsoft, but most of the discussion was about 4th & Mayor. I’m not a Foursquare user, but I can appreciate what Jeff has done in creating this beautiful app with a focus on providing a great user experience. Jeff’s brief presentation was followed by a live taping of The Tablet Show, another offering from Franklin and Campbell.

It was a fun event. The food was great, it was entertaining, and I learned a few new things. Thanks to GANG for hosting and to .NET Rocks! for stopping by Detroit!