Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / C#
Tip/Trick

WCF and Silverlight - Putting Your Code All Together

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
5 Jan 2011CPOL3 min read 10.6K   8   2
How to get (almost) all your code in one place when using WCF together with Silverlight
So, I've trolled the Internet for a solution to the problem where you are forced to operate in a completely asynchronous fashion when using WCF in Silveright. And, I've found a lot of different answers. Of course, the answers all address how to make your WCF calls in a synchronous fashion, one by one - with the usual caveat that you must stay off the UI thread, or rest in infinite peace. I view these as half a solution, because most of the time, you are, well, interacting with a user. It's Silverlight, it's what you do.

So, I wanted a way to (relatively) get all my code in one place. The advantages of this are: (relative) increase in human readability of the code hopefully leading to higher degrees of maintainability and keeping "functional" state out of your class - by this, I mean you want to avoid putting temporary state in your classes simply because you have to break your code executing one logical task across several methods.

My first idea was to use aspects - but they don't exist in regular old C# (still the cleanest answer in my opinion). My second idea was to use a call/cc style of continuations to easily be able to move my code around on and off the UI thread, I thought, hey, C# has yield, why not full on continuations. Nope, not there, but, we *do* have closures - lambdas! So, I could pull off a continuation passing style that (relatively) achieves what I want, albeit limited, and uglier than I had hoped. Finally, I, being lazy, didn't want to try and decide all the time if I was on the UI thread and what to do if I was, or for that matter how to get back to the UI thread when I was done playing with WCF. OK, enough context and blathering on about my approach and why.

Here's the class that will allow you to setup synchronous calls:

C#
public class WcfSync
{
    public static Dispatcher currentDispatcher = Application.Current.RootVisual.Dispatcher;
    public void Sync(Action wcfCalls, Action uiCalls = null)
    {
        if (currentDispatcher.CheckAccess())
        {
            Thread t = new Thread(new ThreadStart(() => {
                wcfCalls();
                if (uiCalls != null)
                {
                    currentDispatcher.BeginInvoke(uiCalls);
                }
                if (HandleSyncEnd != null)
                {
                    HandleSyncEnd();
                }
            }));
            t.Start();
        }
        else
        {
            wcfCalls();
            if (uiCalls != null)
            {
                currentDispatcher.BeginInvoke(uiCalls);
            }
            if (HandleSyncEnd != null)
            {
                HandleSyncEnd();
            }
        }
    }
    public delegate void SyncEnd();
    public event SyncEnd HandleSyncEnd;
}


Then, you can use most of the WCF synchronization techniques out there with Sync to handle the typical code scenario of do something with WCF and then do something on the UI to reflect the results. I used an interesting solution from John Leitch[^].

So, using John's sync wrapper, you get code that might look something like this:

C#
WcfSync syncer = new WcfSync();

MmsLogin.MmsLoginClient loginClient = new MmsLogin.MmsLoginClient();

string username = usernameBox.Text;
string password = passwordBox.Password;
OKButton.IsEnabled = false;
string errorMessage = null;

syncer.Sync(
//here is the start of the sync calls
    () =>
{
    MmsLogin.LogonCompletedEventArgs tokenargs = null;
    try
    {
        tokenargs = 
            Wrapper.SynchronousCall<MmsLogin.LogonCompletedEventArgs>(
                loginClient, 
                "Logon", 
                username, 
                password );
    }
    catch (Exception ex)
    {
        errorMessage = ex.Message;
    }

    if (tokenargs != null && tokenargs.Result.Length != 0)
    {
        token = tokenargs.Result;
    }
},
//here is the start of the resulting UI calls
    () =>
{
    if (token != null && errorMessage == null)
    {
        this.DialogResult = true;
    }
    else
    {
        if (errorMessage != null)
        {
            message.Content = errorMessage;
        }
        else
        {
            message.Content = "Username or password not accepted.";
        }
        message.Foreground = new SolidColorBrush(Colors.Red);
        OKButton.IsEnabled = true;
    }
}
);


One disadvantage is that Sync doesn't behave exactly the same way if you are on the UI thread as it does when you are off of it. If you are on the UI thread, Sync returns immediately. Otherwise, Sync waits until you are completed with the WCF section before returning... long story short, don't put code after your sync call that you want to have happen *after* the WCF and UI calls. Yup it's inelegant, and kludgy, but it accomplishes my goals and I can crank out reliable and maintainable code with it (provided I don't try to do more after Sync that I expect to behave synchronously following my Sync calls).

Enjoy,
Jerry

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralInteresting approach. Pin
Dr.Walt Fair, PE27-Dec-10 13:25
professionalDr.Walt Fair, PE27-Dec-10 13:25 
GeneralInteresting Pin
#realJSOP26-Dec-10 3:57
mve#realJSOP26-Dec-10 3:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.