7
\$\begingroup\$

I really like using the new TAP pattern in .Net 4.5. and I am updating some of my older projects to use it.

One of my old patterns was to use EAP with WCF so I could have functions that could take longer than 60 seconds (the default timeout for WCF) to complete without doing custom setup on the client side App.Conifg.

Here is a simple example of what I would do.

[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IService1
{
    [OperationContract(IsOneWay = true)]
    void Test(int arg);
}

[ServiceContract]
interface ICallback
{
    [OperationContract(IsOneWay=true)]
    void Callback(int arg);
}

public class Service1 : IService1
{
    public void Test(int arg)
    {
        var callback = OperationContext.Current.GetCallbackChannel<ICallback>();
        Thread.Sleep(61000); //Sleep for 61 sec.
        callback.Callback(arg + 1);
    }
}

Now I want to put a wrapper around my EAP pattern and turn it in to a TAP pattern (as an aside, just returning a TAP pattern like public Task<int> Test(int arg) will still have the 60 second time limit but it does work)

Here is the solution I came up with, this code would be run on the client.

static class ProxyClient
{
    private delegate void CallbackDelegate(int arg);

    private class CallbackClass : IService1Callback
    {
        public event CallbackDelegate CallbackEvent;

        void IService1Callback.Callback(int arg)
        {
            var tmp = CallbackEvent;
            if (tmp != null)
                tmp(arg);
        }
    }

    public static async Task<int> Test(int arg)
    {
        var callback = new CallbackClass();
        var client = new Service1Client(new InstanceContext(callback));
        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();

        //start listening for the completion event
        callback.CallbackEvent += (resultArg) => tcs.TrySetResult(resultArg);

        client.Test(arg);

        //wait for the result
        var result = await tcs.Task;

        //close the connection
        client.Close();

        return result;
    }
}

The main concern I had was receiving the completion callback for another invocation if a connection was used more than once. So I create and breakdown the connection from inside the function entirely.

I would love to hear input if this is a good idea, or is there a better way to accomplish long running tasks in WCF without having to modify timeout values client-side at the time of proxy creation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.