Sunday, December 13, 2015

WebSocket4Net Extensions: OpenAsync

I recently talked about .NET WebSocket Libraries, and how I like using WebSocket4Net as a .NET WebSocket client. That library is great, but really wanted it to have two additional features:

  1. Retry logic for opening a connection.
  2. An OpenAsync method.

...so I created an extension method that does both!

WebSocket4Net Extensions

public static class WebSocketExtensions
{
    public static async Task OpenAsync(
        this WebSocket webSocket,
        int retryCount = 5,
        CancellationToken cancelToken = default(CancellationToken))
    {
        var failCount = 0;
        var exceptions = new List<Exception>(retryCount);
 
        var openCompletionSource = new TaskCompletionSource<bool>();
        cancelToken.Register(() => openCompletionSource.TrySetCanceled());
 
        EventHandler openHandler = (s, e) => openCompletionSource.TrySetResult(true);
 
        EventHandler<ErrorEventArgs> errorHandler = (s, e) =>
        {
            if (exceptions.All(ex => ex.Message != e.Exception.Message))
            {
                exceptions.Add(e.Exception);
            }
        };
 
        EventHandler closeHandler = (s, e) =>
        {
            if (cancelToken.IsCancellationRequested)
            {
                openCompletionSource.TrySetCanceled();
            }
            else if (++failCount < retryCount)
            {
                webSocket.Open();
            }
            else
            {
                var exception = exceptions.Count == 1
                    ? exceptions.Single()
                    : new AggregateException(exceptions);
 
                var webSocketException = new WebSocketException(
                    "Unable to connect", 
                    exception);
 
                openCompletionSource.TrySetException(webSocketException);
            }
        };
 
        try
        {
            webSocket.Opened += openHandler;
            webSocket.Error += errorHandler;
            webSocket.Closed += closeHandler;
 
            webSocket.Open();
 
            await openCompletionSource.Task.ConfigureAwait(false);
        }
        finally
        {
            webSocket.Opened -= openHandler;
            webSocket.Error -= errorHandler;
            webSocket.Closed -= closeHandler;
        }
    }

Enjoy,
Tom

No comments:

Post a Comment

Real Time Web Analytics