Skip to content

Commit

Permalink
Handle task cancellation in the .NET client
Browse files Browse the repository at this point in the history
  • Loading branch information
abnanda1 committed Jun 29, 2013
1 parent f9d5662 commit 6a04fb5
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/Microsoft.AspNet.SignalR.Client.WinRT/Resources.resw
Expand Up @@ -147,6 +147,9 @@
<data name="Error_StartMustBeCalledBeforeDataCanBeSent" xml:space="preserve">
<value>The Start method must be called before data can be sent.</value>
</data>
<data name="Error_TaskCancelledException" xml:space="preserve">
<value>Request failed - task cancelled.</value>
</data>
<data name="Error_TransportFailedToConnect" xml:space="preserve">
<value>Transport failed trying to connect.</value>
</data>
Expand Down
11 changes: 10 additions & 1 deletion src/Microsoft.AspNet.SignalR.Client/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Microsoft.AspNet.SignalR.Client/Resources.resx
Expand Up @@ -147,6 +147,9 @@
<data name="Error_StartMustBeCalledBeforeDataCanBeSent" xml:space="preserve">
<value>The Start method must be called before data can be sent.</value>
</data>
<data name="Error_TaskCancelledException" xml:space="preserve">
<value>Request failed - task cancelled.</value>
</data>
<data name="Error_TransportFailedToConnect" xml:space="preserve">
<value>Transport failed trying to connect.</value>
</data>
Expand Down
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client.Http;
Expand Down Expand Up @@ -79,7 +80,8 @@ public void Start()
}
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed back to user.")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed back to user.")]
[SuppressMessage("Microsoft.Usage", "CA2201:ExceptionNotSufficientlySpecific", Justification = "Limited information about cancellation")]
private void Poll()
{
// This is to ensure that we do not accidently fire off another poll after being told to stop
Expand Down Expand Up @@ -108,9 +110,16 @@ private void Poll()
var next = TaskAsyncHelper.Empty;
Exception exception = null;
if (task.IsFaulted)
if (task.IsFaulted || task.IsCanceled)
{
exception = task.Exception.Unwrap();
if (task.IsCanceled)
{
exception = new Exception(Resources.Error_TaskCancelledException);
}
else
{
exception = task.Exception.Unwrap();
}
OnError(exception);
}
Expand Down
Expand Up @@ -79,8 +79,14 @@ private void Reconnect(IConnection connection, string data, CancellationToken di
});
}

public void OpenConnection(IConnection connection, Action<Exception> errorCallback)
{
OpenConnection(connection, null, CancellationToken.None, () => { }, errorCallback);
}

[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "We will refactor later.")]
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "We will refactor later.")]
[SuppressMessage("Microsoft.Usage", "CA2201:ExceptionNotSufficientlySpecific", Justification = "Limited information about cancellation")]
private void OpenConnection(IConnection connection,
string data,
CancellationToken disconnectToken,
Expand Down Expand Up @@ -108,9 +114,19 @@ private void Reconnect(IConnection connection, string data, CancellationToken di
}, isLongRunning: true).ContinueWith(task =>
{
if (task.IsFaulted)
if (task.IsFaulted || task.IsCanceled)
{
Exception exception = task.Exception.Unwrap();
Exception exception;
if (task.IsCanceled)
{
exception = new Exception(Resources.Error_TaskCancelledException);
}
else
{
exception = task.Exception.Unwrap();
}
if (!ExceptionHelper.IsRequestAborted(exception))
{
if (errorCallback != null)
Expand Down
53 changes: 52 additions & 1 deletion tests/Microsoft.AspNet.SignalR.Tests/Client/TransportFacts.cs
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNet.SignalR.Client.Http;
using Microsoft.AspNet.SignalR.Client.Transports;
Expand Down Expand Up @@ -84,6 +85,56 @@ public void ProcessResponseCapturesOnReceivedExceptions()
connection.VerifyAll();
}

[Fact]
public void CancelledTaskHandledinServerSentEvents()
{
var tcs = new TaskCompletionSource<IResponse>();
var wh = new TaskCompletionSource<Exception>();

tcs.TrySetCanceled();

var httpClient = new Mock<Microsoft.AspNet.SignalR.Client.Http.IHttpClient>();
var connection = new Mock<Microsoft.AspNet.SignalR.Client.IConnection>();

httpClient.Setup(c => c.Get(It.IsAny<string>(),
It.IsAny<Action<Client.Http.IRequest>>(), It.IsAny<bool>()))
.Returns(tcs.Task);

connection.SetupGet(c => c.ConnectionToken).Returns("foo");

var sse = new ServerSentEventsTransport(httpClient.Object);
sse.OpenConnection(connection.Object, (ex) =>
{
wh.TrySetResult(ex);
});

Assert.True(wh.Task.Wait(TimeSpan.FromSeconds(5)));
Assert.Equal("Request failed - task cancelled.", wh.Task.Result.Message);
}

[Fact]
public void CancelledTaskHandledinLongPolling()
{
var tcs = new TaskCompletionSource<IResponse>();
var wh = new TaskCompletionSource<Exception>();

tcs.TrySetCanceled();

var httpClient = new Mock<Microsoft.AspNet.SignalR.Client.Http.IHttpClient>();

httpClient.Setup(c => c.Post(It.IsAny<string>(),
It.IsAny<Action<Client.Http.IRequest>>(), It.IsAny<IDictionary<string, string>>(), It.IsAny<bool>()))
.Returns(tcs.Task);

var pollingHandler = new PollingRequestHandler(httpClient.Object);
pollingHandler.Start();

pollingHandler.OnError += (ex) => { wh.TrySetResult(ex); };

Assert.True(wh.Task.Wait(TimeSpan.FromSeconds(5)));
Assert.Equal("Request failed - task cancelled.", wh.Task.Result.Message);
}

[Fact]
public void SendCatchesOnReceivedExceptions()
{
Expand All @@ -106,7 +157,7 @@ public void SendCatchesOnReceivedExceptions()

httpClient.Setup(h => h.Post(It.IsAny<string>(),
It.IsAny<Action<Client.Http.IRequest>>(),
It.IsAny<IDictionary<string, string>>(),false))
It.IsAny<IDictionary<string, string>>(), false))
.Returns(TaskAsyncHelper.FromResult(response.Object));

connection.Setup(c => c.Trace(TraceLevels.Messages, It.IsAny<string>(), It.IsAny<object[]>()));
Expand Down

0 comments on commit 6a04fb5

Please sign in to comment.