Exception Handling, Queuing, and UI Synchronization for WCF Services Using the CCR

This weekend I wanted to throw together a nice sample illustrating some ideas that I was playing around with this summer. While I was out at Microsoft Research, I got turned onto Microsoft Robotics Developer Studio and the incredibly cool Concurrency and Coordination Runtime (CCR) that gives it a solid foundation.

Interacting with remote services is difficult.  WCF has made the interaction easier using the “address-binding-contact” abstractions, but this doesn’t address things like concurrency , multithreading, asynchronicity, failures, and timeouts. Writing code that handles all of the possible scenarios can be messy very quickly. ThreadPools, BeginInvoke, EndInvoke, IAsyncResult, ManualResetEvent, and friends aren’t exactly the easiest thing to get right, but if you want a responsive UI and a robust application, you must worry about all of these things.

George Chrysanthakopoulos and the creators of the CCR recognized this and have provided an amazing abstraction on top of the current threading implementations on the .NET platform. I’ve blogged about the CCR before, but haven’t really posted any useful examples that truly illustrate its power. Get ready to be blown away — I’m going to show how easy it is to write a WinForms client that accesses a remote WCF service that:

  • Correctly interacts with the UI on the correct thread
  • Has full responsiveness of the UI
  • Caches requests to the service if necessary
  • Never blocks a thread while waiting for something, performing all operations asynchronously
  • Never uses the “lock” keyword

I couldn’t believe how easy it was to get everything working.

The WCF Service

I’ve just made an extremely simple WCF Service for this demo.  It has a single operation, DoSomething that takes a request and generates a response. I like the way that the DoSomethingRequest and DoSomethingResponse allow for both multiple input and output properties on the respective types, making for a cleaner interface. Apparently I’m not the only one to think this, though the motivation is grounds for another complete post.

Our WCF service is contained within a WCF Service Library. This makes it easy to reference from other projects in the solution.

[ServiceContract]

public interface IUsefulService

{

    [OperationContract]

    DoSomethingResponse DoSomething(DoSomethingRequest request);

}

The request/response classes are very straightforward:

[DataContract]

public class DoSomethingRequest

{

    public DoSomethingRequest(int inputValue)

    {

        this.InputValue = inputValue;

    }

    [DataMember]

    public int InputValue { get; private set; }

}

[DataContract]

public class DoSomethingResponse

{

    public DoSomethingResponse(string outputValue)

    {

        this.OutputValue = outputValue;

    }

 

    [DataMember]

    public string OutputValue { get; private set; }

}

The implementation of the service is also very simple:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall, ConcurrencyMode=ConcurrencyMode.Multiple)]

public class UsefulService : IUsefulService

{

    public DoSomethingResponse DoSomething(DoSomethingRequest request)

    {           

        // Do something useful [sic]

        Thread.Sleep(500);

 

        // We REALLY don’t like 2 (reminds us of the clowns…)

        if (request.InputValue == 2)

        {

            throw new ArgumentException(“UsefulService: The input value may not be 2!!”);

        }

        string message = String.Format(“UsefulService: Just did something useful with: {0}”, request.InputValue);

        return new DoSomethingResponse(message);

    }

}

The service just takes in a request (an integer) and returns a response (a string) with more text.  However, if the input is 2, then an exception is thrown, so we’ll need to be ready on the client to handle this. (We’re ignoring fault contracts now for simplicity).

I should also point out that this service has InstanceContextMod=PerCall.  This means that WCF instantiates a new instance of the UsefulService class for every call that comes in. Also, we have ConcurrencyMode=Multiple, indicating that WCF also uses a new thread for every incoming call (with a preset maximum number that I can’t remember at the moment).  What this does is essentially blow the WCF service host wide open in terms of concurrency, allowing multiple threads to interact with their own instance of the class.  Since we’re not doing anything requiring synchronized access to shared state, these settings are largely unimportant.

Note that I’m not using the CCR on the service side — not yet.  I have some examples of how to do this, but that will unfortunately have to wait for future post :) Now onto the client…

The WCF Client

On the client side (a WinForms project), we add a reference to the service, making sure to go into the advanced option and turn on the generation of asynchronous operations.

image

image

This automatically generates a UsefulServiceClient class that not only has synchronous methods DoSomething, but also a method/event pair that can be used to invoke the operation asynchronously:

image

We’ll use the method/event pair for this example and won’t worry about using the Begin/End methods.

<Sidenote>

It’s also interesting to note that our generated IUsefulService interface on the client actually has 3 methods instead of 1 (with the attributes, cruft and unnecessary namespaces removed):

public interface IUsefulService {

 

    [OperationContractAttribute(Action=“…”, ReplyAction=“…”)]

    DoSomethingResponse DoSomething(DoSomethingRequest request);

 

    [OperationContractAttribute(AsyncPattern=true, Action=“…”, ReplyAction=“…”)]

    System.IAsyncResult BeginDoSomething(DoSomethingRequest request, AsyncCallback callback, object asyncState);

 

    DoSomethingResponse EndDoSomething(IAsyncResult result);

}

We could also use the {Begin/End}DoSomething pair here (also exposed on the UsefulServiceClient) since WCF can handle the APM (Asynchronous Programming Model pattern of the framework) invocation under the covers.  I’ll dig into this in a future post when we get to using the CCR on the server side. If you’re interested, Dan Rigsby has an excellent series of posts about asynchronous WCF service implementation. I’ll talk about this more in a future post.

</Sidenote>

CCR-Compatible WCF Client Wrapper

I’m not going to go into much detail here (check out this post to get started) about the architecture of the CCR. Suffice it to say that we have our very own thread pool, the DispatcherQueue, not related in any way to the .NET ThreadPool.  We create any number of “ports” which are just strongly-typed queues that can have messages “posted” to them.  Then, we can hook up handlers that get called whenever a message gets posted to the port.  The sender and receiver are completely decoupled, and the thread which executes the handler is managed by the dispatcher.

The key thing to take away from this is that ports (aptly named) are the “interfaces” between the producer and the consumer.  So, if we want to communicate with a service, we ask it for a port with which to post incoming requests for it to operate on.  On a similar token, we can also request a reference to a port with which we can hook up a handler to be called whenever the service obtains a response.

So, we can create a wrapper class around the auto-generated WCF client class that exposes two ports — an input (request) and an output (response) port.

Well, that’s the idea anyway.  Unfortunately we’ve subtly overlooked our failure scenarios.  Another possible outcome of a call to the service is that an exception is thrown.  The CCR allows us to create a conglomerate of ports called a PortSet which allows us to specify that either of two message types can be posted there.  We need this for the output port since the outcome of our operation could either be a response or an exception. This is a great approach since the failure information is explicit — we don’t have to wonder if an exception will just “bubble up” later.

Another point that needs to be made is that the CCR operates under a message-passing paradigm which emphasizes statelessness. Every message is self-contained.  So, we could post message requests into a port and wait for message responses on another port, but because of the asynchronous nature of things, we can’t assume that the response order will match the request order.  If we need to know which request generated which response (as is the case here), we need to be more explicit. The solution isn’t difficult — we just bundle a request with its response and call it a DoSomethingContext:

public class DoSomethingContext

{

    public DoSomethingRequest Request { get; set; }

    public DoSomethingResponse Response { get; set; }

}

This brings us to the first glimpse of our UsefulServiceWrapper class:

public class UsefulServiceWrapper : CcrServiceBase

{

    public UsefulServiceWrapper(DispatcherQueue queue)

        : base(queue)

    {

// …

    }

 

    public Port<DoSomethingContext> DoSomethingInputPort {get…}

 

    public PortSet<DoSomethingContext, Exception> DoSomethingOutputPort {get…}

 

    public Port<string> LogPort {get…} 

 

// …

}

We notice that our wrapper inherits from CcrServiceBase, a lightweight base class that just provides a TaskQueue property that exposes a DispatcherQueue which is set in the constructor, as well as a few other convenience methods.  We need to have access to the application’s DispatcherQueue to be able to send and receive messages through the ports.

There are three ports (or Ports/PortSets to be particular) here.  The first port is the input to the DoSomething operation which takes a DoSomethingContext (in this case the Request property will have a non-null DoSomethingRequest and the Response property will be null). The second port is a PortSet of a DoSomethingContext and an Exception, indicating that there are 2 possible outcomes of the operation.  The third port is a convenience port which allows the internal workings of the wrapper class to be observed (if desired) by allowing log messages to be posted to it.

Wrapper Logic

While implementing the wrapper logic, we have one rule — NEVER block a thread while we’re waiting for WCF to do something.  If we’re not doing something constructive with the thread (a scarce resource), then let the CCR execute other code with it.

Consequently, the standard WCF client convention is completely out:

UsefulServiceClient client = new UsefulServiceClient();

client.Open();

client.DoSomething(request);

client.Close();

This ties up a single thread during the entire execution of the operation.  If there’s a lot of network delay, I wouldn’t be surprised if 99% of the time the thread is sitting there idle, waiting for a response. This really limits our scalability in a big way. This isn’t going to work work — we need to use the asynchronous equivalent for everything — {Begin/End}Open, DoSomethingAsync/DoSomethingCompleted, and {Begin/End}Close.

Let’s take a look at just the constructor operation.  We’re going to use an awesome feature of the CCR – CCR Iterators — that uses C# 2.0 iterators to write synchronous-looking code that executes asynchronously.  The trick is to implement a method that returns IEnumerator<ITask>.  ITask is just a “unit of work” for the CCR, and we return an enumeration.  We get to use the yield keyword inside of iterator methods.

When you think about it, iterators are methods that execute different code each time that you call them.  That is exactly why they are well-suited for doing asynchronous programming — the individual sections of the method can be executed by different threads in an asynchronous manner as they are needed. The compiler works its magic behind the scenes, actually implementing iterators as a state machine. Pretty cool stuff.

Here’s the first part of the implementation showing how we can execute the constructor and catch any exceptions:

private IEnumerator<ITask> DoSomethingIterator(DoSomethingContext context)

{

    bool failed = false;

    SuccessFailurePort successFailurePort = new SuccessFailurePort();

 

    // Try to call constructor

    UsefulServiceClient client = null;

    try

    {

        client = new UsefulServiceClient();

        successFailurePort.Post(new SuccessResult());               

    }

    catch (Exception ex)

    {

        successFailurePort.Post(ex);

    }

    yield return Arbiter.Choice(successFailurePort,

        (successResult) =>

        {

            m_LogPort.Post(“Client creation successful.”);

        },

        (failureException) =>

        {

            m_LogPort.Post(“Client creation failed.”);

            m_DoSomethingOutputPort.Post(failureException);

            failed = true;

        });

    if (failed) yield break;

    // … rest of the code

}

First we create a SuccessFailurePort, just a fancy name for PortSet<SuccessResult,Exception>. Then we try to call the constructor inside of a try/catch block. If the constructor completes successfully, then we post a success result to the success/failure port.  If an exception occurs, then we post the exception to the port.  The next line is where the magic of the CCR comes in — we “yield return Arbiter.Choice(successFailurePort…)”.  Translated into english, this means: “Return this thread back to the CCR and don’t come back until EITHER a success result OR an exception gets posted to the successFailurePort. Then, when we’ve ‘joined’ up with either result, execute either of these next two anonymous methods depending on which one was posted.”  Whoa.  That’s an amazing amount of power right there, after you get used to the unfamiliar syntax.

So, If there is a successful result, a message is posted to the log and the method continues down.  If there is an exception, we post a message to the log and also post the exception to the DoSomethingOutputPort, and set the failed flag to true.  If that flag is set, then we “yield break”, indicating to the CCR that we are completely finished with this method and never expect to re-enter the iterator. When we yield break, we’re completely done.

(Bear with me — even though this looks like a lot of code, it’s boilerplate. I’ve written a T4 template for generating it.  Also, there are less verbose ways of calling things (thanks to some extension methods in the latest version) but they can be difficult to grasp without first seeing things like this. We’ll see soon that interacting with this code via the ports is a breeze, so it’s worth it to write it once and forget about it.)

Now, assuming that the constructor didn’t throw an exception, we can now open the client (asynchronously of course):

client.InnerChannel.BeginOpen(

    (iar) =>

    {

        try

        {

            client.InnerChannel.EndOpen(iar);                       

            successFailurePort.Post(new SuccessResult());                       

        }

        catch (Exception ex)

        {

            successFailurePort.Post(ex);

        }

    }, null);

yield return Arbiter.Choice(successFailurePort,

    (successResult) =>

    {

        m_LogPort.Post(“Open successful.”);

    },

    (failureException) =>

    {

        m_LogPort.Post(“Open failed.”);

        m_DoSomethingOutputPort.Post(failureException);

        failed = true;

    });

if (failed) yield break;

This pattern should look familiar — it is the standard method of interacting with APM code.  The trick is that the EndXXX method can always throw an exception if the operation failed, so we need to handle that in the same way as before with the successFailurePort. Notice that if we have two possible paths (e.g. success or failure) then both paths must be capable of posting something to the port to be able to continue past the Choice.

Now we can interact with the DoSomethingAsync operation.  First we subscribe to the even handler, call the method, and then wait for either success or failure:

// Now try to call DoSomething asynchronously

client.DoSomethingCompleted += (sender, args) =>

{

    try

    {

        if (args.Cancelled == true)

        {

            successFailurePort.Post(new Exception(“The operation was cancelled.”));

        }

        if (args.Error != null)

        {

            successFailurePort.Post(args.Error);

        }

        context.Response = args.Result;

        successFailurePort.Post(new SuccessResult());

    }

    catch (Exception ex)

    {

        successFailurePort.Post(ex);

    }

};

client.DoSomethingAsync(context.Request);

// Wait until the operation EITHER succeeds or fails

yield return Arbiter.Choice(successFailurePort,

    (successResult) =>

    {

        m_LogPort.Post(“Operation successful”);

    },

    (failureException) =>

    {

        m_LogPort.Post(“Operation failed.”);

        m_DoSomethingOutputPort.Post(failureException);

        failed = true;

    });

if (failed) yield break;

Once again, if there was a failure then the exception is posted to the output port and we “yield break” indicating that the iterator method has completed (completely).

As the last step, we then call {Begin,End}Close:

// Now try to call BeginClose asynchronously

client.InnerChannel.BeginClose(

    (iar) =>

    {

        try

        {

            client.InnerChannel.EndClose(iar);

            successFailurePort.Post(new SuccessResult());

        }

        catch (Exception ex)

        {

            successFailurePort.Post(ex);

        }

    }, null);

// Wait until the operation EITHER succeeds or fails

yield return Arbiter.Choice(successFailurePort,

    (successResult) =>

    {

        m_LogPort.Post(“Close successful.”);

    },

    (failureException) =>

    {

        m_LogPort.Post(“Close failed.”);

        m_DoSomethingOutputPort.Post(failureException);

        failed = true;

    });

if (failed) yield break;

If we make it this far in the iterator method, then we are finished and a successful result has been stored in the DoSomethingContext.  We can then post the completed context (containing both the request and the response of the DoSomething method) to the output port:

// If we made it this far, then the result was obtained

// successfully and we can post it to the output port.

m_DoSomethingOutputPort.Post(context);

yield break;

And…we’re done. Almost.

The only thing missing is how we specify that DoSomethingIterator contains all of the code to run when something is posted to the DoSomethingInputPort.  To do this, we need to “activate” a “receiver” on the input port — that is, wire up the input port so that it runs the iterator. In this case, it’s as easy as putting this in the constructor:

Arbiter.Activate(this.TaskQueue,

    Arbiter.ReceiveWithIterator(true, m_DoSomethingInputPort, DoSomethingIterator)

);

The TaskQueue property refers to the DispatcherQueue given to the wrapper class’s constructor.

Now that we have the verbose part out of the way, let’s take a look at how we can use our CCR-compatible wrapper class by interfacing through its ports.

The WinForms Client

Ok, now we get to the fun part. :) So far we have implemented a service, auto-generated a WCF proxy to the service, and created a wrapper class around the WCF proxy.  Now all we need to do is create a form to illustrate how to use our CCR WCF wrapper class.

The form is simple: 1 input text box, 1 button, and a scrolling output text box.

image

When I press the Send button, I want to fire off N simultaneous requests to the WCF service with the request payload counting from 1 to N. When a request comes back, I want to log some information in the bottom text box.  I also want to handle all service exceptions, and I want to be able to move the window around while the service calls are being executed without having redraw problems.

Ok, so we’re faced with an interesting scenario here: to be CCR-compatible, we need to use the CCR  DispatcherQueue (essentially a thread pool), but how can we do that when WinForms has very specific threading requirements to handle the underlying Win32 API interop (message pump, etc)?

The trick is that the CCR comes with a number of WinForms adapters that make this impedance mismatch easier to handle.  Unfortunately I didn’t find everything that I needed in the Microsoft.Ccr.Adapters.WinForms namespace, so I needed to write a little more interface code.  The result is a programming API that directly mimics a typical WinForms program.  Normally the Program.cs file contains:

[STAThread]

static void Main()

{

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);

    Application.Run(new MainForm());

}

However, I’ve written a CcrApplication.Run static method so that we can do this instead:

[STAThread]

static void Main()

{

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);

    CcrApplication.Run((queue) => new MainForm(queue));

}

That’s not so bad.  The only trick here is that instead of passing in a Form argument to Application.Run is that we’re passing in a Func<DispatcherQueue,CcrForm> delegate.  This is just a method that takes a DispatcherQueue and returns a CcrForm.  What is this CcrForm, you ask?

It’s just an abstract base class that accepts a DispatcherQueue in the constructor and uses that queue to set everything up. The key here is that the CcrForm has a property called FormServicePort of type WinFormsServicePort that lets us interact with the form (create a new one, invoke delegates on the UI thread, and close down the form).

I modified the code from this post so that it correctly handles form shutdown. The CcrApplication.Run method just creates a DispatcherQueue and then initializes a ManualResetEvent that we can wait on to keep the main thread from exiting (otherwise our window wouldn’t even show). We also hook up to the FormClosed event on the form so that we can cleanly shut down.

public static class CcrApplication

{

    private static DispatcherQueue m_DispatcherQueue;

// …

    public static void Run(Func<DispatcherQueue, CcrForm> createForm)

    {

        if (createForm == null)

        {

            throw new ArgumentNullException(“createForm”);

        }

 

        using (Dispatcher dispatcher = new Dispatcher(0, “Dispatcher”))

        {

            using (m_DispatcherQueue = new DispatcherQueue(“DispatcherQueue”, dispatcher))

            {

                // Create the form using the newly-created dispatcher

                CcrForm form = createForm(m_DispatcherQueue);

                // …

 

                ManualResetEvent mainThreadEvent = new ManualResetEvent(false);

 

                form.FormClosed +=

                    (sender, args) =>

                    {

                        Shutdown shutdown = new Shutdown();

 

                        // Sign up to be notified when the WinFormServicePort

                        // has successfully been shutdown

                        Arbiter.Activate(m_DispatcherQueue,

                            Arbiter.Choice(shutdown.ResultPort,

                                (success) =>

                                {

                                    mainThreadEvent.Set();

                                },

                                (failure) =>

                                {

                                    mainThreadEvent.Set();

                                })

                            );

 

                        // We need to inform the WinFormsAdaptor that it is ok to quit.

                        form.FormServicePort.Post(shutdown);

                    };

 

                // Use the WinFormsServicePort to create a MainForm.

                form.FormServicePort.Post(new RunForm(() => form));

 

                // Wait for the form to be closed

                mainThreadEvent.WaitOne();

            }

        }

    }

}

The CcrForm class is also fairly straightforward, just storing the DispatcherQueue so that we can use it from the form.

public partial class CcrForm : Form

{

    public CcrForm(DispatcherQueue taskQueue)

        : base()

    {

        InitializeComponent();

 

        if (taskQueue == null)

        {

            throw new InvalidOperationException(“The taskQueue is null.  Make sure that you are using the CcrApplication.Run method to start the main message loop.”);

        }

        this.TaskQueue = taskQueue;

 

        this.FormServicePort = WinFormsAdapter.Create(taskQueue);

    }

 

    public DispatcherQueue TaskQueue { get; private set; }

 

    public WinFormsServicePort FormServicePort {get; private set; }

 

 

    public void Activate(params ITask[] tasks)

    {

        Arbiter.Activate(this.TaskQueue, tasks);

    }

 

    public void FormInvoke(Action action)

    {

        this.FormServicePort.Post(new FormInvoke(() => action()));

    }

}

The Activate method is just for convenience so we don’t need to keep typing this.TaskQueue.  The FormInvoke method also makes calling it easier (as we’ll see in a sec).

Client Logic

Ok, we’re almost there! We need to “wire up” the logic in the form:

  • Whenever a message is posted to the log port, display the information in the bottom text box
  • Whenever a message is posted to the service output port (successfully), display the result in the bottom text box
  • Whenever a message is posted to the service output port (exception), display the exception message in the bottom text box
  • Whenever the Send button is pressed, post messages to the service input port.

The first 3 are receivers, and then last 1 is a post.  We can set up the first three persistent receivers in the constructor like this:

// Create the CCR wrapper for the WCF service so that it dispatches to our main queue

m_Service = new UsefulServiceWrapper(this.TaskQueue);

 

// Wire up the logic:

this.Activate(

 

    // If anything comes in on the log port,

    Arbiter.Receive(true, m_Service.LogPort,

    // then write it to the output

        (message) =>

        {

            Log(“Log   : {0}”, message);

        }),

 

    // If a string result comes in on the output port,

    Arbiter.Receive(true, m_Service.DoSomethingOutputPort.P0,

    // then write it to the output

        (result) =>

        {

            Log(“Result: {0}”, result.Response.OutputValue);

        }),

 

    // If an error comes in on the result port,

    Arbiter.Receive(true, m_Service.DoSomethingOutputPort.P1,

    // then write it to the output

        (error) =>

        {

            Log(“Error : {0}”, error.Message);

        })

);

The Log method is just a helper method that appends a line of text to the lower textbox by wrapping the code up into a delegate and posted it to the WinFormsServicePort so that it may be executed on the UI thread.

private void Log(string format, params object[] args)

{

    // Invoke the AppendText method on the UI thread

    this.FormInvoke(

        () =>

        {

            txtOutput.AppendText(

                String.Format(“[{0}]:{1}{2}”,

                    DateTime.Now.ToLongTimeString(),

                    String.Format(format, args),

                    Environment.NewLine));

        }

    );

}

The only thing we have left is the button handler which posts new messages to the service input port:

private void btnSend_Click(object sender, EventArgs e)

{

    int numThreads;

    if (Int32.TryParse(txtInput.Text, out numThreads))

    {

        if (numThreads > 50) numThreads = 50;

        if (numThreads < 2) numThreads = 2;

 

        for (int i = 0; i < numThreads; i++)

        {

            // post the number into the input port of the service

            DoSomethingContext ctx = new DoSomethingContext()

            {

                Request = new DoSomethingRequest()

                {

                    InputValue = i

                }

            };

            m_Service.DoSomethingInputPort.Post(ctx);

        }

    }

}

There’s an arbitrary limit of 50 messages in there, just so you can’t go completely nuts (100,000 requests might be a bit much).

Testing

After all of that work, we can finally try things out! I set my solution so that both my WinForms project and my WCF service get started when I hit F5.

The WCF test client starts up, indicating our service is live:

image

Now we dial in 10 as the number of threads to start and click the Send button.  Not just once.  20 times.  I just totally wail on the Send button and watch what happens:

image

After about 20 seconds, all of the queued requests finally finish and all log lines get printed to the text box.  Amazingly, I was able to constantly move the window around my screen without any hiccups as all of that was going on! And, to think that all of that happened without writing a single line of lock synchronization code…

Conclusion

I hope you enjoyed this in-depth exploration into the amazing world of the CCR.  I know I sure did. I’m quickly becoming a fan of the CCR’s model of event-driven asynchronous programming, where you can define your interfaces between components and then just “wire them up” with receiver code.  It certainly makes for a clean model.

To recap, we were able to write clean code that correctly interacted with the UI thread, giving us a fully-responsive UI, were able to cache the service requests by posting them into the wrapper’s input port, and we NEVER blocked a thread while waiting for asynchronous I/O. In addition, all failure conditions were handled cleanly. The code might seem pretty complicated at first (lots of anonymous methods everywhere) but after you get used to the way things work, it’s very powerful.  The ability to write synchronous-looking code that executes asynchronously is (to put it simply) pure genius on George’s part.

One thing that I didn’t cover is the CCR’s ability to coordinate lock-style code (e.g. to access shared state).  I’ll take an in-depth look into coordination/synchronization, as well as how to use the CCR to implement asynchronous WCF services in a future post.

I’ll put up the code soon for everyone to download.

Hope that helps! :)


You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

AddThis Social Bookmark Button

4 Responses to “Exception Handling, Queuing, and UI Synchronization for WCF Services Using the CCR”

  1. Do you have this zipped up? I walked through this but at the end, it kinda falls apart. When reviewing my windows form, I can’t view it in design mode.

  2. Any chance that you will be posting a working example of the code from this article?

  3. Would love to see the original solution file!

  4. You’d think after a 3 yr. time span of request for the code it would’ve either a.) been posted or b.) a response from author that is would not be available. Which then brings me to the question of “Why blog if you’re not going to interact with your audience?”

    [Ed. Note] Just because I’ve had time to blog in the past doesn’t necessarily mean that I have time to blog at the moment. If you’d left your comment with a valid email address (and perhaps phrased the request a little more nicely), I’d be happy to send you an email with the necessary files.

Leave a Reply