Exception Handling with Task Parallel Library Based WCF Services

Exception handling can be different across the .NET Framework.  Custom exceptions often augment the Exception base class.  In Task Parallel Library (TPL) Exceptions can pile-up fast; so TPL's custom Exception, the AggregateException, includes properties developers use to handle numerous Exceptions.  Windows Communication Foundation (WCF) must often share Exceptions with a client on the other end of the network.  WCF includes custom exceptions for packaging and transporting a serialized Exception.

Bridging TPL and WCF exception handling models requires understanding both models.  The following paragraphs will demonstrate some techniques to bring the two models together.

WCF and TPL Together

Prior articles on this site demonstrated how these two technologies can play together.  How the technologies are combined influences how Exceptions handling is configured.  So here are some configuration assumptions.

Tasks are the TPL Core.  Tasks implement the IAsyncResult.  IAsyncResult is the Asynchronous Programming Model (APM) core.  A developer using TPL with WCF will likely utilize the WCF APM.  Signature sample WCF APM code follows.

public IAsyncResult BeginTestServiceMethod(RequestObj req, AsyncCallback callback, object asyncState)
{
           
    return new Func<ResponseObj> (
        () =>
        {
            throw new Exception("Test exception generated");
        }
    ).ToStartedTask<ResponseObj>(callback,asyncState);
            
}
 
public ResponseObj EndTestServiceMethod(IAsyncResult result)
{
    return result.ToResultOrException<ResponseObj>();
}
 

Notice the Begin portion that starts the operation and the End portion that returns the Result to the client.  A Callback method joins the functions together.  The Operation state is stored inside the Task instance. 

TPL Continuations glue the Task to the Callback.  I'll talk more about Continuations later in the article.  The RunSynchronously option ensures that the Continuation is configured to run on the same thread as the Task.  Running synchronously is not a guarantee though.  If everything is operating normally this will be the case.  However if the Task has faulted, the Continuation will be scheduled on another Thread. 

Thus begins the Exception Odyssey.

TPL Exceptions

A complete TPL Exceptions review is beyond the scope of this article, so the overview follows.

As stated earlier TPL stores Exceptions in an AggregateException class.  An AggregateException is embedded in the Task Exception property.  The following code demonstrates accessing the Exception property.

if (t.IsFaulted) 
{
    t.Exception.Handle((e) => { return true; });
    //Log to the Event log or some other place
}
 
task.Exception.Flatten().Message
 

Normally, uncaught Exceptions will terminate an application.  TPL handles Exceptions differently.  TPL requires an Exception to be observed.  So simply inspecting an Exception is enough to handle the exception.

Of course, most developers will want to do more than inspect an exception.  So, for example, a developer may want to capture an Exception Message and write it to the Event Log.  The previous TPL code demonstrates AggregateExeption properties to assist with this endeavor.

As mentioned earlier AggregateExceptions can become large.  A TPL operation waiting on a handful of faulting Tasks will accumulate a lot of Exceptions.  Special care must be taken with WCF to not only handle Exceptions, but also to properly package the Exceptions.

WCF Exception Contracts

WCF's core comprises sending and receiving Messages.  WCF developers are careful about Message sizes.  Configuring a large Message size may unnecessarily consume system resources.  DataContracts dictate message formatting and message size.  WCF Exceptions are a sort of DataContract.  Services embed Exception Contracts alongside Data Contracts.  The following code demonstrates how to configure a WCF Exception Contract.

[OperationContractAttribute(AsyncPattern = true, Action = "TestServiceMethod", Name = "TestServiceMethod", ReplyAction = "TestServiceMethodReply")]
[FaultContract(typeof(TestServiceFaultContract))]
IAsyncResult BeginTestServiceMethod(RequestObj req, AsyncCallback callback, object asyncState);
 

The FaultContract attribute ensures that the Exception Contract will appear in the Services' WSDL .

Large Exceptions sent back to a WCF client may mean large messages.  SOAP Services include special Exception formatting.  WCF hides this mess from the developer.   The following code demonstrates how to package a WCF Exception.

public static T ToResultOrException<T>(this IAsyncResult result)
{
    var task = result as Task<T>;
 
    if (task.IsFaulted)
    {
        throw new FaultException<TestServiceFaultContract>
            (new TestServiceFaultContract() 
            { 
                FaultCode = 1
                , FaultMessage = task.Exception.Flatten().Message }
                , new FaultReason("Because I felt like it")); 
    }
 
    return task.Result;
}
 

All WCF Exceptions are packaged in a FaultException.  In the example; the code lives inside an Extension function that is attached to an IAsyncResult.  As stated earlier a Task is an IAsyncResult.  The Extension function standardizes how Results are propagated back to the Client.  If the Task is Faulted the Exception is packaged and an new FaultException is thrown.  Otherwise the Task's Result is returned.  In most implementations there may be further Result packaging.

A client receiving the Exception deals only with another Exception class rather than wading through the XML.  Clients receive a CommunicationException, but can find more Exception information on properties throughout the custom Exception.  Some of those properties are demonstrated in the Client-side code below.

try
{
 
    var r = c.TestServiceMethod(new RequestObj() { Payload = "Test first load" });
 
    Console.WriteLine(obj.ToString() + " result was " + r.PayloadResponse);
}
catch (FaultException ex)
{
    Console.WriteLine(ex.Message);
}
 

FaultException is the base WCF Exception.

Combining Continuations, Generics, Extension Methods, and Task completion inspections; a developer can create a sort of funnel into the Service core and then out of the Service core.  A Continuation allows a developer to offload some internal Exception processing like logging to the Event log.

The complete code solution accompanies this article.

Conclusion

If TPL and WCF are to work well together; a developer must think about how to bridge their two Exception models.  Understanding how each model works is the key to bridging the two models.  WCF requires special Exception packaging to move an Exception over the wire to the client.  TPL AggregateExceptions require observation or handling.

Resources

Specifying and Handling Faults in Contracts and Services



Related Articles

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

  • Do you know where your data is? Consumer cloud-based file sharing services store your sensitive company data on servers outside of your control, outside of your policy and regulatory guidelines – maybe even outside your country – and not managed by you. The potential for data leakage, security breaches, and harm to your business is enormous. Download this white paper to learn about file sync and share alternatives that allow you to manage and protect your sensitive data while integrating and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds