Showing posts with label Threading. Show all posts
Showing posts with label Threading. Show all posts

Sunday, December 21, 2008

Understanding SyncrhronizationContext

SynchronizationContext - MSDN Lets You Down

I don't know why, but there is really not much information about this new class within the .NET Framework. The MSDN documentation contains very little information on how to use SynchronizationContext. Initially, I must say that I had a hard time understanding the reason for this new class and how to use it. After reading a lot on the subject, I finally understood the purpose of this class and how it should be used. I decided to write this article to help other developers understand how to use this class, and what it can and cannot do for you. (MSDN)

Using SynchronizationContext to Marshal Code from One Thread to Another

Let's get some technical points out of the way so we can show how to use this class. A SynchronizationContext allows a thread to communicate with another thread. Suppose you have two threads, Thread1 and Thread2. Say, Thread1 is doing some work, and then Thread1 wishes to execute code on Thread2. One possible way to do it is to ask Thread2 for its SynchronizationContext object, give it to Thread1, and then Thread1 can call SynchronizationContext.Send to execute the code on Thread2. Sounds like magic... Well, there is a something you should know. Not every thread has a SynchronizationContext attached to it. One thread that always has a SynchronizationContext is the UI thread.

Who puts the SynchronizationContext into the UI thread? Any guesses? Give up? OK, here it is, the first control that is created on the thread places the SynchronizationContext into that thread. Normally, it is the first form that gets created. How do I know? Well, I tried it out.

Because my code uses SynchronizationContext.Current, let me explain what this static property gives us. SynchronizationContext.Current allows us to get a SynchronizationContext that is attached to the current thread. Let's be clear here, SynchronizationContext.Current is not a singleton per AppDomain, but per thread. This means that two threads can have different instances of SynchronizationContext when calling SynchronizationContext.Current. If you wonder where the actual context is stored, it is stored within the Thread data store (and as I said before, not in the global memory space of the appdomain).

OK, let's look at the code that places a SynchronizationContext within our UI thread:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    // let's check the context here
    var context = SynchronizationContext.Current;
    if (context == null)
        MessageBox.Show("No context for this thread");
    else
        MessageBox.Show("We got a context");

    // create a form
    Form1 form = new Form1();

    // let's check it again after creating a form
    context = SynchronizationContext.Current;

    if (context == null)
        MessageBox.Show("No context for this thread");
    else
        MessageBox.Show("We got a context");

    if (context == null)
        MessageBox.Show("No context for this thread");

    Application.Run(new Form1());
}

As you can see, there are a few points to note:

  • The first message box will indicate that there is no context attached to the thread. That's because .NET doesn't even know what is going to happen on this thread, and there is no runtime class that initializes the Sync Context for this thread.
  • Right after creating the form, notice that the context is set. The Form class is responsible for this. It checks if a Sync Context is present, and if it is not, it places it there. Remember that the context is always the same on the same thread, so any UI control can access it. This is because all UI operations must be running on the UI thread. To be more specific, the thread that creates the window is the thread that can communicate with the window. In our case, it is the main thread of the application.

How Do I Use It?

Now that the UI thread is nice enough to give us a Sync Context so we can "run code" under the UI thread, how do we use it?

First, do we really have to marshal code into the UI thread? Yes. If you are running on a thread other than the UI thread, you cannot update the UI. Want to be a hero and try it? You will get an exception (in version 1.0, they didn't enforce the exception, it just crashed the application, but in version 2.0, there is a fat ugly exception that pops in your face).

To be fair, I will say that you don't have to use this class to sync into the UI thread. You can use the InvokeRequired property (which is on every UI control class) and see if you need to marshal your code. If you get a "true" out of InvokeRequired, then you have to use Control.Invoke to marshal the code to the UI thread. Great! Why keep reading? Well, there is an issue with this technique. You must have a Control in order to call Invoke on it. It doesn't matter which UI control, but you need at least one control reference available to you within your non-UI thread in order to do this type of thread marshalling. From a design prospective, you never want to have a UI reference within your BI layer. So, you can leave all sync operations on the UI class, and make sure the UI is responsible to marshal its own work (see my article on the MVP pattern). However, this puts more responsibility on the UI, and makes the UI smarter than we want it to be, I must say. It would be nice for the BI to have the ability to marshal code to the UI thread without having a reference to a control or a form.

So, how is it done?

Simple. Create a thread, send it the sync context, and have this thread use the sync object to marshal code into the UI thread. Let's see an example.

In the following example, I have a list box that is populated from a worker thread. The thread simulates a computation and then writes to the UI list box. The thread used to update the UI is launched from the mToolStripButtonThreads_Click event handler.

First, let's see what's on the form:

    private void InitializeComponent()
    {
        System.ComponentModel.ComponentResourceManager resources =
          new System.ComponentModel.ComponentResourceManager(typeof(Form1));
        this.mListBox = new System.Windows.Forms.ListBox();
        this.toolStrip1 = new System.Windows.Forms.ToolStrip();
        this.mToolStripButtonThreads = new System.Windows.Forms.ToolStripButton();
        this.toolStrip1.SuspendLayout();
        this.SuspendLayout();
        //
        // mListBox
        //
        this.mListBox.Dock = System.Windows.Forms.DockStyle.Fill;
        this.mListBox.FormattingEnabled = true;
        this.mListBox.Location = new System.Drawing.Point(0, 0);
        this.mListBox.Name = "mListBox";
        this.mListBox.Size = new System.Drawing.Size(284, 264);
        this.mListBox.TabIndex = 0;
        //
        // toolStrip1
        //
        this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
        this.mToolStripButtonThreads});
        this.toolStrip1.Location = new System.Drawing.Point(0, 0);
        this.toolStrip1.Name = "toolStrip1";
        this.toolStrip1.Size = new System.Drawing.Size(284, 25);
        this.toolStrip1.TabIndex = 1;
        this.toolStrip1.Text = "toolStrip1";
        //
        // mToolStripButtonThreads
        //
        this.mToolStripButtonThreads.DisplayStyle =
          System.Windows.Forms.ToolStripItemDisplayStyle.Text;
        this.mToolStripButtonThreads.Image = ((System.Drawing.Image)
            (resources.GetObject("mToolStripButtonThreads.Image")));
        this.mToolStripButtonThreads.ImageTransparentColor =
             System.Drawing.Color.Magenta;
        this.mToolStripButtonThreads.Name = "mToolStripButtonThreads";
        this.mToolStripButtonThreads.Size = new System.Drawing.Size(148, 22);
        this.mToolStripButtonThreads.Text = "Press Here to start threads";
        this.mToolStripButtonThreads.Click +=
          new System.EventHandler(this.mToolStripButtonThreads_Click);
        //
        // Form1
        //
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(284, 264);
        this.Controls.Add(this.toolStrip1);
        this.Controls.Add(this.mListBox);
        this.Name = "Form1";
        this.Text = "Form1";
        this.toolStrip1.ResumeLayout(false);
        this.toolStrip1.PerformLayout();
        this.ResumeLayout(false);
        this.PerformLayout();
    }

    #endregion

    private System.Windows.Forms.ListBox mListBox;
    private System.Windows.Forms.ToolStrip toolStrip1;
    private System.Windows.Forms.ToolStripButton mToolStripButtonThreads;
}

Now, let's see the example:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void mToolStripButtonThreads_Click(object sender, EventArgs e)
    {
        // let's see the thread id
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id);

        // grab the sync context associated to this
        // thread (the UI thread), and save it in uiContext
        // note that this context is set by the UI thread
        // during Form creation (outside of your control)
        // also note, that not every thread has a sync context attached to it.
        SynchronizationContext uiContext = SynchronizationContext.Current;

        // create a thread and associate it to the run method
        Thread thread = new Thread(Run);

        // start the thread, and pass it the UI context,
        // so this thread will be able to update the UI
        // from within the thread
        thread.Start(uiContext);
    }

    private void Run(object state)
    {
        // lets see the thread id
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("Run thread: " + id);

        // grab the context from the state
        SynchronizationContext uiContext = state as SynchronizationContext;

        for (int i = 0; i < 1000; i++)
        {
            // normally you would do some code here
            // to grab items from the database. or some long
            // computation
            Thread.Sleep(10);

            // use the ui context to execute the UpdateUI method,
            // this insure that the UpdateUI method will run on the UI thread.

            uiContext.Post(UpdateUI, "line " + i.ToString());
        }
    }

    /// <summary>
    /// This method is executed on the main UI thread.
    /// </summary>
    private void UpdateUI(object state)
    {
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("UpdateUI thread:" + id);
        string text = state as string;
        mListBox.Items.Add(text);
    }
}

Let's go over this code. Notice that I log the thread ID of each method so we can review it later.

For example:

// let's see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id);

When pressing on the toolstrip button, a thread is launched with its delegate pointing to the Run method. However, notice that I am passing state to this thread. I am passing the Sync Context of the UI thread by calling:

SynchronizationContext uiContext = SynchronizationContext.Current;

Because I am running on the event handler thread of the toolstrip button, I know I am currently running on the UI thread, and by calling SynchronizationContext.Current, I will get the sync context for the UI thread.

Run will first grab the SynchronizationContext from its state, so it can have the knowledge of how to marshal code into the UI thread.

// grab the context from the state
SynchronizationContext uiContext = state as SynchronizationContext;

The Run thread writes 1000 lines into the list box. How? Well, first it uses the Send method on the SynchronizationContext:

public virtual void Send(SendOrPostCallback d, object state);

Calling SynchronizationContext.Send takes two arguments, a delegate pointing to a method and a state object. Within our example...

uiContext.Send(UpdateUI, "line " + i.ToString());

... UpdateUI is the value we provide for the delegate, and state contains the string we want to add to the listbox. The code in UpdateUI is supposed to run on the UI thread, and not on the calling thread.

private void UpdateUI(object state)
{
    int id = Thread.CurrentThread.ManagedThreadId;
    Trace.WriteLine("UpdateUI thread:" + id);
    string text = state as string;
    mListBox.Items.Add(text);
}

Notice that this code directly runs on the UI thread. There is no checking for InvokerRequired because I know it is on the UI thread due to the fact that it was used with the Send method of the UI SynchronizationContext.

Let's look at the thread IDs and see if it makes sense:

mToolStripButtonThreads_Click thread: 10
Run thread: 3
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
... (x1000 times)

This means that the UI thread is 10, the worker thread (Run) is 3, and when we update the UI, notice we are on thread ID 10 again (the UI thread). So, everything is working as advertised.

Error Handling

Very nice, we are able to marshal code into the UI thread, but what happens when the code we marshal throws an exception? Who is responsible to catch it? The UI thread or the worker thread?

private void Run(object state)
{
    // let's see the thread id
    int id = Thread.CurrentThread.ManagedThreadId;
    Trace.WriteLine("Run thread: " + id);

    // grab the context from the state
    SynchronizationContext uiContext = state as SynchronizationContext;

    for (int i = 0; i < 1000; i++)
    {
        Trace.WriteLine("Loop " + i.ToString());
        // normally you would do some code here
        // to grab items from the database. or some long
        // computation
        Thread.Sleep(10);

        // use the ui context to execute the UpdateUI method, this insure that the
        // UpdateUI method will run on the UI thread.

        try
        {
            uiContext.Send(UpdateUI, "line " + i.ToString());
        }
        catch (Exception e)
        {
            Trace.WriteLine(e.Message);
        }
    }
}

/// <summary>
/// This method is executed on the main UI thread.
/// </summary>
private void UpdateUI(object state)
{
    throw new Exception("Boom");
}

I modified the code so that the UpdateUI method throws an exception:

throw new Exception("Boom");

Also, I have modified the Run method to place a try/catch around the Send method.

try
{
    uiContext.Send(UpdateUI, "line " + i.ToString());
}
catch (Exception e)
{
    Trace.WriteLine(e.Message);
}

When running this code, I noticed that the exception is caught in the Run thread and not on the UI thread. This is interesting because you might expect the exception to bring down the UI thread, considering no class is catching the exception on the UI thread.

Therefore, the Send method is doing a little magic; it is executing our code in a blocking fashion, and it reports back any exception during its execution.

Send vs. Post

Using Send is only one of two possible methods you can use to marshal code on the UI thread. There is another method called Post. What's the difference? A lot!

Maybe it is time to see this class in more detail, so let's review the interface of SynchronizationContext:

// Summary:
//     Provides the basic functionality for propagating a synchronization context
//     in various synchronization models.
public class SynchronizationContext
{
    // Summary:
    //     Creates a new instance of the System.Threading.SynchronizationContext class.
    public SynchronizationContext();

    // Summary:
    //     Gets the synchronization context for the current thread.
    //
    // Returns:
    //     A System.Threading.SynchronizationContext object representing the current
    //     synchronization context.
    public static SynchronizationContext Current { get; }

    // Summary:
    //     When overridden in a derived class, creates a copy of the synchronization
    //     context.
    //
    // Returns:
    //     A new System.Threading.SynchronizationContext object.
    public virtual SynchronizationContext CreateCopy();
    //
    // Summary:
    //     Determines if wait notification is required.
    //
    // Returns:
    //     true if wait notification is required; otherwise, false.
    public bool IsWaitNotificationRequired();
    //
    // Summary:
    //     When overridden in a derived class, responds to the notification that an
    //     operation has completed.
    public virtual void OperationCompleted();
    //
    // Summary:
    //     When overridden in a derived class, responds to the notification that an
    //     operation has started.
    public virtual void OperationStarted();
    //
    // Summary:
    //     When overridden in a derived class, dispatches an asynchronous message to
    //     a synchronization context.
    //
    // Parameters:
    //   d:
    //     The System.Threading.SendOrPostCallback delegate to call.
    //
    //   state:
    //     The object passed to the delegate.
    public virtual void Post(SendOrPostCallback d, object state);
    //
    // Summary:
    //     When overridden in a derived class, dispatches a synchronous message to a
    //     synchronization context.
    //
    // Parameters:
    //   d:
    //     The System.Threading.SendOrPostCallback delegate to call.
    //
    //   state:
    //     The object passed to the delegate.
    public virtual void Send(SendOrPostCallback d, object state);
    //
    // Summary:
    //     Sets the current synchronization context.
    //
    // Parameters:
    //   syncContext:
    //     The System.Threading.SynchronizationContext object to be set.
    public static void SetSynchronizationContext(SynchronizationContext syncContext);
    //
    // Summary:
    //     Sets notification that wait notification is required and prepares the callback
    //     method so it can be called more reliably when a wait occurs.
    protected void SetWaitNotificationRequired();
    //
    // Summary:
    //     Waits for any or all the elements in the specified array to receive a signal.
    //
    // Parameters:
    //   waitHandles:
    //     An array of type System.IntPtr that contains the native operating system
    //     handles.
    //
    //   waitAll:
    //     true to wait for all handles; false to wait for any handle.
    //
    //   millisecondsTimeout:
    //     The number of milliseconds to wait, or System.Threading.Timeout.Infinite
    //     (-1) to wait indefinitely.
    //
    // Returns:
    //     The array index of the object that satisfied the wait.
    [PrePrepareMethod]
    [CLSCompliant(false)]
    public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
    //
    // Summary:
    //     Helper function that waits for any or all the elements in the specified array
    //     to receive a signal.
    //
    // Parameters:
    //   waitHandles:
    //     An array of type System.IntPtr that contains the native operating system
    //     handles.
    //
    //   waitAll:
    //     true to wait for all handles; false to wait for any handle.
    //
    //   millisecondsTimeout:
    //     The number of milliseconds to wait, or System.Threading.Timeout.Infinite
    //     (-1) to wait indefinitely.
    //
    // Returns:
    //     The array index of the object that satisfied the wait.
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    [PrePrepareMethod]
    [CLSCompliant(false)]
    protected static int WaitHelper(IntPtr[] waitHandles,
                     bool waitAll, int millisecondsTimeout);
}

Notice the comment for the Post method:

//
// Summary:
//     When overridden in a derived class, dispatches an asynchronous message to
//     a synchronization context.
//
// Parameters:
//   d:
//     The System.Threading.SendOrPostCallback delegate to call.
//
//   state:
//     The object passed to the delegate.
public virtual void Post(SendOrPostCallback d, object state);

The key word here is asynchronous. This means that Post will not wait for the execution of the delegate to complete. Post will "Fire and Forget" about the execution code within the delegate. It also means that you cannot catch exceptions as we did with the Send method. Suppose an exception is thrown, it will be the UI thread that will get it; unhanding the exception will terminate the UI thread.

However, Post or Send, the execution of the delegate always runs on the correct thread. Just replace the code with Post instead of Send, and you will still get the right thread ID when executing on the UI thread.

So Now, I Can Use SynchronizationContext to Sync Any Thread I Want, Right? Nope!

At this point, you might try to use SynchronizationContext with any thread. However, you will soon find that your thread does not have a SynchronizationContext when using SynchronizationContext.Current, and it always returns null. No big deal you say, and you simply create a SynchronizationContext if there isn't one. Simple. But, it does not really work.

Let's look at a program similar to the one we used for the UI thread:

class Program
{
    private static SynchronizationContext mT1 = null;

    static void Main(string[] args)
    {
        // log the thread id
        int id = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Main thread is " + id);

        // create a sync context for this thread
        var context = new SynchronizationContext();
        // set this context for this thread.
        SynchronizationContext.SetSynchronizationContext(context);

        // create a thread, and pass it the main sync context.
        Thread t1 = new Thread(new ParameterizedThreadStart(Run1));
        t1.Start(SynchronizationContext.Current);
        Console.ReadLine();
    }

    static private void Run1(object state)
    {
        int id = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Run1 Thread ID: " + id);

        // grab  the sync context that main has set
        var context = state as SynchronizationContext;

        // call the sync context of main, expecting
        // the following code to run on the main thread
        // but it will not.
        context.Send(DoWork, null);

        while (true)
            Thread.Sleep(10000000);
    }

    static void DoWork(object state)
    {
        int id = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("DoWork Thread ID:" + id);
    }
}

This simple console application is something you should not do at home. This program does not work, and it is done simply to prove a point. Notice I am setting a Sync Context on the main console thread. I am simply creating a new instance of the object. Then, I am setting it to my current thread. This is similar to what the UI thread does when a form is created (not really, but I will explain later). Then, I create a thread Run1, and pass it the context of the main thread. When I try to call Send, based on my trace, I notice Send was called on the Run1 thread and not on the main thread as we may expect. Here is the output:

Main thread is 10
Run1 Thread ID: 11
DoWork Thread ID:11

Notice that DoWork is executed on thread 11, the same thread as Run1. Not much of a SynchronizationContext into the main thread. Why? What's going on? Well... This is the part when you realize that nothing is for free in life. Threads can't just switch contexts between them, they must have an infrastructure built-in into them in order to do so. The UI thread, for example, uses a message pump, and within its SynchronizationContext, it leverages the message pump to sync into the UI thread.

So, the UI thread has it own SynchronizationContext class, but it is a class that derives from SynchronizationContext, and it is called System.Windows.Forms.WindowsFormsSynchronizationContext. Now, this class has a very different implementation from the simple plain vanilla SynchronizationContext. The UI version overrides the Post and Send methods, and provides a "message pump" version of these methods (I tried to get the source code of this class, but I didn't find it). So, what does the plain vanilla SynchronizationContext do?

Somehow, I was able to get the source code of SynchronizationContext, and here it is: found it here.

(I have removed the attributes, and did some minor formatting just to have the code fit in the page.)

namespace System.Threading
{
    using Microsoft.Win32.SafeHandles;
    using System.Security.Permissions;
    using System.Runtime.InteropServices;
    using System.Runtime.CompilerServices;
    using System.Runtime.ConstrainedExecution;
    using System.Reflection;

    internal struct SynchronizationContextSwitcher : IDisposable
    {
        internal SynchronizationContext savedSC;
        internal SynchronizationContext currSC;
        internal ExecutionContext _ec;

        public override bool Equals(Object obj)
        {
            if (obj == null || !(obj is SynchronizationContextSwitcher))
                return false;
            SynchronizationContextSwitcher sw = (SynchronizationContextSwitcher)obj;
            return (this.savedSC == sw.savedSC &&
                    this.currSC == sw.currSC && this._ec == sw._ec);
        }

        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        public static bool operator ==(SynchronizationContextSwitcher c1,
                                       SynchronizationContextSwitcher c2)
        {
            return c1.Equals(c2);
        }

        public static bool operator !=(SynchronizationContextSwitcher c1,
                                       SynchronizationContextSwitcher c2)
        {
            return !c1.Equals(c2);
        }

        void IDisposable.Dispose()
        {
            Undo();
        }

        internal bool UndoNoThrow()
        {
            if (_ec  == null)
            {
                return true;
            }

            try
            {
                Undo();
            }
            catch
            {
                return false;
            }
            return true;
        }

        public void Undo()
        {
            if (_ec  == null)
            {
                return;
            }

            ExecutionContext  executionContext =
              Thread.CurrentThread.GetExecutionContextNoCreate();
            if (_ec != executionContext)
            {
                throw new InvalidOperationException(Environment.GetResourceString(
                          "InvalidOperation_SwitcherCtxMismatch"));
            }
            if (currSC != _ec.SynchronizationContext)
            {
                throw new InvalidOperationException(Environment.GetResourceString(
                          "InvalidOperation_SwitcherCtxMismatch"));
            }
            BCLDebug.Assert(executionContext != null, " ExecutionContext can't be null");
            // restore the Saved Sync context as current
            executionContext.SynchronizationContext = savedSC;
            // can't reuse this anymore
            _ec = null;
        }
    }

    public delegate void SendOrPostCallback(Object state);

    [Flags]
    enum SynchronizationContextProperties
    {
        None = 0,
        RequireWaitNotification = 0x1
    };

    public class SynchronizationContext
    {
        SynchronizationContextProperties _props = SynchronizationContextProperties.None;

        public SynchronizationContext()
        {
        }

        // protected so that only the derived sync
        // context class can enable these flags
        protected void SetWaitNotificationRequired()
        {
            // Prepare the method so that it can be called
            // in a reliable fashion when a wait is needed.
            // This will obviously only make the Wait reliable
            // if the Wait method is itself reliable. The only thing
            // preparing the method here does is to ensure there
            // is no failure point before the method execution begins.

            RuntimeHelpers.PrepareDelegate(new WaitDelegate(this.Wait));
            _props |= SynchronizationContextProperties.RequireWaitNotification;
        }

        public bool IsWaitNotificationRequired()
        {
            return ((_props &
              SynchronizationContextProperties.RequireWaitNotification) != 0);
        }

        public virtual void Send(SendOrPostCallback d, Object state)
        {
            d(state);
        }

        public virtual void Post(SendOrPostCallback d, Object state)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
        }

        public virtual void OperationStarted()
        {
        }

        public virtual void OperationCompleted()
        {
        }

        // Method called when the CLR does a wait operation
        public virtual int Wait(IntPtr[] waitHandles,
                       bool waitAll, int millisecondsTimeout)
        {
            return WaitHelper(waitHandles, waitAll, millisecondsTimeout);
        }

        // Static helper to which the above method
        // can delegate to in order to get the default
        // COM behavior.
        protected static extern int WaitHelper(IntPtr[] waitHandles,
                         bool waitAll, int millisecondsTimeout);

        // set SynchronizationContext on the current thread
        public static void SetSynchronizationContext(SynchronizationContext syncContext)
        {
            SetSynchronizationContext(syncContext,
              Thread.CurrentThread.ExecutionContext.SynchronizationContext);
        }

        internal static SynchronizationContextSwitcher
          SetSynchronizationContext(SynchronizationContext syncContext,
          SynchronizationContext prevSyncContext)
        {
            // get current execution context
            ExecutionContext ec = Thread.CurrentThread.ExecutionContext;
            // create a switcher
            SynchronizationContextSwitcher scsw = new SynchronizationContextSwitcher();

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                // attach the switcher to the exec context
                scsw._ec = ec;
                // save the current sync context using the passed in value
                scsw.savedSC = prevSyncContext;
                // save the new sync context also
                scsw.currSC = syncContext;
                // update the current sync context to the new context
                ec.SynchronizationContext = syncContext;
            }
            catch
            {
                // Any exception means we just restore the old SyncCtx
                scsw.UndoNoThrow(); //No exception will be thrown in this Undo()
                throw;
            }
            // return switcher
            return scsw;
        }

        // Get the current SynchronizationContext on the current thread
        public static SynchronizationContext Current
        {
            get
            {
                ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate();
                if (ec != null)
                    return ec.SynchronizationContext;
                return null;
            }
        }

        // helper to Clone this SynchronizationContext,
        public virtual SynchronizationContext CreateCopy()
        {
            // the CLR dummy has an empty clone function - no member data
            return new SynchronizationContext();
        }

        private static int InvokeWaitMethodHelper(SynchronizationContext syncContext,
            IntPtr[] waitHandles,
            bool waitAll,
            int millisecondsTimeout)
        {
            return syncContext.Wait(waitHandles, waitAll, millisecondsTimeout);
        }
    }
}

Look at the implementation of Send and Post...

public virtual void Send(SendOrPostCallback d, Object state)
{
    d(state);
}

public virtual void Post(SendOrPostCallback d, Object state)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
}

Send simply calls the delegate on the calling thread (no thread switching of any kind), and Post does the same thing, but simply uses the ThreadPool to do it in an async fashion. In my opinion, this class should be abstract. The default implementation of this class is confusing and useless. It is one of two reasons I decided to write this article.

Conclusion

I hope you know more about this class now, and you understand how to use it. Within .NET, I found two classes that provide a custom synchronization. One for the WinForms thread context and one for WPF thread context. I am sure there are more, but these are the ones I found so far. The default implementation of the class, as I showed you, does nothing to switch code from one thread to another. This is simply because threads, by default, do not have this type of mechanism. UI threads, on the other hand, have a message pump and Windows APIs such as SendMessage and PostMessage that I am sure are used when marshalling code to the UI thread.

However, this should not be the end of the road for this class. You can make your own SynchronizationContext, it is really simple. In fact, I had to write one. At my work, we needed to have all COM based calls executed on an STA thread. However, our application is using the thread pool and WCF, and it was not simple to just marshal code into an STA thread. Therefore, I decided to code my own version of SynchronizationContext called StaSynchronizationContext. I will show how I did it in part II of this article.

Happy .NETting.

Tuesday, January 1, 2008

MVP (Model View Presenter or Supervising Controller) with DI (Spring.Net) and Threading support


Introduction



In this article I will show how to use the Model View Presenter pattern to remove logic from the UI and move it to a controller class. Furthermore, I will show an easy way to enable threading within the application and follow the rule of "no business work should be done in the UI thread". By applying threading correctly you should never have a situation where the UI is blocked while processing some business work.



Logon Example


To show the MVP pattern and all its glory I decided to use the logon screen example. We are all familiar with logon: a screen shows up asking for the user name and password. When the user presses the "Logon" button, work is initiated to validate if the user is authenticated on the system. Normally, logon is quick, however in complex systems, logging-on can take significant amount of time, I am going to show how to handle long operations with MVP, using a tiny framework which is based on the thread pool. But, first thing first, lets define our screen.



Creating the View



Views are really our UI layer. Normally these would be web pages or win forms, in this example I will use winforms. Using MVP, the view should really expose no business logic what's so ever. In fact, if you need to add an if statement you should ask yourself if it belongs in the view or the controller, unless your if statement relates with UI work, it probably belongs in the controller. The way I see views in MVP, are classes that at the core expose only properties and events - nothing else. There could be exceptions to this rule, but the goal is to make the view very simple. The view knows how to get data, and how to set data, but it doesn't know in which sequence or why. It is like a dummy puppet that provides all the ropes but without knowing the actual act.

Suppose our logon screen will have a user name field, password field, a status field (indicating if there is an error) and a button for performing the actual log-on. We can define the interface for the view without too much trouble.


public interface ILogonView

{

event EventHandler LogonEvent;

void Notify(string notification);

string Password { get; }

string UserName { get; }

}


Notice the interface contains a property with setter and getter for each field, and an event for pressing the log-on button. I have also added the Notify method, so I can notify my view from the outside, this method is used to setup the status field indicating if the logon is successful or not. I will talk about this method later. Using the ILogonView interface we get the extra benefit of having a view implemented in different ways, it can be a web page, or it can be a winform. It can even be a regular class - just used for testing.


public partial class LogonForm : Form, ILogonView

{

public event EventHandler LogonEvent;

public LogonForm()

{

InitializeComponent();

}



///

/// Get the User Name from the username text box

/// Trim the user name, and always return lower case

///


public string UserName

{

get { return mTextBoxUserName.Text.Trim().ToLower(); }

}



///

/// Get the password from the password textbox

///


public string Password

{

get

{

return mTextBoxPassword.Text;

}

}



///

/// Update the screen with a message

///


/// Message to show on the status bar

public void Notify(string notification)

{

mToolStripStatusLabelStatus.Text = notification;

}



private void mButtonLogon_Click(object sender, EventArgs e)

{

// fire the event that the button was clicked.

if (LogonEvent != null)

LogonEvent(this, EventArgs.Empty);

}

}


The Controller


The job of the controller (or the presenter) is to handle the events coming from the view, and use the view getters and setters properties to define the behavior of the view. Think of the view as a data source, just like a data layer, you can query the view for information and you set information to the view. The controller is the only component that knows exactly how to manipulate the view, and how to call the setters and getters in the right sequence.

public class LogonController

{

private ILogonView mView;

public LogonController(ILogonView view)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);

}



void mView_LogonEvent(object sender, EventArgs e)

{

string userName = mView.UserName;

string password = mView.Password;



if ((userName == "mike") && (password == "aop"))

{

mView.Notify("User Logged On");

}

else

{

mView.Notify("Invlid user name or password");

}

}

}



The controller is listening to the logon event that the view fires. When a logon event handler is triggered, the controller queries the user name and user password and validats if the user name and password are correct. If there is an error message, the controller sets the status message on the view with a message. However there are a few problems... First, I don't know if you noticed, when I first showed the code of the view, it does not contain a reference to the controller. Therefore I need to modify my Form to include knowledge of the controller


public partial class LogonForm : Form, ILogonView

{

public event EventHandler LogonEvent;

private LogonController mController;

public LogonForm()

{

InitializeComponent();

mController = new LogonController(this);

}



// rest of the class unchanged



So far we are classic MVP, if you understand everything to this point, you have just understood MVP. Anything above this point is just little things that bug me.



  • The controller is doing all the work, normally the logon work should not be done directly by the controller but delegated to a business layer class to handle the logon, ideally, a logon service.


  • What if the logon takes 10 minutes to process, we can not keep the view frozen.


  • What if we would like to send status back to the view during a business operation outside of the controller. how do we handle that?


  • To be honest with you, I still feel the view should be beyond stupid and not know anything. But, as you can see the view knows about its controller, and how to create it.




Using a service Layer



OK. one problem at a time. The first task would be to remove the logon processing from the controller and move it to a service layer. Let's create a LogonService class, which accepts a user name and a password, and validates if the user is valid. Now we will use our service layer from the controller to perform the logon operation. Same idea, the controller handles the logon event handler and delegates the work to the service layer. The service layer actually does the work of logging and updates the status message on the screen with the outcome of the operation.

We can create a simple service that looks like this:

public class LogonService

{

public bool Logon(string userName, string password)

{

bool rc;

if ((userName == "mike") && (password == "aop"))

{

rc = true;

}

else

{

rc = false;

}

}

}



But, here again, we have some problems. What if our service is a long running service, and maybe executes many steps to log a user. This example is simple, but let's face it is never that simple in production code. We normally have to go to the database to validate a user, I would like to provide the service some way to report status back to the view. After all, our controller can do this, so should the service... An idea would be to introduce an interface to allow the service report status something like INotify


public interface INotify

{

void Notify(string notification);

}



Now this should look familiar, our View has this method... (take a look)




public interface ILogonView

{

event EventHandler LogonEvent;

void Notify(string notification);

string Password { get; }

string UserName { get; }

}
So, lets break this into 2 interfaces...

public interface INotify

{

void Notify(string notification);

}



public interface ILogonView : INotify

{

event EventHandler LogonEvent;

string Password { get; }

string UserName { get; }

}

Notice that ILogonView inherits from INotify. Now we need to pass this INotify to the service, so lets modify our service. Other then that little change there nothing new with our View. Lets look at the controller using the

LogonService class.


public class LogonController

{

private ILogonView mView;

public LogonController(ILogonView view)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);

}



void mView_LogonEvent(object sender, EventArgs e)

{

string userName = mView.UserName;

string password = mView.Password;



LogonService logonService = new LogonService(mView);

logonService.Logon(userName, password);

}

}





public class LogonService

{

private INotify mNotifier;

public LogonService(INotify notifier)

{

mNotifier = notifier;

}

public bool Logon(string userName, string password)

{

bool rc;

if ((userName == "mike") && (password == "aop"))

{

mNotifier.Notify("Logon Successful");

rc = true;

}

else

{

mNotifier.Notify("Invliad User or Password");

rc = false;

}



return rc;

}

}


Notice a few things:





  • The service is created as a local variable to the event handler, it might be better to create the service once and keep it during the lifetime of the controller, but then we have the problem of who creates the service? It could be passed to the controller on the constructor or created directly in the Controller, but then it might not be re-used by other controllers. Best approach is to pass the service to the constructor, but I am not willing to have the view create it and pass it. I will deal with this issue soon.


  • The service is passing the view as an INotify, there is really nothing wrong with that, but if you think about it allows the service direct access to the UI. A better way would be to have the service talk to the Controller via INotify. Then we are respecting the role of the controller... (so I am going to make this change by allowing the controller to implement INotify


  • The goal was to provide the service a channel to communicate to the view, so now it is possible for a long running service to report status. But, what if we don't want to report anything, and would like to run the service without a view and without a UI, notice that you can't create the service without INotify. So here is another problem, which I will deal with later. At least we can say the logic of the logon is now outside of the controller, and our service is a little more powerful with its capabilities


  • A note about DDD (Domain Driven Design), notice my service is not very domain driven, it is normally at the service level that we should see classes such as User, and Authentication, For example Autentication.Autenticate(User user), but I am leaving the domain model out of this article, because already I have a lot of problems to solve and DDD deserve an article on its own.


Lets do a bit of re-factoring, first step, lets create the service as a member variable of the controller class. Lets also have the ability to pass the service to the constructor


public LogonController(ILogonView view)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);



mLogonService = new LogonService(this);

}



// set the serivce by the client (but not used for now).

public LogonController(ILogonView view, LogonService logonService)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);



mLogonService = logonService;

}



void mView_LogonEvent(object sender, EventArgs e)

{

string userName = mView.UserName;

string password = mView.Password;

mLogonService.Logon(userName, password);

}



// used to implemnt INotify

public void Notify(string notification)

{

mView.Notify(notification);

}

}




  • The controller implements INotify


  • The service can be passed to the controller, it's more flexible. But I am not changing the view, so this constructor will not be used


  • I created the service as a member variable if it is not passed.


OK. Lets step back a little, most of you might be happy with this implementation of MVP, and it is kind of by the book. But, I am still not happy with it. First of all, who is going to create the LogonService, it should really be set outside of the controller, or supplied to the controller (but I hate having the view create the service. Same problem with the Controller being created by the view. The view should have no knowledge of how to create a controller, it would be nice if the controller can be supplied to the view. The solution is to have a factory pattern to create the controller, service and even the view! The solution to all these problems can be addressed with Dependency Injection (DI).


The View depends on a Controller, and my Controller depends on a service. I can create a Factory that will create my view, addressing all the dependencies, and what do you know, there is a framework out there just for that - Spring.Net.


Using Spring.NET for Dependency Injection



To tell you all the truth, I am new to Dependency Injection, however it was not complicated to learn, and it solves the issues of object creation and dependecies. I chose to resolve all dependecies using setters properites. I have also created interfaces to all the classes that require depndecy injection

The controller interface:


public interface ILogonController : INotify

{

ILogonView LogonView { get; set; }

}

Setting the view to the controller, rather then passing the view as parameter into the constructure. Now the controller can have a empty default constructure.

Lets see the newly modified controller


public class LogonController : INotify, ILogonController

{

private ILogonView mView;

private ILogonService mLogonService;



public LogonController()

{



}



public LogonController(ILogonView view)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);



mLogonService = new LogonService(this);

}



// set the serivce by the client (but not used for now).

public LogonController(ILogonView view, LogonService logonService)

{

// register the view

mView = view;



// listen to the view logon event

mView.LogonEvent += new EventHandler(mView_LogonEvent);



mLogonService = logonService;

}



void mView_LogonEvent(object sender, EventArgs e)

{

// make sure the view is attached

Debug.Assert(mView != null, "view not attached");



string userName = mView.UserName;

string password = mView.Password;



mLogonService.Logon(userName, password);

}



// used to implemnt INotify

public void Notify(string notification)

{

mView.Notify(notification);

}



public ILogonService LogonService

{

set

{

mLogonService = value;

mLogonService.Notifier = this;

}

get

{

return mLogonService;

}

}



public ILogonView LogonView

{

set

{

mView = value;

mView.LogonEvent += new EventHandler(mView_LogonEvent);

}

get

{

return mView;

}

}

}


Notes:



  • Now when setting the LogonView property, the view is attached to the controller. Spring.Net will handle this for us.


  • Because this controller can be created using an empty constructure, I added an Assert, to make sure the view is attached when handling the logon event handler


  • Notice there is a setter property for the LogonService, After setting the service, the controller sets the Notify property of the service.



In order to inject the service into the controller, I needed to first make an interface to the service. Lets take a look at the service interface and the service class:

public interface ILogonService

{

bool Logon(string userName, string password);

INotify Notifier { get; set; }

}



public class LogonService : ILogonService

{

private INotify mNotifier;

public LogonService()

{

// instead of having it as null

mNotifier = new EmptyNotify();

}

public LogonService(INotify notifier)

{

mNotifier = notifier;

}

public bool Logon(string userName, string password)

{

bool rc;

if ((userName == "mike") && (password == "aop"))

{

mNotifier.Notify("Logon Successful");

rc = true;

}

else

{

mNotifier.Notify("Invliad User or Password");

rc = false;

}



return rc;

}

public INotify Notifier

{

set { mNotifier = value; }

get { return mNotifier; }

}

}


Notes:



  • The logon service interface now allows an INotify to be specified as a setter (so if I wanted, it could of been initialized using DI as well, but I am not doing it in this example



  • I provide an empty constructor, so now I don't need to have a notify object for creating or running the service. However, in case the INotify is not passed to the constructor or not set by the setter, I provide an EmptyNotify which is similar to having the mNofity set to null. However, because this empty class implements the interface, I don't need to check in my code if the INotify object is null, or if is passed.



Here a quick look at the EmptyNotify (which is like a Null)

public class EmptyNotify : INotify

{

public void Notify(string notification)

{

return; // do nothing.

}

}


Lets see how the view is changed

The nice thing about the new version of the view is that it is now simpler, the goal was always to keep the view unaware of business work and even something simple as creating the controller is now outside of the view. Like anything in MVP, there is a property to set the controller.

public ILogonController LogonController

{

set

{

mController = value;

mController.LogonView = this;

}

}


Notice that right after the controller is set, I assign the view to the controller LogonView property. Here is the full source code of the view after the modification.

public partial class LogonForm : Form, ILogonView

{

public event EventHandler LogonEvent;

private ILogonController mController;

public LogonForm()

{

InitializeComponent();

}



///

/// Get the User Name from the username text box

/// Trim the user name, and always return lower case

///


public string UserName

{

get { return mTextBoxUserName.Text.Trim().ToLower(); }

}



///

/// Get the password from the password textbox

///


public string Password

{

get

{

return mTextBoxPassword.Text;

}

}



public ILogonController LogonController

{

set

{

mController = value;

mController.LogonView = this;

}

}



///

/// Update the screen with a message

///


/// Message to show on the status bar

public void Notify(string notification)

{

mToolStripStatusLabelStatus.Text = notification;

}







private void mButtonLogon_Click(object sender, EventArgs e)

{

// fire the event that the button was clicked.

if (LogonEvent != null)

LogonEvent(this, EventArgs.Empty);

}

}


Setting Spring.Net


So far I have tried to avoid talking about Spring.Net, but at this point we are ready to deal with
Dependency Injection. First step is to get Spring.Net and install it. Don't worry it is safe, I have done it many times it will not break anything on your computer. You can download Spring.Net from http://www.springframework.net/

This example is using version 1.1 of Spring.Net

Next step is adding a file reference to Spring.Core.dll into the .NET project.

Now, that we have Spring.net, all that is left is to specify the dependencies for creating the objects (view, controller and service). To do this I have used the app.config to specify the dependencies in XML. The XML is simple to understand here is a copy of my App.Config for the Logon MVP example:




<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<configSections>

<sectionGroup name="spring">

<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>

<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />

</sectionGroup>

</configSections>



<spring>



<context>

<resource uri="config://spring/objects"/>

</context>



<objects xmlns="http://www.springframework.net/">



<object id ="LogonService" type="MvpExample.LogonService, MvpExample"/>



<object id="LogonController" type="MvpExample.LogonController, MvpExample">

<property name="LogonService" ref="LogonService"/>

</object>



<object id="LogonView" type="MvpExample.LogonForm, MvpExample">

<property name="LogonController" ref="LogonController"/>

</object>

</objects>

</spring>

</configuration>





Notes:

  • The Object ID tag is just a logical name

  • I have setup the LogonView, to have its property LogonController set to the object definition of "LogonController"

  • Similar case with the setting the LogonService logical name into the LogonController property "LogonService"

    All that is left, is just to create the root object, the view within my application. Notice the changes to Program.cs


    static class Program

    {

    ///

    /// The main entry point for the application.

    ///


    [STAThread]

    static void Main()

    {

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);





    IApplicationContext ctx = ContextRegistry.GetContext();

    Form logonForm = ctx.GetObject("LogonView") as Form;

    Application.Run(logonForm);

    }

    }


    The most important part are the Spring.net application context:
    IApplicationContext ctx = ContextRegistry.GetContext();

    Form logonForm = ctx.GetObject("LogonView") as Form;


    Here we are asking Spring.Net to create our View object, by specifying its Logical Name LogonView, the name must match the name in the app.config

    <object id="LogonView" type="MvpExample.LogonForm, MvpExample">

    <property name="LogonController" ref="LogonController"/>

    </object>




    All the other dependencies are taken care of by using Spring.Net. At this point our Logon application is initialized with the correct version of a view, controller and service. Notice that this allows us to "switch" the implementation of a dependency, just by providing a new implementation of an interface and configuration change. For example, to provide another version of the LogonService that willcontain
    additional work, we just need to tell Spring.Net which version to "inject". At this point I wanted to finish my article, but I noticed that there is one more issue with this MVP
    pattern. The case of having a long running service, and the risk of freezing the UI while processing the service. To solve this problem I have introduced a simple but yet powerful little threading framework.


    The UI should never freeze



    The main problem with UI and threads, is that the UI is not allowed to accessible from any other the thread then the thread it was created. This means that if our application starts to create threads, and performs processing in threads, it is not legal to have these threads update the UI (via an interface or not). In fact, trying to update the UI from another thread will cause a runtime exception in .NET 2.0, and unpredictable results in version 1.1

    So, our first goal is to make sure the UI is able to update correctly no matter from which thread it is called on. To do this, I have added a base class to my LogonForm called View. My base class contains only one method, UpdateUI, this method accepts a delegate of type MethodInvoker and makes sure this delegate is executed on the UI thread.




    public class View : Form

    {

    protected void UpdateUI(MethodInvoker uiDelegate)

    {

    if (InvokeRequired)

    this.Invoke(uiDelegate);

    else

    uiDelegate();

    }

    }





    I am planning to use the same delegate for all my UI activities. This should make you wonder, how a delegate that takes no arguments and no return values is able to satisfy all UI operations.

    Here is a trick... I use Anonymous methods to wrap all UI operations... lets look at a simple example:

    Getting the user name from the UI should be done on the UI thread, so I would like to wrap the code that gets the user name from the textbox into a MethodInvoker delegate




    Before:



    public string UserName

    {

    get

    {

    return mTextBoxUserName.Text.Trim().ToLower();

    }

    }


    After:


    public string UserName

    {

    get

    {

    string value = null;

    MethodInvoker uiDelegate = delegate

    {

    value = mTextBoxUserName.Text.Trim().ToLower();

    };

    UpdateUI(uiDelegate);

    return value;

    }

    }




    Notice: for the getters, I needed to store the return value outside of my anonymous method. This is because my delegate does not accept a return value. This is an issue I plan to resolved in a second part of the article... (using AOP to handle UI thread safely). Now, we have to surround all our View public methods with this uiDelegate. To make the job simpler I made a C# Snippet that allows you to select the code within the property, and then apply the "view thread safe"

    snippet. Here is the snippet, if you want to use it.




    <?xml version="1.0" encoding="utf-8" ?>

    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

    <CodeSnippet Format="1.0.0">

    <Header>

    <Title>View Thread Safe</Title>

    <Shortcut>view</Shortcut>

    <Description>Code snippet for creating thread safe view code</Description>

    <Author>Atrion Corporation</Author>

    <SnippetTypes>

    <SnippetType>Expansion</SnippetType>

    <SnippetType>SurroundsWith</SnippetType>

    </SnippetTypes>

    </Header>

    <Snippet>

    <Declarations>

    <Literal>

    <ID>delegate</ID>

    <ToolTip>Delegate to call</ToolTip>

    <Default>uiDelegate</Default>

    </Literal>

    <Literal>

    <ID>method</ID>

    <ToolTip>Function to handle the threading</ToolTip>

    <Default>UpdateUI</Default>

    </Literal>



    </Declarations>

    <Code Language="csharp"><![CDATA[

    MethodInvoker $delegate$ = delegate

    {

    $selected$ $end$

    };

    $method$($delegate$);

    $end$]]>

    </Code>

    </Snippet>

    </CodeSnippet>

    </CodeSnippets>



    Lets look at our new View method:


    public partial class LogonForm : View, ILogonView

    {

    public event EventHandler LogonEvent;

    private ILogonController mController;

    public LogonForm()

    {

    InitializeComponent();

    //mController = new LogonController(this);

    }



    ///

    /// Get the User Name from the username text box

    /// Trim the user name, and always return lower case

    ///


    public string UserName

    {

    get

    {

    string value = null;

    MethodInvoker uiDelegate = delegate

    {

    value = mTextBoxUserName.Text.Trim().ToLower();

    };

    UpdateUI(uiDelegate);

    return value;

    }

    }



    ///

    /// Get the password from the password textbox

    ///


    public string Password

    {

    get

    {

    string value = null;

    MethodInvoker uiDelegate = delegate

    {

    value = mTextBoxPassword.Text;

    };

    UpdateUI(uiDelegate);

    return value;

    }

    }



    public ILogonController LogonController

    {

    set

    {

    mController = value;

    mController.LogonView = this;

    }

    }



    ///

    /// Update the screen with a message

    ///


    /// Message to show on the status bar

    public void Notify(string notification)

    {

    MethodInvoker uiDelegate = delegate

    {

    mToolStripStatusLabelStatus.Text = notification;

    };

    UpdateUI(uiDelegate);

    }

    private void mButtonLogon_Click(object sender, EventArgs e)

    {

    // fire the event that the button was clicked.

    if (LogonEvent != null)

    LogonEvent(this, EventArgs.Empty);

    }

    }




    Now our view is able to update itself, no matter from which thread it is being called from. Next step is to actually use threads within the controller. Suppose the logon takes 5 seconds to logon. To enable threading at the controller level I can use the same approach I used for the view. Using delegates... Notice the new base controller class.


    public class AsyncController

    {

    public delegate void AsyncDelegate();



    // must call end invoke to clean up resources by the .net runtime.

    // if there is an exception, call the OnExcption which may be overridden by

    // children.

    protected void EndAsync(IAsyncResult ar)

    {

    // clean up only.

    AsyncDelegate del = (AsyncDelegate)ar.AsyncState;

    try

    {

    del.EndInvoke(ar);

    }

    catch (Exception ex)

    {

    OnException(ex);

    }

    }



    protected void BeginInvoke(AsyncDelegate del)

    {

    // thread the delegate, as a fire and forget.

    del.BeginInvoke(EndAsync, del);

    }



    protected virtual void OnException(Exception ex)

    {

    // override by childern

    }

    }


    Notes:





    • By calling BeginInvoke on a delegate I am using the thread-pool


    • I don't really care for output values or return code and this is mostly due to the MVP pattern, when I implement my controller function I can know when to set values to the view.


    • Notice that I still make sure EndInvoke is called; this is for 2 reasons, first to make sure I get exceptions and second making sure there is no resource leak. Calling BeginInvoke without EndInvoke may cause resources to leak.


    • If there is an exception, I let the child controller to take care of it.

    • I modified the logon service to simulate a long running operation, by Sleeping for 5 seconds




    public bool Logon(string userName, string password)

    {

    // simulate a long operation, wait 5 seconds.

    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));



    bool rc;

    if ((userName == "mike") && (password == "aop"))

    {

    mNotifier.Notify("Logon Successful");

    rc = true;

    }

    else

    {

    mNotifier.Notify("Invliad User or Password");

    rc = false;

    }



    return rc;

    }




    Lets, see the new logon event handler using threads:


    void mView_LogonEvent(object sender, EventArgs e)

    {

    // make sure the view is attached

    Debug.Assert(mView != null, "view not attached");



    AsyncDelegate asyncOperation = delegate

    {

    mView.Notify("About to perform logon");

    string userName = mView.UserName;

    string password = mView.Password;



    mLogonService.Logon(userName, password);



    };

    base.BeginInvoke(asyncOperation);

    }




    Just one note:
    Now when you execute the program, the UI will not freeze when pressing logon (the way it should be). However that doesn't stop the user from keep pressing on the logon button. It is important to add to the view additional functions to enable and disable the button. I didn't do it in this example, however it works well with MVP, but providing a setter method to enable or disable the Logon Button.




    Conclusion


    We went a long way from our simple Logon application. We have removed most of the logic from the view, keeping the view very simple. We have used DI to allow the application to inject the controller and service into our view. Finally, I have showed a way to enable threading without making major changes. The idea is to wrap UI functions with thread safe code, allowing all UI code to be marshalled to the UI thread. The only last re-factoring left to do is to remove the thread safety wrappers, and find a way to have them done with an Advice using Spring.Net. That way we can keep the view simple, not even knowing about the threading work.

    However, I think this will be done in my next article. I hope you enjoyed this article - Happy .netting.


    Dowload sample code: http://mike.peretz.googlepages.com/MvpProject.zip