From 0f4d702854a86085aa14c21d18a75d6f2621428f Mon Sep 17 00:00:00 2001 From: Evgeniy Kulakov Date: Wed, 19 Apr 2017 01:20:56 +0300 Subject: [PATCH] Add CancellationToken and .ConfigureAwait(false) --- .../ChatterClientTests.cs | 8 +- src/ChatterToolkitForNET/ChatterClient.cs | 76 +++++---- src/ChatterToolkitForNET/IChatterClient.cs | 21 ++- .../CommonTests.cs | 6 +- .../BulkTests.cs | 4 +- .../CommonTests.cs | 14 +- .../AuthenticationClient.cs | 25 +-- .../HttpContentCompressedDataExtensions.cs | 2 +- .../IAuthenticationClient.cs | 10 +- src/CommonLibrariesForNET/IJsonHttpClient.cs | 25 +-- src/CommonLibrariesForNET/IXmlHttpClient.cs | 9 +- .../Internals/BaseHttpClient.cs | 17 +- src/CommonLibrariesForNET/JsonHttpClient.cs | 49 +++--- src/CommonLibrariesForNET/XmlHttpClient.cs | 17 +- .../BulkForceClientTests.cs | 4 +- .../ForceClientTests.cs | 6 +- .../BulkForceClientTests.cs | 34 ++-- .../ForceClientTests.cs | 6 +- src/ForceToolkitForNET/ForceClient.cs | 161 +++++++++--------- src/ForceToolkitForNET/IForceClient.cs | 69 ++++---- 20 files changed, 286 insertions(+), 277 deletions(-) diff --git a/src/ChatterToolkitForNET.FunctionalTests/ChatterClientTests.cs b/src/ChatterToolkitForNET.FunctionalTests/ChatterClientTests.cs index 9f088dd8..7cb227e3 100644 --- a/src/ChatterToolkitForNET.FunctionalTests/ChatterClientTests.cs +++ b/src/ChatterToolkitForNET.FunctionalTests/ChatterClientTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Configuration; using System.Net; -using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using NUnit.Framework; using Salesforce.Chatter.Models; @@ -20,7 +20,7 @@ public class ChatterClientTests private static string _password = ConfigurationManager.AppSettings["Password"]; private AuthenticationClient _auth; - private ChatterClient _chatterClient; + private IChatterClient _chatterClient; [TestFixtureSetUp] public void Init() @@ -39,7 +39,7 @@ public void Init() ServicePointManager.SecurityProtocol |= (SecurityProtocolType)(SecurityProtocolTypeTls12 | SecurityProtocolTypeTls11); _auth = new AuthenticationClient(); - _auth.UsernamePasswordAsync(_consumerKey, _consumerSecret, _username, _password, TokenRequestEndpointUrl).Wait(); + _auth.UsernamePasswordAsync(_consumerKey, _consumerSecret, _username, _password, TokenRequestEndpointUrl, CancellationToken.None).Wait(); _chatterClient = new ChatterClient(_auth.InstanceUrl, _auth.AccessToken, _auth.ApiVersion); } @@ -226,7 +226,7 @@ public async Task Chatter_Get_Users_IsNotNull() } #region private functions - private async Task postFeedItem(ChatterClient chatter) + private async Task postFeedItem(IChatterClient chatter) { var me = await chatter.MeAsync(); var id = me.id; diff --git a/src/ChatterToolkitForNET/ChatterClient.cs b/src/ChatterToolkitForNET/ChatterClient.cs index e511a276..47b5013e 100644 --- a/src/ChatterToolkitForNET/ChatterClient.cs +++ b/src/ChatterToolkitForNET/ChatterClient.cs @@ -1,5 +1,6 @@ using System; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Salesforce.Chatter.Models; using Salesforce.Common; @@ -8,7 +9,8 @@ namespace Salesforce.Chatter { public class ChatterClient : IChatterClient, IDisposable { - private readonly JsonHttpClient _jsonHttpClient; + private readonly IJsonHttpClient _jsonHttpClient; + private readonly JsonHttpClient _fullJsonHttpClient; private readonly string _itemsOrElements; public ChatterClient(string instanceUrl, string accessToken, string apiVersion) @@ -18,105 +20,105 @@ public ChatterClient(string instanceUrl, string accessToken, string apiVersion) public ChatterClient(string instanceUrl, string accessToken, string apiVersion, HttpClient httpClient) { - _jsonHttpClient = new JsonHttpClient(instanceUrl, apiVersion, accessToken, httpClient); + _jsonHttpClient = _fullJsonHttpClient = new JsonHttpClient(instanceUrl, apiVersion, accessToken, httpClient); // A change in endpoint for feed item was introduced in v31 of the API. - _itemsOrElements = float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30 ? "feed-elements" : "feed-items"; + _itemsOrElements = float.Parse(_fullJsonHttpClient.GetApiVersion().Substring(1)) > 30 ? "feed-elements" : "feed-items"; } - public Task FeedsAsync() + public Task FeedsAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync("chatter/feeds"); + return _jsonHttpClient.HttpGetAsync("chatter/feeds", token); } - public Task MeAsync() + public Task MeAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync("chatter/users/me"); + return _jsonHttpClient.HttpGetAsync("chatter/users/me", token); } - public Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId) + public Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId, CancellationToken token) { // Feed items not available post v30.0 - if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) + if (float.Parse(_fullJsonHttpClient.GetApiVersion().Substring(1)) > 30.0) { - return _jsonHttpClient.HttpPostAsync(feedItemInput, "chatter/feed-elements"); + return _jsonHttpClient.HttpPostAsync(feedItemInput, "chatter/feed-elements", token); } - return _jsonHttpClient.HttpPostAsync(feedItemInput, string.Format("chatter/feeds/news/{0}/{1}", userId, _itemsOrElements)); + return _jsonHttpClient.HttpPostAsync(feedItemInput, string.Format("chatter/feeds/news/{0}/{1}", userId, _itemsOrElements), token); } - public Task PostFeedItemToObjectAsync(ObjectFeedItemInput envelope) + public Task PostFeedItemToObjectAsync(ObjectFeedItemInput envelope, CancellationToken token) { - return _jsonHttpClient.HttpPostAsync(envelope, "chatter/feed-elements/"); + return _jsonHttpClient.HttpPostAsync(envelope, "chatter/feed-elements/", token); } - public Task PostFeedItemWithAttachmentAsync(ObjectFeedItemInput envelope, byte[] fileContents, string fileName) + public Task PostFeedItemWithAttachmentAsync(ObjectFeedItemInput envelope, byte[] fileContents, string fileName, CancellationToken token) { - return _jsonHttpClient.HttpBinaryDataPostAsync("chatter/feed-elements/", envelope, fileContents, "feedElementFileUpload", fileName); + return _jsonHttpClient.HttpBinaryDataPostAsync("chatter/feed-elements/", envelope, fileContents, "feedElementFileUpload", fileName, token); } - public Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId) + public Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId, CancellationToken token) { - if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) + if (float.Parse(_fullJsonHttpClient.GetApiVersion().Substring(1)) > 30.0) { - return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/capabilities/comments/items", _itemsOrElements, feedId)); + return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/capabilities/comments/items", _itemsOrElements, feedId), token); } - return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/comments", _itemsOrElements, feedId)); + return _jsonHttpClient.HttpPostAsync(envelope, string.Format("chatter/{0}/{1}/comments", _itemsOrElements, feedId), token); } - public Task LikeFeedItemAsync(string feedId) + public Task LikeFeedItemAsync(string feedId, CancellationToken token) { - if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) + if (float.Parse(_fullJsonHttpClient.GetApiVersion().Substring(1)) > 30.0) { - return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/capabilities/chatter-likes/items", _itemsOrElements, feedId)); + return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/capabilities/chatter-likes/items", _itemsOrElements, feedId), token); } - return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/likes", _itemsOrElements, feedId)); + return _jsonHttpClient.HttpPostAsync(null, string.Format("chatter/{0}/{1}/likes", _itemsOrElements, feedId), token); } - public Task ShareFeedItemAsync(string feedId, string userId) + public Task ShareFeedItemAsync(string feedId, string userId, CancellationToken token) { var sharedFeedItem = new SharedFeedItemInput { SubjectId = userId }; - if (float.Parse(_jsonHttpClient.GetApiVersion().Substring(1)) > 30.0) + if (float.Parse(_fullJsonHttpClient.GetApiVersion().Substring(1)) > 30.0) { sharedFeedItem.OriginalFeedElementId = feedId; - return _jsonHttpClient.HttpPostAsync(sharedFeedItem, "chatter/feed-elements"); + return _jsonHttpClient.HttpPostAsync(sharedFeedItem, "chatter/feed-elements", token); } sharedFeedItem.OriginalFeedItemId = feedId; - return _jsonHttpClient.HttpPostAsync(sharedFeedItem, string.Format("chatter/feeds/user-profile/{0}/{1}", userId, _itemsOrElements)); + return _jsonHttpClient.HttpPostAsync(sharedFeedItem, string.Format("chatter/feeds/user-profile/{0}/{1}", userId, _itemsOrElements), token); } - public Task GetMyNewsFeedAsync(string query = "") + public Task GetMyNewsFeedAsync(string query = "", CancellationToken token = default(CancellationToken)) { var url = string.Format("chatter/feeds/news/me/{0}", _itemsOrElements); if (!string.IsNullOrEmpty(query)) url += string.Format("?q={0}", query); - return _jsonHttpClient.HttpGetAsync(url); + return _jsonHttpClient.HttpGetAsync(url, token); } - public Task GetGroupsAsync() + public Task GetGroupsAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync("chatter/groups"); + return _jsonHttpClient.HttpGetAsync("chatter/groups", token); } - public Task GetGroupFeedAsync(string groupId) + public Task GetGroupFeedAsync(string groupId, CancellationToken token) { - return _jsonHttpClient.HttpGetAsync(string.Format("chatter/feeds/record/{0}/{1}", _itemsOrElements, groupId)); + return _jsonHttpClient.HttpGetAsync(string.Format("chatter/feeds/record/{0}/{1}", _itemsOrElements, groupId), token); } - public Task GetUsersAsync() + public Task GetUsersAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync("chatter/users"); + return _jsonHttpClient.HttpGetAsync("chatter/users", token); } - public Task GetTopicsAsync() + public Task GetTopicsAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync("connect/topics"); + return _jsonHttpClient.HttpGetAsync("connect/topics", token); } public void Dispose() diff --git a/src/ChatterToolkitForNET/IChatterClient.cs b/src/ChatterToolkitForNET/IChatterClient.cs index 4cb5352a..6514d8fd 100644 --- a/src/ChatterToolkitForNET/IChatterClient.cs +++ b/src/ChatterToolkitForNET/IChatterClient.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Salesforce.Chatter.Models; @@ -5,14 +6,16 @@ namespace Salesforce.Chatter { public interface IChatterClient { - Task FeedsAsync(); - Task MeAsync(); - Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId); - Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId); - Task LikeFeedItemAsync(string feedId); - Task ShareFeedItemAsync(string feedId, string userId); - Task GetMyNewsFeedAsync(string query = ""); - Task GetGroupsAsync(); - Task GetGroupFeedAsync(string groupId); + Task FeedsAsync(CancellationToken token = default(CancellationToken)); + Task MeAsync(CancellationToken token = default(CancellationToken)); + Task PostFeedItemAsync(FeedItemInput feedItemInput, string userId, CancellationToken token = default(CancellationToken)); + Task PostFeedItemCommentAsync(FeedItemInput envelope, string feedId, CancellationToken token = default(CancellationToken)); + Task LikeFeedItemAsync(string feedId, CancellationToken token = default(CancellationToken)); + Task ShareFeedItemAsync(string feedId, string userId, CancellationToken token = default(CancellationToken)); + Task GetMyNewsFeedAsync(string query = "", CancellationToken token = default(CancellationToken)); + Task GetGroupsAsync(CancellationToken token = default(CancellationToken)); + Task GetGroupFeedAsync(string groupId, CancellationToken token = default(CancellationToken)); + Task GetUsersAsync(CancellationToken token = default(CancellationToken)); + Task GetTopicsAsync(CancellationToken token = default(CancellationToken)); } } \ No newline at end of file diff --git a/src/CommonLibrariesForNET.FunctionalTests/CommonTests.cs b/src/CommonLibrariesForNET.FunctionalTests/CommonTests.cs index 1d5f4646..1a2e9f6c 100644 --- a/src/CommonLibrariesForNET.FunctionalTests/CommonTests.cs +++ b/src/CommonLibrariesForNET.FunctionalTests/CommonTests.cs @@ -20,8 +20,8 @@ public class CommonTests private static string _username = ConfigurationManager.AppSettings["Username"]; private static string _password = ConfigurationManager.AppSettings["Password"]; - private AuthenticationClient _auth; - private JsonHttpClient _jsonHttpClient; + private IAuthenticationClient _auth; + private IJsonHttpClient _jsonHttpClient; [TestFixtureSetUp] public void Init() @@ -173,7 +173,7 @@ public async Task Upsert_New_CheckReturnInclude() public async Task BadTokenHandling() { var badToken = "badtoken"; - var serviceHttpClient = new JsonHttpClient(_auth.InstanceUrl, _auth.ApiVersion, badToken, new HttpClient()); + IJsonHttpClient serviceHttpClient = new JsonHttpClient(_auth.InstanceUrl, _auth.ApiVersion, badToken, new HttpClient()); const string query = "SELECT count() FROM Account"; diff --git a/src/CommonLibrariesForNET.UnitTests/BulkTests.cs b/src/CommonLibrariesForNET.UnitTests/BulkTests.cs index 7f064399..bbb76cbd 100644 --- a/src/CommonLibrariesForNET.UnitTests/BulkTests.cs +++ b/src/CommonLibrariesForNET.UnitTests/BulkTests.cs @@ -28,7 +28,7 @@ public async void Requests_CheckHttpRequestMessage_HttpGetXml() Assert.AreEqual(r.Headers.GetValues("X-SFDC-Session").First(), "accessToken"); }, new object())); - using (var httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) + using (IXmlHttpClient httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) { await httpClient.HttpGetAsync("brad"); } @@ -57,7 +57,7 @@ public async void Requests_CheckHttpRequestMessageAndResponseDeserialization_Htt }, testObject)); // pass in the object to be returned (Same object roundtripped here for simplicity) - using (var httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) + using (IXmlHttpClient httpClient = new XmlHttpClient("http://localhost:1899", "v32", "accessToken", client)) { var result = await httpClient.HttpPostAsync(testObject, "brad"); Assert.AreEqual(testObject.TestField, result.TestField); diff --git a/src/CommonLibrariesForNET.UnitTests/CommonTests.cs b/src/CommonLibrariesForNET.UnitTests/CommonTests.cs index 4f49f4ab..60bfedad 100644 --- a/src/CommonLibrariesForNET.UnitTests/CommonTests.cs +++ b/src/CommonLibrariesForNET.UnitTests/CommonTests.cs @@ -31,7 +31,7 @@ public async Task Auth_UsernamePassword_Check() Assert.AreEqual(r.Content.ToString(), "System.Net.Http.FormUrlEncodedContent"); })); - using (var auth = new AuthenticationClient(client)) + using (IAuthenticationClient auth = new AuthenticationClient(client)) { await auth.UsernamePasswordAsync(consumerKey, consumerSecret, username, password); @@ -58,7 +58,7 @@ public async Task Requests_CheckHttpRequestMessage_HttpGet() Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); })); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpGetAsync("wade"); } @@ -78,7 +78,7 @@ public async Task Requests_CheckHttpRequestMessage_HttpGet_WithNode() Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); })); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpGetAsync("wade"); } @@ -98,7 +98,7 @@ public async Task Requests_CheckHttpRequestMessage_HttpPost() Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); })); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpPostAsync(null, "wade"); } @@ -118,7 +118,7 @@ public async Task Requests_CheckHttpRequestMessage_HttpPatch() Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); })); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpPatchAsync(null, "wade"); } @@ -138,7 +138,7 @@ public async Task Requests_CheckHttpRequestMessage_HttpDelete() Assert.AreEqual(r.Headers.Authorization.ToString(), "Bearer accessToken"); })); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpDeleteAsync("wade"); } @@ -155,7 +155,7 @@ public async Task Requests_CheckCustomRequestsHeaders() client.DefaultRequestHeaders.Add("headername", "headervalue"); - using (var httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) + using (IJsonHttpClient httpClient = new JsonHttpClient("http://localhost:1899", "v36", "accessToken", client)) { await httpClient.HttpGetAsync("wade"); } diff --git a/src/CommonLibrariesForNET/AuthenticationClient.cs b/src/CommonLibrariesForNET/AuthenticationClient.cs index e0553002..5513b39b 100644 --- a/src/CommonLibrariesForNET/AuthenticationClient.cs +++ b/src/CommonLibrariesForNET/AuthenticationClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Salesforce.Common.Models.Json; @@ -32,12 +33,12 @@ public AuthenticationClient(HttpClient httpClient) ApiVersion = "v36.0"; } - public Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password) + public Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, CancellationToken token) { - return UsernamePasswordAsync(clientId, clientSecret, username, password, TokenRequestEndpointUrl); + return UsernamePasswordAsync(clientId, clientSecret, username, password, TokenRequestEndpointUrl, token); } - public async Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl) + public async Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl, CancellationToken token) { if (string.IsNullOrEmpty(clientId)) throw new ArgumentNullException("clientId"); if (string.IsNullOrEmpty(clientSecret)) throw new ArgumentNullException("clientSecret"); @@ -64,7 +65,7 @@ public async Task UsernamePasswordAsync(string clientId, string clientSecret, st request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); - var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); + var responseMessage = await _httpClient.SendAsync(request, token).ConfigureAwait(false); var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); if (responseMessage.IsSuccessStatusCode) @@ -82,12 +83,12 @@ public async Task UsernamePasswordAsync(string clientId, string clientSecret, st } } - public Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code) + public Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, CancellationToken token) { - return WebServerAsync(clientId, clientSecret, redirectUri, code, TokenRequestEndpointUrl); + return WebServerAsync(clientId, clientSecret, redirectUri, code, TokenRequestEndpointUrl, token); } - public async Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl) + public async Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl, CancellationToken token) { if (string.IsNullOrEmpty(clientId)) throw new ArgumentNullException("clientId"); if (string.IsNullOrEmpty(clientSecret)) throw new ArgumentNullException("clientSecret"); @@ -115,7 +116,7 @@ public async Task WebServerAsync(string clientId, string clientSecret, string re request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); - var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); + var responseMessage = await _httpClient.SendAsync(request, token).ConfigureAwait(false); var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); if (responseMessage.IsSuccessStatusCode) @@ -142,12 +143,12 @@ public async Task WebServerAsync(string clientId, string clientSecret, string re } } - public Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret = "") + public Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret = "", CancellationToken token = default(CancellationToken)) { - return TokenRefreshAsync(clientId, refreshToken, clientSecret, TokenRequestEndpointUrl); + return TokenRefreshAsync(clientId, refreshToken, clientSecret, TokenRequestEndpointUrl, token); } - public async Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret, string tokenRequestEndpointUrl) + public async Task TokenRefreshAsync(string clientId, string refreshToken, string clientSecret, string tokenRequestEndpointUrl, CancellationToken token) { var url = Common.FormatRefreshTokenUrl( tokenRequestEndpointUrl, @@ -163,7 +164,7 @@ public async Task TokenRefreshAsync(string clientId, string refreshToken, string request.Headers.UserAgent.ParseAdd(string.Concat(UserAgent, "/", ApiVersion)); - var responseMessage = await _httpClient.SendAsync(request).ConfigureAwait(false); + var responseMessage = await _httpClient.SendAsync(request, token).ConfigureAwait(false); var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); if (responseMessage.IsSuccessStatusCode) diff --git a/src/CommonLibrariesForNET/Extensions/HttpContentCompressedDataExtensions.cs b/src/CommonLibrariesForNET/Extensions/HttpContentCompressedDataExtensions.cs index cd3af245..31f53e57 100644 --- a/src/CommonLibrariesForNET/Extensions/HttpContentCompressedDataExtensions.cs +++ b/src/CommonLibrariesForNET/Extensions/HttpContentCompressedDataExtensions.cs @@ -38,7 +38,7 @@ public static async Task ReadAsDecompressedStringAsync(this HttpContent { var responseStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false); var unzippedContent = new GZipStream(responseStream, CompressionMode.Decompress); - content = await(new StreamReader(unzippedContent)).ReadToEndAsync(); + content = await new StreamReader(unzippedContent).ReadToEndAsync().ConfigureAwait(false); } else { diff --git a/src/CommonLibrariesForNET/IAuthenticationClient.cs b/src/CommonLibrariesForNET/IAuthenticationClient.cs index e961ccad..8614baea 100644 --- a/src/CommonLibrariesForNET/IAuthenticationClient.cs +++ b/src/CommonLibrariesForNET/IAuthenticationClient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; namespace Salesforce.Common @@ -8,9 +9,10 @@ public interface IAuthenticationClient : IDisposable string InstanceUrl { get; set; } string AccessToken { get; set; } string ApiVersion { get; set; } - Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password); - Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl); - Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code); - Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl); + string Id { get; set; } + Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, CancellationToken token = default(CancellationToken)); + Task UsernamePasswordAsync(string clientId, string clientSecret, string username, string password, string tokenRequestEndpointUrl, CancellationToken token = default(CancellationToken)); + Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, CancellationToken token = default(CancellationToken)); + Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl, CancellationToken token = default(CancellationToken)); } } diff --git a/src/CommonLibrariesForNET/IJsonHttpClient.cs b/src/CommonLibrariesForNET/IJsonHttpClient.cs index 46ecc9fb..8a0fb835 100644 --- a/src/CommonLibrariesForNET/IJsonHttpClient.cs +++ b/src/CommonLibrariesForNET/IJsonHttpClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Salesforce.Common.Models.Json; @@ -9,23 +10,23 @@ public interface IJsonHttpClient: IDisposable { // GET - Task HttpGetAsync(string urlSuffix); - Task HttpGetAsync(Uri uri); - Task> HttpGetAsync(string urlSuffix, string nodeName); - Task HttpGetRestApiAsync(string apiName); + Task HttpGetAsync(string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpGetAsync(Uri uri, CancellationToken token = default(CancellationToken)); + Task> HttpGetAsync(string urlSuffix, string nodeName, CancellationToken token = default(CancellationToken)); + Task HttpGetRestApiAsync(string apiName, CancellationToken token = default(CancellationToken)); // POST - Task HttpPostAsync(object inputObject, string urlSuffix); - Task HttpPostAsync(object inputObject, Uri uri); - Task HttpPostRestApiAsync(string apiName, object inputObject); - Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName); + Task HttpPostAsync(object inputObject, string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpPostAsync(object inputObject, Uri uri, CancellationToken token = default(CancellationToken)); + Task HttpPostRestApiAsync(string apiName, object inputObject, CancellationToken token = default(CancellationToken)); + Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName, CancellationToken token = default(CancellationToken)); // PATCH - Task HttpPatchAsync(object inputObject, string urlSuffix); - Task HttpPatchAsync(object inputObject, Uri uri); + Task HttpPatchAsync(object inputObject, string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpPatchAsync(object inputObject, Uri uri, CancellationToken token = default(CancellationToken)); // DELETE - Task HttpDeleteAsync(string urlSuffix); - Task HttpDeleteAsync(Uri uri); + Task HttpDeleteAsync(string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpDeleteAsync(Uri uri, CancellationToken token = default(CancellationToken)); } } \ No newline at end of file diff --git a/src/CommonLibrariesForNET/IXmlHttpClient.cs b/src/CommonLibrariesForNET/IXmlHttpClient.cs index 8dc4a5dc..39377cfa 100644 --- a/src/CommonLibrariesForNET/IXmlHttpClient.cs +++ b/src/CommonLibrariesForNET/IXmlHttpClient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; namespace Salesforce.Common @@ -6,11 +7,11 @@ namespace Salesforce.Common public interface IXmlHttpClient: IDisposable { // GET - Task HttpGetAsync(string urlSuffix); - Task HttpGetAsync(Uri uri); + Task HttpGetAsync(string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpGetAsync(Uri uri, CancellationToken token = default(CancellationToken)); // POST - Task HttpPostAsync(object inputObject, string urlSuffix); - Task HttpPostAsync(object inputObject, Uri uri); + Task HttpPostAsync(object inputObject, string urlSuffix, CancellationToken token = default(CancellationToken)); + Task HttpPostAsync(object inputObject, Uri uri, CancellationToken token = default(CancellationToken)); } } diff --git a/src/CommonLibrariesForNET/Internals/BaseHttpClient.cs b/src/CommonLibrariesForNET/Internals/BaseHttpClient.cs index 3af4af7b..457cf37b 100644 --- a/src/CommonLibrariesForNET/Internals/BaseHttpClient.cs +++ b/src/CommonLibrariesForNET/Internals/BaseHttpClient.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Salesforce.Common.Internals @@ -43,9 +44,9 @@ public string GetApiVersion() return ApiVersion; } - protected async Task HttpGetAsync(Uri uri) + protected async Task HttpGetAsync(Uri uri, CancellationToken token) { - var responseMessage = await HttpClient.GetAsync(uri).ConfigureAwait(false); + var responseMessage = await HttpClient.GetAsync(uri, token).ConfigureAwait(false); if (responseMessage.StatusCode == HttpStatusCode.NoContent) { return string.Empty; @@ -60,11 +61,11 @@ protected async Task HttpGetAsync(Uri uri) throw new BaseHttpClientException(response, responseMessage.StatusCode); } - protected async Task HttpPostAsync(string payload, Uri uri) + protected async Task HttpPostAsync(string payload, Uri uri, CancellationToken token) { var content = new StringContent(payload, Encoding.UTF8, _contentType); - var responseMessage = await HttpClient.PostAsync(uri, content).ConfigureAwait(false); + var responseMessage = await HttpClient.PostAsync(uri, content, token).ConfigureAwait(false); if (responseMessage.StatusCode == HttpStatusCode.NoContent) { return string.Empty; @@ -79,7 +80,7 @@ protected async Task HttpPostAsync(string payload, Uri uri) throw new BaseHttpClientException(response, responseMessage.StatusCode); } - protected async Task HttpPatchAsync(string payload, Uri uri) + protected async Task HttpPatchAsync(string payload, Uri uri, CancellationToken token) { var content = new StringContent(payload, Encoding.UTF8, _contentType); @@ -90,7 +91,7 @@ protected async Task HttpPatchAsync(string payload, Uri uri) Content = content }; - var responseMessage = await HttpClient.SendAsync(request).ConfigureAwait(false); + var responseMessage = await HttpClient.SendAsync(request, token).ConfigureAwait(false); if (responseMessage.StatusCode == HttpStatusCode.NoContent) { return string.Empty; @@ -105,9 +106,9 @@ protected async Task HttpPatchAsync(string payload, Uri uri) throw new BaseHttpClientException(response, responseMessage.StatusCode); } - protected async Task HttpDeleteAsync(Uri uri) + protected async Task HttpDeleteAsync(Uri uri, CancellationToken token) { - var responseMessage = await HttpClient.DeleteAsync(uri).ConfigureAwait(false); + var responseMessage = await HttpClient.DeleteAsync(uri, token).ConfigureAwait(false); if (responseMessage.StatusCode == HttpStatusCode.NoContent) { return string.Empty; diff --git a/src/CommonLibrariesForNET/JsonHttpClient.cs b/src/CommonLibrariesForNET/JsonHttpClient.cs index 8b0b978a..723cb0ac 100644 --- a/src/CommonLibrariesForNET/JsonHttpClient.cs +++ b/src/CommonLibrariesForNET/JsonHttpClient.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -31,17 +32,17 @@ private static ForceException ParseForceException(string responseMessage) // GET - public async Task HttpGetAsync(string urlSuffix) + public Task HttpGetAsync(string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpGetAsync(url); + return HttpGetAsync(url, token); } - public async Task HttpGetAsync(Uri uri) + public async Task HttpGetAsync(Uri uri, CancellationToken token) { try { - var response = await HttpGetAsync(uri); + var response = await HttpGetAsync(uri, token).ConfigureAwait(false); var jToken = JToken.Parse(response); if (jToken.Type == JTokenType.Array) { @@ -65,7 +66,7 @@ public async Task HttpGetAsync(Uri uri) } } - public async Task> HttpGetAsync(string urlSuffix, string nodeName) + public async Task> HttpGetAsync(string urlSuffix, string nodeName, CancellationToken token) { string next = null; var records = new List(); @@ -79,7 +80,7 @@ public async Task> HttpGetAsync(string urlSuffix, string nodeName) } try { - var response = await HttpGetAsync(url); + var response = await HttpGetAsync(url, token).ConfigureAwait(false); var jObject = JObject.Parse(response); var jToken = jObject.GetValue(nodeName); next = (jObject.GetValue("nextRecordsUrl") != null) ? jObject.GetValue("nextRecordsUrl").ToString() : null; @@ -95,21 +96,21 @@ public async Task> HttpGetAsync(string urlSuffix, string nodeName) return records; } - public async Task HttpGetRestApiAsync(string apiName) + public Task HttpGetRestApiAsync(string apiName, CancellationToken token) { var url = Common.FormatRestApiUrl(apiName, InstanceUrl); - return await HttpGetAsync(url); + return HttpGetAsync(url, token); } // POST - public async Task HttpPostAsync(object inputObject, string urlSuffix) + public Task HttpPostAsync(object inputObject, string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpPostAsync(inputObject, url); + return HttpPostAsync(inputObject, url, token); } - public async Task HttpPostAsync(object inputObject, Uri uri) + public async Task HttpPostAsync(object inputObject, Uri uri, CancellationToken token) { var json = JsonConvert.SerializeObject(inputObject, Formatting.None, @@ -121,7 +122,7 @@ public async Task HttpPostAsync(object inputObject, Uri uri) }); try { - var response = await HttpPostAsync(json, uri); + var response = await HttpPostAsync(json, uri, token).ConfigureAwait(false); return JsonConvert.DeserializeObject(response); } catch (BaseHttpClientException e) @@ -130,13 +131,13 @@ public async Task HttpPostAsync(object inputObject, Uri uri) } } - public async Task HttpPostRestApiAsync(string apiName, object inputObject) + public Task HttpPostRestApiAsync(string apiName, object inputObject, CancellationToken token) { var url = Common.FormatRestApiUrl(apiName, InstanceUrl); - return await HttpPostAsync(inputObject, url); + return HttpPostAsync(inputObject, url, token); } - public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName) + public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName, CancellationToken token) { // BRAD: I think we should probably, in time, refactor multipart and binary support to the BaseHttpClient. // For now though, I just left this in here. @@ -161,7 +162,7 @@ public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputOb byteArrayContent.Headers.Add("Content-Disposition", string.Format("form-data; name=\"{0}\"; filename=\"{1}\"", headerName, fileName)); content.Add(byteArrayContent, headerName, fileName); - var responseMessage = await HttpClient.PostAsync(uri, content).ConfigureAwait(false); + var responseMessage = await HttpClient.PostAsync(uri, content, token).ConfigureAwait(false); var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); if (responseMessage.IsSuccessStatusCode) @@ -174,13 +175,13 @@ public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputOb // PATCH - public async Task HttpPatchAsync(object inputObject, string urlSuffix) + public Task HttpPatchAsync(object inputObject, string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpPatchAsync(inputObject, url); + return HttpPatchAsync(inputObject, url, token); } - public async Task HttpPatchAsync(object inputObject, Uri uri) + public async Task HttpPatchAsync(object inputObject, Uri uri, CancellationToken token) { var json = JsonConvert.SerializeObject(inputObject, Formatting.None, @@ -192,7 +193,7 @@ public async Task HttpPatchAsync(object inputObject, Uri uri) }); try { - var response = await base.HttpPatchAsync(json, uri); + var response = await base.HttpPatchAsync(json, uri, token).ConfigureAwait(false); return string.IsNullOrEmpty(response) ? new SuccessResponse{ Id = "", Errors = "", Success = true } : JsonConvert.DeserializeObject(response); @@ -205,17 +206,17 @@ public async Task HttpPatchAsync(object inputObject, Uri uri) // DELETE - public async Task HttpDeleteAsync(string urlSuffix) + public Task HttpDeleteAsync(string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpDeleteAsync(url); + return HttpDeleteAsync(url, token); } - public new async Task HttpDeleteAsync(Uri uri) + public new async Task HttpDeleteAsync(Uri uri, CancellationToken token) { try { - await base.HttpDeleteAsync(uri); + await base.HttpDeleteAsync(uri, token).ConfigureAwait(false); return true; } catch (BaseHttpClientException e) diff --git a/src/CommonLibrariesForNET/XmlHttpClient.cs b/src/CommonLibrariesForNET/XmlHttpClient.cs index 9b8b098d..ee152c95 100644 --- a/src/CommonLibrariesForNET/XmlHttpClient.cs +++ b/src/CommonLibrariesForNET/XmlHttpClient.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; @@ -24,17 +25,17 @@ public XmlHttpClient(string instanceUrl, string apiVersion, string accessToken, // GET - public async Task HttpGetAsync(string urlSuffix) + public Task HttpGetAsync(string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpGetAsync(url); + return HttpGetAsync(url, token); } - public async Task HttpGetAsync(Uri uri) + public async Task HttpGetAsync(Uri uri, CancellationToken token) { try { - var response = await HttpGetAsync(uri); + var response = await HttpGetAsync(uri, token).ConfigureAwait(false); return DeserializeXmlString(response); } catch (BaseHttpClientException e) @@ -45,18 +46,18 @@ public async Task HttpGetAsync(Uri uri) // POST - public async Task HttpPostAsync(object inputObject, string urlSuffix) + public Task HttpPostAsync(object inputObject, string urlSuffix, CancellationToken token) { var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); - return await HttpPostAsync(inputObject, url); + return HttpPostAsync(inputObject, url, token); } - public async Task HttpPostAsync(object inputObject, Uri uri) + public async Task HttpPostAsync(object inputObject, Uri uri, CancellationToken token) { var postBody = SerializeXmlObject(inputObject); try { - var response = await HttpPostAsync(postBody, uri); + var response = await HttpPostAsync(postBody, uri, token).ConfigureAwait(false); return DeserializeXmlString(response); } catch (BaseHttpClientException e) diff --git a/src/ForceToolkitForNET.FunctionalTests/BulkForceClientTests.cs b/src/ForceToolkitForNET.FunctionalTests/BulkForceClientTests.cs index fce5528b..d1b29e58 100644 --- a/src/ForceToolkitForNET.FunctionalTests/BulkForceClientTests.cs +++ b/src/ForceToolkitForNET.FunctionalTests/BulkForceClientTests.cs @@ -19,8 +19,8 @@ public class BulkForceClientTests private static string _password = ConfigurationManager.AppSettings["Password"]; private static string _organizationId = ConfigurationManager.AppSettings["OrganizationId"]; - private AuthenticationClient _auth; - private ForceClient _client; + private IAuthenticationClient _auth; + private IForceClient _client; [TestFixtureSetUp] public void Init() diff --git a/src/ForceToolkitForNET.FunctionalTests/ForceClientTests.cs b/src/ForceToolkitForNET.FunctionalTests/ForceClientTests.cs index 71b926be..0cb04b68 100644 --- a/src/ForceToolkitForNET.FunctionalTests/ForceClientTests.cs +++ b/src/ForceToolkitForNET.FunctionalTests/ForceClientTests.cs @@ -23,8 +23,8 @@ public class ForceClientTests private static string _password = ConfigurationManager.AppSettings["Password"]; private static string _organizationId = ConfigurationManager.AppSettings["OrganizationId"]; - private AuthenticationClient _auth; - private ForceClient _client; + private IAuthenticationClient _auth; + private IForceClient _client; [TestFixtureSetUp] public void Init() @@ -88,7 +88,7 @@ public async Task Query_Accounts_Continuation() Assert.AreNotEqual(contacts, nextContacts); } - public async Task CreateLotsOfAccounts(ForceClient forceClient) + public async Task CreateLotsOfAccounts(IForceClient forceClient) { var account = new Account { Name = "Test Account", Description = "New Account Description" }; diff --git a/src/ForceToolkitForNET.UnitTests/BulkForceClientTests.cs b/src/ForceToolkitForNET.UnitTests/BulkForceClientTests.cs index 2ba5dcdc..008a62e8 100644 --- a/src/ForceToolkitForNET.UnitTests/BulkForceClientTests.cs +++ b/src/ForceToolkitForNET.UnitTests/BulkForceClientTests.cs @@ -17,7 +17,7 @@ public class BulkForceClientTests [ExpectedException(typeof (ArgumentNullException))] public async void RunJobAndPoll_NullObjectName_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.RunJobAndPollAsync(null, BulkConstants.OperationType.Insert, new List>()); // expects exception @@ -27,7 +27,7 @@ public async void RunJobAndPoll_NullObjectName_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void RunJobAndPoll_NullBatchList_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.RunJobAndPollAsync>>("Account", BulkConstants.OperationType.Insert, null); // expects exception @@ -37,7 +37,7 @@ public async void RunJobAndPoll_NullBatchList_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void RunJob_NullObjectName_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.RunJobAsync(null, BulkConstants.OperationType.Insert, new List>()); // expects exception @@ -47,7 +47,7 @@ public async void RunJob_NullObjectName_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void RunJob_NullBatchList_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.RunJobAsync>>("Account", BulkConstants.OperationType.Insert, null); // expects exception @@ -57,7 +57,7 @@ public async void RunJob_NullBatchList_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void CreateJobAsync_NullObjectName_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.CreateJobAsync(null, BulkConstants.OperationType.Insert); // expects exception @@ -67,7 +67,7 @@ public async void CreateJobAsync_NullObjectName_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void CreateJobBatchAsync_NullJobId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.CreateJobBatchAsync((string)null, new SObjectList()); // expects exception @@ -77,7 +77,7 @@ public async void CreateJobBatchAsync_NullJobId_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void CreateJobBatchAsync_NullJobInfo_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.CreateJobBatchAsync((JobInfoResult)null, new SObjectList()); // expects exception @@ -87,7 +87,7 @@ public async void CreateJobBatchAsync_NullJobInfo_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void CreateJobBatchAsync_NullObjectList_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.CreateJobBatchAsync>("testId", null); // expects exception @@ -97,7 +97,7 @@ public async void CreateJobBatchAsync_NullObjectList_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void PollJobAsync_NullJobInfo_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.PollJobAsync((JobInfoResult)null); // expects exception @@ -107,7 +107,7 @@ public async void PollJobAsync_NullJobInfo_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void PollJobAsync_NullJobId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.PollJobAsync((string)null); // expects exception @@ -117,7 +117,7 @@ public async void PollJobAsync_NullJobId_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void PollBatchAsync_NullBatchInfo_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.PollBatchAsync(null); // expects exception @@ -127,7 +127,7 @@ public async void PollBatchAsync_NullBatchInfo_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void PollBatchAsync_NullBatchId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.PollBatchAsync(null, "test"); // expects exception @@ -137,7 +137,7 @@ public async void PollBatchAsync_NullBatchId_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void PollBatchAsync_NullJobId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.PollBatchAsync("test", null); // expects exception @@ -147,7 +147,7 @@ public async void PollBatchAsync_NullJobId_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void GetBatchResultAsync_NullBatchInfo_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.GetBatchResultAsync(null); // expects exception @@ -157,7 +157,7 @@ public async void GetBatchResultAsync_NullBatchInfo_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void GetBatchResultAsync_NullBatchId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.GetBatchResultAsync(null, "test"); // expects exception @@ -167,7 +167,7 @@ public async void GetBatchResultAsync_NullBatchId_ArgumentNullException() [ExpectedException(typeof(ArgumentNullException))] public async void GetBatchResultAsync_NullJobId_ArgumentNullException() { - var client = new ForceClient("test", "test", "v32"); + IForceClient client = new ForceClient("test", "test", "v32"); await client.GetBatchResultAsync("test", null); // expects exception @@ -298,7 +298,7 @@ public async void RunJobAndPoll_GoodData_CompleteRunThroughSucceeds() }; var httpClient = new HttpClient(new BulkFakeHttpRequestHandler(expectedResponses, testingActions)); - var client = new ForceClient("http://localhost:1899", "accessToken", "v29", new HttpClient(), httpClient); + IForceClient client = new ForceClient("http://localhost:1899", "accessToken", "v29", new HttpClient(), httpClient); using (client) { diff --git a/src/ForceToolkitForNET.UnitTests/ForceClientTests.cs b/src/ForceToolkitForNET.UnitTests/ForceClientTests.cs index 79b05100..18cd4692 100644 --- a/src/ForceToolkitForNET.UnitTests/ForceClientTests.cs +++ b/src/ForceToolkitForNET.UnitTests/ForceClientTests.cs @@ -17,7 +17,7 @@ public class ForceClientTests public async Task Requests_CheckHttpRequestMessage_UserAgent() { var httpClient = new HttpClient(new ServiceClientRouteHandler(r => Assert.AreEqual(r.Headers.UserAgent.ToString(), UserAgent + "/v32"))); - var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); + IForceClient forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); try { @@ -35,7 +35,7 @@ public async Task GetBasicInformationAsync_EmptyObjectName_ThrowsException() { var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) { Content = new JsonContent(new { }) }; var httpClient = new HttpClient(new FakeHttpRequestHandler(expectedResponse)); - var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); + IForceClient forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); Action asserts = exception => Assert.That(exception.Message, Is.Not.Null); await AssertEx.ThrowsAsync(() => forceClient.BasicInformationAsync(""), asserts); @@ -49,7 +49,7 @@ public async void GetBasicInformationAsync_ValidObjectName_ReturnsParsedResponse Content = JsonContent.FromFile("KnownGoodContent/UserObjectDescribeMetadata.json") }; var httpClient = new HttpClient(new FakeHttpRequestHandler(expectedResponse)); - var forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); + IForceClient forceClient = new ForceClient("http://localhost:1899", "accessToken", ApiVersion, httpClient, new HttpClient()); var result = await forceClient.BasicInformationAsync("ValidObjectName"); diff --git a/src/ForceToolkitForNET/ForceClient.cs b/src/ForceToolkitForNET/ForceClient.cs index dd7149b1..a1173f72 100644 --- a/src/ForceToolkitForNET/ForceClient.cs +++ b/src/ForceToolkitForNET/ForceClient.cs @@ -5,6 +5,7 @@ using System.Runtime.Serialization; using System.Threading.Tasks; using System.Reflection; +using System.Threading; using Salesforce.Common; using Salesforce.Common.Models.Json; using Salesforce.Common.Models.Xml; @@ -13,8 +14,8 @@ namespace Salesforce.Force { public class ForceClient : IForceClient, IDisposable { - private readonly XmlHttpClient _xmlHttpClient; - private readonly JsonHttpClient _jsonHttpClient; + private readonly IXmlHttpClient _xmlHttpClient; + private readonly IJsonHttpClient _jsonHttpClient; public ForceClient(string instanceUrl, string accessToken, string apiVersion) : this(instanceUrl, accessToken, apiVersion, new HttpClient(), new HttpClient()) @@ -35,45 +36,43 @@ public ForceClient(string instanceUrl, string accessToken, string apiVersion, Ht // STANDARD METHODS - public Task> QueryAsync(string query) + public Task> QueryAsync(string query, CancellationToken token) { if (string.IsNullOrEmpty(query)) throw new ArgumentNullException("query"); - return _jsonHttpClient.HttpGetAsync>(string.Format("query?q={0}", Uri.EscapeDataString(query))); + return _jsonHttpClient.HttpGetAsync>(string.Format("query?q={0}", Uri.EscapeDataString(query)), token); } - public Task> QueryContinuationAsync(string nextRecordsUrl) + public Task> QueryContinuationAsync(string nextRecordsUrl, CancellationToken token) { if (string.IsNullOrEmpty(nextRecordsUrl)) throw new ArgumentNullException("nextRecordsUrl"); - return _jsonHttpClient.HttpGetAsync>(nextRecordsUrl); + return _jsonHttpClient.HttpGetAsync>(nextRecordsUrl, token); } - public Task> QueryAllAsync(string query) + public Task> QueryAllAsync(string query, CancellationToken token) { if (string.IsNullOrEmpty(query)) throw new ArgumentNullException("query"); - return _jsonHttpClient.HttpGetAsync>(string.Format("queryAll/?q={0}", Uri.EscapeDataString(query))); + return _jsonHttpClient.HttpGetAsync>(string.Format("queryAll/?q={0}", Uri.EscapeDataString(query)), token); } - public async Task ExecuteRestApiAsync(string apiName) + public Task ExecuteRestApiAsync(string apiName, CancellationToken token) { if (string.IsNullOrEmpty(apiName)) throw new ArgumentNullException("apiName"); - var response = await _jsonHttpClient.HttpGetRestApiAsync(apiName); - return response; + return _jsonHttpClient.HttpGetRestApiAsync(apiName, token); } - public async Task ExecuteRestApiAsync(string apiName, object inputObject) + public Task ExecuteRestApiAsync(string apiName, object inputObject, CancellationToken token) { if (string.IsNullOrEmpty(apiName)) throw new ArgumentNullException("apiName"); if (inputObject == null) throw new ArgumentNullException("inputObject"); - var response = await _jsonHttpClient.HttpPostRestApiAsync(apiName, inputObject); - return response; + return _jsonHttpClient.HttpPostRestApiAsync(apiName, inputObject, token); } - public async Task QueryByIdAsync(string objectName, string recordId) + public async Task QueryByIdAsync(string objectName, string recordId, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(recordId)) throw new ArgumentNullException("recordId"); @@ -85,151 +84,151 @@ public async Task QueryByIdAsync(string objectName, string recordId) })); var query = string.Format("SELECT {0} FROM {1} WHERE Id = '{2}'", fields, objectName, recordId); - var results = await QueryAsync(query).ConfigureAwait(false); + var results = await QueryAsync(query, token).ConfigureAwait(false); return results.Records.FirstOrDefault(); } - public async Task CreateAsync(string objectName, object record) + public Task CreateAsync(string objectName, object record, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (record == null) throw new ArgumentNullException("record"); - return await _jsonHttpClient.HttpPostAsync(record, string.Format("sobjects/{0}", objectName)).ConfigureAwait(false); + return _jsonHttpClient.HttpPostAsync(record, string.Format("sobjects/{0}", objectName), token); } - public Task UpdateAsync(string objectName, string recordId, object record) + public Task UpdateAsync(string objectName, string recordId, object record, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(recordId)) throw new ArgumentNullException("recordId"); if (record == null) throw new ArgumentNullException("record"); - return _jsonHttpClient.HttpPatchAsync(record, string.Format("sobjects/{0}/{1}", objectName, recordId)); + return _jsonHttpClient.HttpPatchAsync(record, string.Format("sobjects/{0}/{1}", objectName, recordId), token); } - public Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record) + public Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(externalFieldName)) throw new ArgumentNullException("externalFieldName"); if (string.IsNullOrEmpty(externalId)) throw new ArgumentNullException("externalId"); if (record == null) throw new ArgumentNullException("record"); - return _jsonHttpClient.HttpPatchAsync(record, string.Format("sobjects/{0}/{1}/{2}", objectName, externalFieldName, externalId)); + return _jsonHttpClient.HttpPatchAsync(record, string.Format("sobjects/{0}/{1}/{2}", objectName, externalFieldName, externalId), token); } - public Task DeleteAsync(string objectName, string recordId) + public Task DeleteAsync(string objectName, string recordId, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(recordId)) throw new ArgumentNullException("recordId"); - return _jsonHttpClient.HttpDeleteAsync(string.Format("sobjects/{0}/{1}", objectName, recordId)); + return _jsonHttpClient.HttpDeleteAsync(string.Format("sobjects/{0}/{1}", objectName, recordId), token); } - public Task DeleteExternalAsync(string objectName, string externalFieldName, string externalId) + public Task DeleteExternalAsync(string objectName, string externalFieldName, string externalId, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(externalFieldName)) throw new ArgumentNullException("externalFieldName"); if (string.IsNullOrEmpty(externalId)) throw new ArgumentNullException("externalId"); - return _jsonHttpClient.HttpDeleteAsync(string.Format("sobjects/{0}/{1}/{2}", objectName, externalFieldName, externalId)); + return _jsonHttpClient.HttpDeleteAsync(string.Format("sobjects/{0}/{1}/{2}", objectName, externalFieldName, externalId), token); } - public Task> GetObjectsAsync() + public Task> GetObjectsAsync(CancellationToken token) { - return _jsonHttpClient.HttpGetAsync>("sobjects"); + return _jsonHttpClient.HttpGetAsync>("sobjects", token); } - public Task BasicInformationAsync(string objectName) + public Task BasicInformationAsync(string objectName, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}", objectName)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}", objectName), token); } - public Task DescribeAsync(string objectName) + public Task DescribeAsync(string objectName, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/", objectName)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/", objectName), token); } - public Task GetDeleted(string objectName, DateTime startDateTime, DateTime endDateTime) + public Task GetDeleted(string objectName, DateTime startDateTime, DateTime endDateTime, CancellationToken token) { var sdt = Uri.EscapeDataString(startDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss+00:00", System.Globalization.CultureInfo.InvariantCulture)); var edt = Uri.EscapeDataString(endDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss+00:00", System.Globalization.CultureInfo.InvariantCulture)); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/deleted/?start={1}&end={2}", objectName, sdt, edt)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/deleted/?start={1}&end={2}", objectName, sdt, edt), token); } - public Task GetUpdated(string objectName, DateTime startDateTime, DateTime endDateTime) + public Task GetUpdated(string objectName, DateTime startDateTime, DateTime endDateTime, CancellationToken token) { var sdt = Uri.EscapeDataString(startDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss+00:00", System.Globalization.CultureInfo.InvariantCulture)); var edt = Uri.EscapeDataString(endDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss+00:00", System.Globalization.CultureInfo.InvariantCulture)); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/updated/?start={1}&end={2}", objectName, sdt, edt)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/updated/?start={1}&end={2}", objectName, sdt, edt), token); } - public Task DescribeLayoutAsync(string objectName) + public Task DescribeLayoutAsync(string objectName, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/layouts/", objectName)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/layouts/", objectName), token); } - public Task DescribeLayoutAsync(string objectName, string recordTypeId) + public Task DescribeLayoutAsync(string objectName, string recordTypeId, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); if (string.IsNullOrEmpty(recordTypeId)) throw new ArgumentNullException("recordTypeId"); - return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/layouts/{1}", objectName, recordTypeId)); + return _jsonHttpClient.HttpGetAsync(string.Format("sobjects/{0}/describe/layouts/{1}", objectName, recordTypeId), token); } - public Task RecentAsync(int limit = 200) + public Task RecentAsync(int limit = 200, CancellationToken token = default(CancellationToken)) { - return _jsonHttpClient.HttpGetAsync(string.Format("recent/?limit={0}", limit)); + return _jsonHttpClient.HttpGetAsync(string.Format("recent/?limit={0}", limit), token); } - public Task> SearchAsync(string query) + public Task> SearchAsync(string query, CancellationToken token) { if (string.IsNullOrEmpty(query)) throw new ArgumentNullException("query"); if (!query.Contains("FIND")) throw new ArgumentException("query does not contain FIND"); if (!query.Contains("{") || !query.Contains("}")) throw new ArgumentException("search term must be wrapped in braces"); - return _jsonHttpClient.HttpGetAsync>(string.Format("search?q={0}", Uri.EscapeDataString(query))); + return _jsonHttpClient.HttpGetAsync>(string.Format("search?q={0}", Uri.EscapeDataString(query)), token); } - public async Task UserInfo(string url) + public Task UserInfo(string url, CancellationToken token) { if (string.IsNullOrEmpty(url)) throw new ArgumentNullException("url"); if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) throw new FormatException("url"); - var response = await _jsonHttpClient.HttpGetAsync(new Uri(url)); - return response; + return _jsonHttpClient.HttpGetAsync(new Uri(url), token); } // BULK METHODS public async Task> RunJobAsync(string objectName, BulkConstants.OperationType operationType, - IEnumerable> recordsLists) + IEnumerable> recordsLists, CancellationToken token) { if (recordsLists == null) throw new ArgumentNullException("recordsLists"); - var jobInfoResult = await CreateJobAsync(objectName, operationType); + var jobInfoResult = await CreateJobAsync(objectName, operationType, token).ConfigureAwait(false); var batchResults = new List(); foreach (var recordList in recordsLists) { - batchResults.Add(await CreateJobBatchAsync(jobInfoResult, recordList)); + var batchInfoResult = await CreateJobBatchAsync(jobInfoResult, recordList, token).ConfigureAwait(false); + batchResults.Add(batchInfoResult); } - await CloseJobAsync(jobInfoResult); + await CloseJobAsync(jobInfoResult, token).ConfigureAwait(false); return batchResults; } public async Task> RunJobAndPollAsync(string objectName, BulkConstants.OperationType operationType, - IEnumerable> recordsLists) + IEnumerable> recordsLists, CancellationToken token) { const float pollingStart = 1000; const float pollingIncrease = 2.0f; - var batchInfoResults = await RunJobAsync(objectName, operationType, recordsLists); + var batchInfoResults = await RunJobAsync(objectName, operationType, recordsLists, token).ConfigureAwait(false); var currentPoll = pollingStart; var finishedBatchInfoResults = new List(); @@ -238,7 +237,7 @@ public async Task> RunJobAndPollAsync(string objectName var removeList = new List(); foreach (var batchInfoResult in batchInfoResults) { - var batchInfoResultNew = await PollBatchAsync(batchInfoResult); + var batchInfoResultNew = await PollBatchAsync(batchInfoResult, token).ConfigureAwait(false); if (batchInfoResultNew.State.Equals(BulkConstants.BatchState.Completed.Value()) || batchInfoResultNew.State.Equals(BulkConstants.BatchState.Failed.Value()) || batchInfoResultNew.State.Equals(BulkConstants.BatchState.NotProcessed.Value())) @@ -252,7 +251,7 @@ public async Task> RunJobAndPollAsync(string objectName batchInfoResults.Remove(removeItem); } - await Task.Delay((int)currentPoll); + await Task.Delay((int)currentPoll, token).ConfigureAwait(false); currentPoll *= pollingIncrease; } @@ -260,12 +259,13 @@ public async Task> RunJobAndPollAsync(string objectName var batchResults = new List(); foreach (var batchInfoResultComplete in finishedBatchInfoResults) { - batchResults.Add(await GetBatchResultAsync(batchInfoResultComplete)); + var batchResultList = await GetBatchResultAsync(batchInfoResultComplete, token).ConfigureAwait(false); + batchResults.Add(batchResultList); } return batchResults; } - public async Task CreateJobAsync(string objectName, BulkConstants.OperationType operationType) + public Task CreateJobAsync(string objectName, BulkConstants.OperationType operationType, CancellationToken token) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); @@ -276,81 +276,76 @@ public async Task CreateJobAsync(string objectName, BulkConstants Operation = operationType.Value() }; - return await _xmlHttpClient.HttpPostAsync(jobInfo, "/services/async/{0}/job"); + return _xmlHttpClient.HttpPostAsync(jobInfo, "/services/async/{0}/job", token); } - public async Task CreateJobBatchAsync(JobInfoResult jobInfo, ISObjectList recordsList) + public Task CreateJobBatchAsync(JobInfoResult jobInfo, ISObjectList recordsList, CancellationToken token) { if (jobInfo == null) throw new ArgumentNullException("jobInfo"); - return await CreateJobBatchAsync(jobInfo.Id, recordsList).ConfigureAwait(false); + return CreateJobBatchAsync(jobInfo.Id, recordsList, token); } - public async Task CreateJobBatchAsync(string jobId, ISObjectList recordsObject) + public Task CreateJobBatchAsync(string jobId, ISObjectList recordsObject, CancellationToken token) { if (string.IsNullOrEmpty(jobId)) throw new ArgumentNullException("jobId"); if (recordsObject == null) throw new ArgumentNullException("recordsObject"); - return await _xmlHttpClient.HttpPostAsync(recordsObject, string.Format("/services/async/{{0}}/job/{0}/batch", jobId)) - .ConfigureAwait(false); + return _xmlHttpClient.HttpPostAsync(recordsObject, string.Format("/services/async/{{0}}/job/{0}/batch", jobId), token); } - public async Task CloseJobAsync(JobInfoResult jobInfo) + public Task CloseJobAsync(JobInfoResult jobInfo, CancellationToken token) { if (jobInfo == null) throw new ArgumentNullException("jobInfo"); - return await CloseJobAsync(jobInfo.Id); + return CloseJobAsync(jobInfo.Id, token); } - public async Task CloseJobAsync(string jobId) + public Task CloseJobAsync(string jobId, CancellationToken token) { if (string.IsNullOrEmpty(jobId)) throw new ArgumentNullException("jobId"); var state = new JobInfoState { State = "Closed" }; - return await _xmlHttpClient.HttpPostAsync(state, string.Format("/services/async/{{0}}/job/{0}", jobId)) - .ConfigureAwait(false); + return _xmlHttpClient.HttpPostAsync(state, string.Format("/services/async/{{0}}/job/{0}", jobId), token); } - public async Task PollJobAsync(JobInfoResult jobInfo) + public Task PollJobAsync(JobInfoResult jobInfo, CancellationToken token) { if (jobInfo == null) throw new ArgumentNullException("jobInfo"); - return await PollJobAsync(jobInfo.Id); + return PollJobAsync(jobInfo.Id, token); } - public async Task PollJobAsync(string jobId) + public Task PollJobAsync(string jobId, CancellationToken token) { if (string.IsNullOrEmpty(jobId)) throw new ArgumentNullException("jobId"); - return await _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}", jobId)) - .ConfigureAwait(false); + return _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}", jobId), token); } - public async Task PollBatchAsync(BatchInfoResult batchInfo) + public Task PollBatchAsync(BatchInfoResult batchInfo, CancellationToken token) { if (batchInfo == null) throw new ArgumentNullException("batchInfo"); - return await PollBatchAsync(batchInfo.Id, batchInfo.JobId); + return PollBatchAsync(batchInfo.Id, batchInfo.JobId, token); } - public async Task PollBatchAsync(string batchId, string jobId) + public Task PollBatchAsync(string batchId, string jobId, CancellationToken token) { if (string.IsNullOrEmpty(batchId)) throw new ArgumentNullException("batchId"); if (string.IsNullOrEmpty(jobId)) throw new ArgumentNullException("jobId"); - return await _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}/batch/{1}", jobId, batchId)) - .ConfigureAwait(false); + return _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}/batch/{1}", jobId, batchId), token); } - public async Task GetBatchResultAsync(BatchInfoResult batchInfo) + public Task GetBatchResultAsync(BatchInfoResult batchInfo, CancellationToken token) { if (batchInfo == null) throw new ArgumentNullException("batchInfo"); - return await GetBatchResultAsync(batchInfo.Id, batchInfo.JobId); + return GetBatchResultAsync(batchInfo.Id, batchInfo.JobId, token); } - public async Task GetBatchResultAsync(string batchId, string jobId) + public Task GetBatchResultAsync(string batchId, string jobId, CancellationToken token) { if (string.IsNullOrEmpty(batchId)) throw new ArgumentNullException("batchId"); if (string.IsNullOrEmpty(jobId)) throw new ArgumentNullException("jobId"); - return await _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}/batch/{1}/result", jobId, batchId)) - .ConfigureAwait(false); + return _xmlHttpClient.HttpGetAsync(string.Format("/services/async/{{0}}/job/{0}/batch/{1}/result", jobId, batchId), token); } public void Dispose() diff --git a/src/ForceToolkitForNET/IForceClient.cs b/src/ForceToolkitForNET/IForceClient.cs index fd411387..a0c791bd 100644 --- a/src/ForceToolkitForNET/IForceClient.cs +++ b/src/ForceToolkitForNET/IForceClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Salesforce.Common.Models.Json; using Salesforce.Common.Models.Xml; @@ -10,41 +11,41 @@ public interface IForceClient: IDisposable { // STANDARD - Task> QueryAsync(string query); - Task> QueryContinuationAsync(string nextRecordsUrl); - Task> QueryAllAsync(string query); - Task QueryByIdAsync(string objectName, string recordId); - Task ExecuteRestApiAsync(string apiName); - Task ExecuteRestApiAsync(string apiName, object inputObject); - Task CreateAsync(string objectName, object record); - Task UpdateAsync(string objectName, string recordId, object record); - Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record); - Task DeleteAsync(string objectName, string recordId); - Task DeleteExternalAsync(string objectName, string externalFieldName, string externalId); - Task> GetObjectsAsync(); - Task BasicInformationAsync(string objectName); - Task DescribeAsync(string objectName); - Task GetDeleted(string objectName, DateTime startDateTime, DateTime endDateTime); - Task GetUpdated(string objectName, DateTime startDateTime, DateTime endDateTime); - Task DescribeLayoutAsync(string objectName); - Task DescribeLayoutAsync(string objectName, string recordTypeId); - Task RecentAsync(int limit = 200); - Task> SearchAsync(string query); - Task UserInfo(string url); + Task> QueryAsync(string query, CancellationToken token = default(CancellationToken)); + Task> QueryContinuationAsync(string nextRecordsUrl, CancellationToken token = default(CancellationToken)); + Task> QueryAllAsync(string query, CancellationToken token = default(CancellationToken)); + Task QueryByIdAsync(string objectName, string recordId, CancellationToken token = default(CancellationToken)); + Task ExecuteRestApiAsync(string apiName, CancellationToken token = default(CancellationToken)); + Task ExecuteRestApiAsync(string apiName, object inputObject, CancellationToken token = default(CancellationToken)); + Task CreateAsync(string objectName, object record, CancellationToken token = default(CancellationToken)); + Task UpdateAsync(string objectName, string recordId, object record, CancellationToken token = default(CancellationToken)); + Task UpsertExternalAsync(string objectName, string externalFieldName, string externalId, object record, CancellationToken token = default(CancellationToken)); + Task DeleteAsync(string objectName, string recordId, CancellationToken token = default(CancellationToken)); + Task DeleteExternalAsync(string objectName, string externalFieldName, string externalId, CancellationToken token = default(CancellationToken)); + Task> GetObjectsAsync(CancellationToken token = default(CancellationToken)); + Task BasicInformationAsync(string objectName, CancellationToken token = default(CancellationToken)); + Task DescribeAsync(string objectName, CancellationToken token = default(CancellationToken)); + Task GetDeleted(string objectName, DateTime startDateTime, DateTime endDateTime, CancellationToken token = default(CancellationToken)); + Task GetUpdated(string objectName, DateTime startDateTime, DateTime endDateTime, CancellationToken token = default(CancellationToken)); + Task DescribeLayoutAsync(string objectName, CancellationToken token = default(CancellationToken)); + Task DescribeLayoutAsync(string objectName, string recordTypeId, CancellationToken token = default(CancellationToken)); + Task RecentAsync(int limit = 200, CancellationToken token = default(CancellationToken)); + Task> SearchAsync(string query, CancellationToken token = default(CancellationToken)); + Task UserInfo(string url, CancellationToken token = default(CancellationToken)); // BULK - Task> RunJobAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists); - Task> RunJobAndPollAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists); - Task CreateJobAsync(string objectName, BulkConstants.OperationType operationType); - Task CreateJobBatchAsync(JobInfoResult jobInfo, ISObjectList recordsObject); - Task CreateJobBatchAsync(string jobId, ISObjectList recordsObject); - Task CloseJobAsync(JobInfoResult jobInfo); - Task CloseJobAsync(string jobId); - Task PollJobAsync(JobInfoResult jobInfo); - Task PollJobAsync(string jobId); - Task PollBatchAsync(BatchInfoResult batchInfo); - Task PollBatchAsync(string batchId, string jobId); - Task GetBatchResultAsync(BatchInfoResult batchInfo); - Task GetBatchResultAsync(string batchId, string jobId); + Task> RunJobAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists, CancellationToken token = default(CancellationToken)); + Task> RunJobAndPollAsync(string objectName, BulkConstants.OperationType operationType, IEnumerable> recordsLists, CancellationToken token = default(CancellationToken)); + Task CreateJobAsync(string objectName, BulkConstants.OperationType operationType, CancellationToken token = default(CancellationToken)); + Task CreateJobBatchAsync(JobInfoResult jobInfo, ISObjectList recordsObject, CancellationToken token = default(CancellationToken)); + Task CreateJobBatchAsync(string jobId, ISObjectList recordsObject, CancellationToken token = default(CancellationToken)); + Task CloseJobAsync(JobInfoResult jobInfo, CancellationToken token = default(CancellationToken)); + Task CloseJobAsync(string jobId, CancellationToken token = default(CancellationToken)); + Task PollJobAsync(JobInfoResult jobInfo, CancellationToken token = default(CancellationToken)); + Task PollJobAsync(string jobId, CancellationToken token = default(CancellationToken)); + Task PollBatchAsync(BatchInfoResult batchInfo, CancellationToken token = default(CancellationToken)); + Task PollBatchAsync(string batchId, string jobId, CancellationToken token = default(CancellationToken)); + Task GetBatchResultAsync(BatchInfoResult batchInfo, CancellationToken token = default(CancellationToken)); + Task GetBatchResultAsync(string batchId, string jobId, CancellationToken token = default(CancellationToken)); } }