Using Dynamic Proxies to Thread Enable MVP WinForms

The original version of the threaded code used two classes to implement the thread safe view and threaded presenter. These classes were specific to IView and IPresenter used by this application.

presenter.View = new ThreadSafeView(form, form);form.Presenter = new ThreadedPresenter(presenter);

The content of this post may seem out of place if you have not read the other posts in the series.

This approach works fine for the simple application presented in the previous post. We only have one view and one presenter. What would happen if we had many views and presenters as is typical in large applications? Our code would explode with many different ThreadedPresenters and ThreadSafeViews. Each of these thread enabled presenters and views will have the same basic implementation. That does not sound very DRY to me. There must be a better way.Dynamic Proxies to the RescueDynamic proxies let us code the basic implementation of both the ThreadedPresenters and ThreadSafeViews in one location and use this implementation for all of our views and presenters. Dynamic proxies allow us to remove the ThreadSafeView and ThreadedPresenter classes and use the factory pattern to create our thread enabled presenter and view.

presenter.View = ThreadHelper.CreateThreadSafeView<IView>(form, form);form.Presenter = ThreadHelper.CreateThreadedPresenter<IPresenter>(presenter);

The threading magic is now located inside of the ThreadHelper class.

public class ThreadHelper{    public static T CreateThreadedPresenter<T>(T adaptee) {        ProxyGenerator generator = new ProxyGenerator();        return (T) generator.CreateProxy(typeof(T), new PresenterInterceptor(), adaptee);    }    public static T CreateThreadSafeView<T>(T adaptee, ISynchronizeInvoke synchronizer) {        ProxyGenerator generator = new ProxyGenerator();        return (T) generator.CreateProxy(typeof(T), new ViewInterceptor(synchronizer), adaptee);    }}

The real magic is in Castle’s ProxyGenerator. ProxyGenerator’s CreateProxy method allows us to create a dynamic proxy for the interface T. PresenterInterceptor and ViewInterceptor incapsulate how we thread enable a presenter or a view.

public class PresenterInterceptor : IInterceptor {    public object Intercept(IInvocation invocation, params object[] args)    {        ThreadPool.QueueUserWorkItem(delegate(object state) {invocation.Proceed(args);});        return null;    }}

The PresenterInterceptor class is trivial. Each method invocation on the presenter interface is placed on the ThreadPool’s queue. The ThreadPool will execute the presenter method when a thread is available. That is it. Nothing else needs to be done.

The above code assumes that all of your Presenter interface methods have a return type of void. What? That is a huge restriction, right? No. Threading requires that you separate asking the question from getting the answer. Methods that have non-void return types cannot be threaded in any real way.

public class ViewInterceptor : IInterceptor {    private static readonly object[] EMPTY_ARGS = new object[0];    private readonly ISynchronizeInvoke synchronizer;    private delegate void Invoker();    public ViewInterceptor(ISynchronizeInvoke synchronizer) {        this.synchronizer = synchronizer;    }    public object Intercept(IInvocation invocation,                            params object[] args)    {        InvocationInvoker invoker = new InvocationInvoker(invocation, args);        synchronizer.BeginInvoke(new Invoker(invoker.Invoke), EMPTY_ARGS);        return null;    }}public class InvocationInvoker {    private IInvocation invocation;    private object[] args;    public InvocationInvoker(IInvocation invocation, object[] args) {        this.invocation = invocation;        this.args = args;    }    public void Invoke() {        invocation.Proceed(args);    }}

The ViewInterceptor is not as easy. It should be, but C# gets in the way. The majority of the code is focused around synchronizer.BeginInvoke The BeginInvoke method ensures the call to the view gets executed on the application’s GUI thread. The rest of the code is noise required by C#.The full source for this post can be found in my subversion repository.https://esterline.devguard.com/svn/code/MultiThreadWinFormsAll questions and/or comments are welcome.

Multi-Threaded WinForms Application – MVP

This is the third part of the Multi-Threaded WinForm Applications series, we will discuss how to use Model-View-Presenter (MVP) to inject threads into a WinForm application. In part one of this series, we discussed the basics of Multi-Threaded WinForms. In part two, we discussed using a BackgroundWorker to keep the WinForm application responsive during long running operations. In part four, we will use dynamic proxies to keep our code DRY.In order to use MVP, we must first convert our application to use the MVP pattern.Model (Same as in the other articles)

public class Model{    private const int MILLIS_IN_A_SECOND = 1000;    public string LongRunningMethod() {        Thread.Sleep(8 * MILLIS_IN_A_SECOND);        return "I am done";    }}

View (Interface and Concrete Class)Martin Fowler describes this type of view as the Passive View.The view is responsible for notifying the presenter when the Perform Operation button is pressed (Presenter.GetResults) and setting the results when asked to SetResults.

public interface IView{    IPresenter Presenter { get; set; }    void SetResults(string results);}public partial class MainForm : Form, IView{    private IPresenter presenter;    public IPresenter Presenter    {        get { return presenter; }        set { presenter = value; }    }    public void SetResults(string results)    {        label.Text = results;    }    void Button1Click(object sender, EventArgs e)    {        Presenter.GetResults();    }}

Presenter (Interface and Concrete Class)The presenter is responsible for interacting with the model to GetResults for the View.

public interface IPresenter{    IView View { get; set; }    void GetResults();}public class Presenter : IPresenter{    private IView view;    public IView View    {        get { return view; }        set { view = value; }    }    public void GetResults()    {        View.SetResults(new Model().LongRunningMethod());    }}

Where are the Threads?This is a very good question. Neither the View or the Presenter knows anything about Threading. This is a very good thing. I like to separate the responsibility of threads from the rest of the system. This makes the code easier to read and understand. In order to introduce threads into the system, we need to use the Proxy Pattern.ThreadSafeViewThe ThreadSafeView will wrap an IView and make it thread safe. In order to make the view thread safe, we will need a way to synchronize all access to the view. In WinForms, only the thread that created the GUI may change the state of the GUI. If more than one thread modifies the GUI then strange errors can occur. Luckily, .NET WinForms has a way to make sure all GUI changes are made on the GUI thread; ISynchronizeInvoke.The BeginInvoke method of the ISynchronizeInvoke interface ensures that all requests are executed on the GUI thread. Look at the SetResults(string results) for an example of how to use the ISynchronizeInvoke interface. This approach can get tedious as it requires you to create a delegate for each method of the View’s interface.

Note: If you want to use a more dynamic approach to creating the proxies, then check out the DyanmicProxy from the Castle Project.

public class ThreadSafeView : IView{    private IView adaptee;    private ISynchronizeInvoke synchronizer;    public ThreadSafeView(IView adaptee, ISynchronizeInvoke synchronizer)    {        this.adaptee = adaptee;        this.synchronizer = synchronizer;    }    public IPresenter Presenter    {        get { return adaptee.Presenter; }        set { adaptee.Presenter = value; }    }    private delegate void SetResultsDelegate(string results);    public void SetResults(string results)    {        synchronizer.BeginInvoke(new SetResultsDelegate(adaptee.SetResults), new object[] {results});    }}

ThreadedPresenterThe ThreadedPresenter wraps an IPresenter and invokes each method on the interface in another thread. This is illustrated below, in the GetResults method.

Note: The DynamicProxy would come in handy here as well.Note: I did not use the threadpool in the example below to make the code more readable, but in a production system the threadpool should be applied.Note: Read the next article in the series for more information.

public class ThreadedPresenter : IPresenter{    private IPresenter adaptee;    public ThreadedPresenter(IPresenter adaptee)    {        this.adaptee = adaptee;    }    public IView View    {        get { return adaptee.View; }        set { adaptee.View = value; }    }    public void GetResults()    {        new Thread(delegate() {adaptee.GetResults();}).Start();    }}

Putting it all togetherThe last thing we need to do is wire all the parts together. The below code was taken from the main method of the application.

[STAThread]public static void Main(string[] args){    MainForm form = new MainForm();    Presenter presenter = new Presenter();    presenter.View = new ThreadSafeView(form, form);    form.Presenter = new ThreadedPresenter(presenter);    Application.Run(form);}

ConclusionUsing the MVP pattern allows us to separate the normal application logic from the threading logic. This makes the application more maintainable.If we want to turn off threading, we just need to change the wiring defined in the main method. This has come in handy in more than one debugging session. It is much easier to debug a problem if we are able to turn off threads while debugging. If the application implements threading using the BackgroundWorker, it is much harder to turn off threads.MVP does introduce more complexity (as there are more classes), but I think it is worth it for all but the simplest cases.All code for all the articles can be found in my svn repository. All comments are encouraged and welcome.https://esterline.devguard.com/svn/code/MultiThreadWinForms

Multi-Threaded WinForm Application – BackgroundWorker

Welcome back to the second installment of a four part series (Part 1 – Basics, Part 3 – MVP and Part 4 – Dynamic Proxies).In Mult-Threaded WinForm Application – Basics, we discussed that long running operations render WinForm applications unresponsive. .NET 2.0 provides the BackgroundWorker component that allows us to perform long running operations in a background thread. The BackgroundWorker provides two interesting events DoWork and RunWorkerCompleted.DoWork is the event in which you should perform your long running operation. When calling the RunWorkerAsync method of BackgroundWorker the DoWork event is executed in a background thread.RunWorkerCompleted is the event in which you should update the GUI with the results from the work performed during the DoWork event.Example GUI using BackgroundWorker

void Button1Click(object sender, EventArgs e){    worker.RunWorkerAsync();}private string modelResults;void doWork(object sender, DoWorkEventArgs e){    modelResults = new Model().LongRunningMethod();}void workCompleted(object sender, RunWorkerCompletedEventArgs e){    label.Text = modelResults;}

If you run the above example, your GUI will remain responsive while the LongRunningMethod is running. You can test this by checking out the code at:https://esterline.devguard.com/svn/code/MultiThreadWinFormsAfter checking out the code, compile and run the ThreadedView project. Clicking on the Perform Operation button. You can confirm that the GUI is still responsive by moving the window from side to side. The GUI continues to respond even though the LongRunningMethod is executing.Conclusion:BackgroundWorker is a good alternative for simple tasks, but I think it has some issues.

  1. I think that BackgroundWorker encourages users to put more code in the view than I am comfortable with doing.
  2. Harder to test (see #1 and #3).
  3. The use of threads is embedded into application. If you decide to use BackgroundWorker, you are tied to using threads. If you want to remove threads from the application, you have to do major surgery.

In my next post, I will discuss how to the Model-View-Presenter (MVP) to inject threads into your WinForm applications.If you have any questions or comments, please feel free to drop me a note.

Multi-Threaded WinForms Application – Basics

Have you ever written a WinForms application that froze when a button was pushed? Have your users complained that the application is slow (or locking up their machine)? Do you want your applications to be responsive and user friendly? If so, then you will want to read this three part series on Writing Multi-Threaded WinForms Applications.In the first part of this series, I will discuss the benefits of using threads in WinForm applications and show you an example of an application that does not use threads. This will allow us to revisit this application through out the series (Part 2 – BackgroundWorker, Part 3 – MVP and Part 4 – Dynamic Proxies) discussing different ways to inject threads into your WinForms applications.What are the benefits to using threads in a WinForms application?

  1. Perception, to your users, that operations complete faster. By using multiple threads, the users will perceive that the operations complete faster, even though they actually may take longer. The reason for this is feedback. Using threads allows us to give the users feedback while the operation is in progress. This might be in the form of a progress bar, moving image or anything else that means operation in progress.
  2. Multiple tasks can be in progress at the same time. An example of this might be auto saving your users work without forcing them to stop what they are doing. Many applications do this today: all good word processors, Outlook and many others.
  3. GUI remains responsive during the operation. This allows us to perform basic tasks while we are performing work for the user. Without threads, our GUI will not even minimize during a long running task. This can cause our users to wait until the task complete before they can even use their computer again.
  4. Operations can be cancelled. Canceling a long running operation gives the user a chance to change their mind.
  5. GUIs can report Feedback. Feedback is the single most important reason for using threads in a WinForm application. This tells the user that their action did do something. It can also give the user an idea about how much longer a task is going to take.

Example GUI Without Threads

public class Model{    private const int MILLIS_IN_A_SECOND = 1000;    public string LongRunningMethod()    {        Thread.Sleep(8 * MILLIS_IN_A_SECOND);        return "I am done";    }}public partial class MainForm : Form{    void Button1Click(object sender, EventArgs e)    {        label.Text = new Model().LongRunningMethod();    }}

After running the MainForm class, click on the Perform Operation button. After clicking on the button, the GUI will be unresponsive for the 8 seconds that model sleeps during the LongRunningMethod method call. You can verify that the GUI is unresponsive by clicking on the minimize button. The Form will not minimize until the LogRunningMethod has completed.This is an example of a case where using a thread will allow the GUI to continue to be responsive while the model is working. In the next part of this series, I will show how using a thread will make the GUI more responsive during a long running model operation.f you would like to see the full source for the above example, check it out from the following subversion repository.https://esterline.devguard.com/svn/code/MultiThreadWinFormsIf you have any questions or comments, please feel free to drop me a note.