Skip to content

Commit 72adcda

Browse files
committed
Added cancellation of requests using CancellationToken
1 parent 92f16b7 commit 72adcda

File tree

2 files changed

+42
-10
lines changed

2 files changed

+42
-10
lines changed

CSharpHTTPClient/Client.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010
using System.Web.Script.Serialization;
1111
using System.Web;
12+
using System.Threading;
1213

1314
namespace SendGrid.CSharp.HTTP.Client
1415
{
@@ -258,6 +259,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
258259

259260
if( Enum.IsDefined(typeof(Methods), binder.Name.ToUpper()))
260261
{
262+
CancellationToken cancellationToken = CancellationToken.None;
261263
string queryParams = null;
262264
string requestBody = null;
263265
int i = 0;
@@ -278,9 +280,13 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
278280
{
279281
AddRequestHeader((Dictionary<string, string>)obj);
280282
}
283+
else if (name == "cancellationToken")
284+
{
285+
cancellationToken = (CancellationToken)obj;
286+
}
281287
i++;
282288
}
283-
result = RequestAsync(binder.Name.ToUpper(), requestBody: requestBody, queryParams: queryParams).ConfigureAwait(false);
289+
result = RequestAsync(binder.Name.ToUpper(), cancellationToken, requestBody: requestBody, queryParams: queryParams).ConfigureAwait(false);
284290
return true;
285291
}
286292
else
@@ -296,21 +302,23 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
296302
/// </summary>
297303
/// <param name="client">Client object ready for communication with API</param>
298304
/// <param name="request">The parameters for the API call</param>
305+
/// <param name="cancellationToken">A token that allows cancellation of the http request</param>
299306
/// <returns>Response object</returns>
300-
public async virtual Task<Response> MakeRequest(HttpClient client, HttpRequestMessage request)
307+
public async virtual Task<Response> MakeRequest(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken)
301308
{
302-
HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);
309+
HttpResponseMessage response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
303310
return new Response(response.StatusCode, response.Content, response.Headers);
304311
}
305312

306313
/// <summary>
307314
/// Prepare for async call to the API server
308315
/// </summary>
309316
/// <param name="method">HTTP verb</param>
317+
/// <param name="cancellationToken">A token that allows cancellation of the http request</param>
310318
/// <param name="requestBody">JSON formatted string</param>
311319
/// <param name="queryParams">JSON formatted queary paramaters</param>
312320
/// <returns>Response object</returns>
313-
private async Task<Response> RequestAsync(string method, string requestBody = null, string queryParams = null)
321+
private async Task<Response> RequestAsync(string method, CancellationToken cancellationToken, string requestBody = null, string queryParams = null)
314322
{
315323
using (var client = BuildHttpClient())
316324
{
@@ -356,9 +364,13 @@ private async Task<Response> RequestAsync(string method, string requestBody = nu
356364
RequestUri = new Uri(endpoint),
357365
Content = content
358366
};
359-
return await MakeRequest(client, request).ConfigureAwait(false);
367+
return await MakeRequest(client, request, cancellationToken).ConfigureAwait(false);
360368

361369
}
370+
catch(TaskCanceledException)
371+
{
372+
throw;
373+
}
362374
catch (Exception ex)
363375
{
364376
HttpResponseMessage response = new HttpResponseMessage();

UnitTest/UnitTest.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Net.Http;
77
using System.Text;
88
using System.Net;
9+
using System.Threading;
910

1011
namespace UnitTest
1112
{
@@ -17,12 +18,19 @@ public MockClient(string host, Dictionary<string, string> requestHeaders = null,
1718
{
1819
}
1920

20-
public async override Task<Response> MakeRequest(HttpClient client, HttpRequestMessage request)
21+
public override Task<Response> MakeRequest(HttpClient client, HttpRequestMessage request, CancellationToken cancellationToken)
2122
{
22-
HttpResponseMessage response = new HttpResponseMessage();
23-
response.Content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json");
24-
response.StatusCode = HttpStatusCode.OK;
25-
return new Response(response.StatusCode, response.Content, response.Headers);
23+
return Task.Factory.StartNew(() =>
24+
{
25+
26+
HttpResponseMessage response = new HttpResponseMessage();
27+
response.Content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json");
28+
response.StatusCode = HttpStatusCode.OK;
29+
30+
cancellationToken.ThrowIfCancellationRequested();
31+
32+
return new Response(response.StatusCode, response.Content, response.Headers);
33+
}, cancellationToken);
2634
}
2735
}
2836

@@ -74,5 +82,17 @@ public async void TestMethodCall()
7482
var content = new StringContent("{'test': 'test_content'}", Encoding.UTF8, "application/json");
7583
Assert.AreEqual(response.Body.ReadAsStringAsync().Result, content.ReadAsStringAsync().Result);
7684
}
85+
86+
[Test]
87+
[ExpectedException(typeof(TaskCanceledException))]
88+
public async void TestMethodCallWithCancellationToken()
89+
{
90+
var cancellationTokenSource = new CancellationTokenSource();
91+
cancellationTokenSource.Cancel();
92+
93+
var host = "http://api.test.com";
94+
dynamic test_client = new MockClient(host: host);
95+
Response response = await test_client.get(cancellationToken: cancellationTokenSource.Token);
96+
}
7797
}
7898
}

0 commit comments

Comments
 (0)