diff --git a/.gitignore b/.gitignore index 06b66640..ddf6d94f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ TestResults *.user *.sln.docstates *.userprefs +.vs/ # Build results [Dd]ebug/ diff --git a/src/CommonLibrariesForNET/IJsonHttpClient.cs b/src/CommonLibrariesForNET/IJsonHttpClient.cs index fe997322..f37a117c 100644 --- a/src/CommonLibrariesForNET/IJsonHttpClient.cs +++ b/src/CommonLibrariesForNET/IJsonHttpClient.cs @@ -11,15 +11,23 @@ public interface IJsonHttpClient : IDisposable // GET Task HttpGetAsync(string urlSuffix); + Task HttpGetAsync(string urlSuffix) where TErrorResponse : IErrorResponse; Task HttpGetAsync(Uri uri); + Task HttpGetAsync(Uri uri) where TErrorResponse : IErrorResponse; Task> HttpGetAsync(string urlSuffix, string nodeName); + Task> HttpGetAsync(string urlSuffix, string nodeName) where TErrorResponse : IErrorResponse; Task HttpGetRestApiAsync(string apiName); + Task HttpGetRestApiAsync(string apiName) where TErrorResponse : IErrorResponse; // POST Task HttpPostAsync(object inputObject, string urlSuffix); + Task HttpPostAsync(object inputObject, string urlSuffix) where TErrorResponse : IErrorResponse; Task HttpPostAsync(object inputObject, Uri uri); + Task HttpPostAsync(object inputObject, Uri uri) where TErrorResponse : IErrorResponse; Task HttpPostRestApiAsync(string apiName, object inputObject); + Task HttpPostRestApiAsync(string apiName, object inputObject) where TErrorResponse : IErrorResponse; Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName); + Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName) where TErrorResponse : IErrorResponse; // PATCH Task HttpPatchAsync(object inputObject, string urlSuffix); diff --git a/src/CommonLibrariesForNET/JsonHttpClient.cs b/src/CommonLibrariesForNET/JsonHttpClient.cs index 26d67132..ff49df25 100644 --- a/src/CommonLibrariesForNET/JsonHttpClient.cs +++ b/src/CommonLibrariesForNET/JsonHttpClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; @@ -23,10 +24,11 @@ public JsonHttpClient(string instanceUrl, string apiVersion, string accessToken, HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); } - private static ForceException ParseForceException(string responseMessage) + private static ForceException ParseForceException(string responseMessage, HttpStatusCode status) + where TErrorResponse : IErrorResponse { - var errorResponse = JsonConvert.DeserializeObject(responseMessage); - return new ForceException(errorResponse[0].ErrorCode, errorResponse[0].Message); + var errorResponse = JsonConvert.DeserializeObject(responseMessage); + return errorResponse.MapToForceException(status); } // GET @@ -37,7 +39,20 @@ public async Task HttpGetAsync(string urlSuffix) return await HttpGetAsync(url); } + public async Task HttpGetAsync(string urlSuffix) + where TErrorResponse : IErrorResponse + { + var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); + return await HttpGetAsync(url); + } + public async Task HttpGetAsync(Uri uri) + { + return await HttpGetAsync(uri); + } + + public async Task HttpGetAsync(Uri uri) + where TErrorResponse : IErrorResponse { try { @@ -61,11 +76,17 @@ public async Task HttpGetAsync(Uri uri) } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } public async Task> HttpGetAsync(string urlSuffix, string nodeName) + { + return await HttpGetAsync(urlSuffix, nodeName); + } + + public async Task> HttpGetAsync(string urlSuffix, string nodeName) + where TErrorResponse : IErrorResponse { string next = null; var records = new List(); @@ -87,7 +108,7 @@ public async Task> HttpGetAsync(string urlSuffix, string nodeName) } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } while (!string.IsNullOrEmpty(next)); @@ -125,6 +146,13 @@ public async Task HttpGetRestApiAsync(string apiName) return await HttpGetAsync(url); } + public async Task HttpGetRestApiAsync(string apiName) + where TErrorResponse : IErrorResponse + { + var url = Common.FormatRestApiUrl(apiName, InstanceUrl); + return await HttpGetAsync(url); + } + // POST public async Task HttpPostAsync(object inputObject, string urlSuffix) @@ -133,7 +161,20 @@ public async Task HttpPostAsync(object inputObject, string urlSuffix) return await HttpPostAsync(inputObject, url); } + public async Task HttpPostAsync(object inputObject, string urlSuffix) + where TErrorResponse : IErrorResponse + { + var url = Common.FormatUrl(urlSuffix, InstanceUrl, ApiVersion); + return await HttpPostAsync(inputObject, url); + } + public async Task HttpPostAsync(object inputObject, Uri uri) + { + return await HttpPostAsync(inputObject, uri); + } + + public async Task HttpPostAsync(object inputObject, Uri uri) + where TErrorResponse : IErrorResponse { var json = JsonConvert.SerializeObject(inputObject, Formatting.None, @@ -150,7 +191,7 @@ public async Task HttpPostAsync(object inputObject, Uri uri) } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } @@ -160,7 +201,20 @@ public async Task HttpPostRestApiAsync(string apiName, object inputObject) return await HttpPostAsync(inputObject, url); } + public async Task HttpPostRestApiAsync(string apiName, object inputObject) + where TErrorResponse : IErrorResponse + { + var url = Common.FormatRestApiUrl(apiName, InstanceUrl); + return await HttpPostAsync(inputObject, url); + } + public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName) + { + return await HttpBinaryDataPostAsync(urlSuffix, inputObject, fileContents, headerName, fileName); + } + + public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputObject, byte[] fileContents, string headerName, string fileName) + where TErrorResponse : IErrorResponse { // 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. @@ -193,7 +247,7 @@ public async Task HttpBinaryDataPostAsync(string urlSuffix, object inputOb return JsonConvert.DeserializeObject(response); } - throw ParseForceException(response); + throw ParseForceException(response, responseMessage.StatusCode); } // PATCH @@ -238,7 +292,7 @@ public async Task HttpPatchAsync(object inputObject, Uri uri) } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } @@ -264,7 +318,7 @@ public async Task HttpPatchAsync(object inputObject, Uri uri, N } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } @@ -285,7 +339,7 @@ public async Task HttpDeleteAsync(string urlSuffix) } catch (BaseHttpClientException e) { - throw ParseForceException(e.Message); + throw ParseForceException(e.Message, e.GetStatus()); } } } diff --git a/src/CommonLibrariesForNET/Models/Json/ErrorResponses.cs b/src/CommonLibrariesForNET/Models/Json/ErrorResponses.cs index 783cf570..1566c38d 100644 --- a/src/CommonLibrariesForNET/Models/Json/ErrorResponses.cs +++ b/src/CommonLibrariesForNET/Models/Json/ErrorResponses.cs @@ -1,6 +1,14 @@ using System.Collections.Generic; +using System.Linq; +using System.Net; namespace Salesforce.Common.Models.Json { - public class ErrorResponses : List { } + public class ErrorResponses : List, IErrorResponse + { + public ForceException MapToForceException(HttpStatusCode status) + { + return new ForceException(this.FirstOrDefault()?.ErrorCode, this.FirstOrDefault()?.Message); + } + } } diff --git a/src/CommonLibrariesForNET/Models/Json/IErrorResponse.cs b/src/CommonLibrariesForNET/Models/Json/IErrorResponse.cs new file mode 100644 index 00000000..79b882dc --- /dev/null +++ b/src/CommonLibrariesForNET/Models/Json/IErrorResponse.cs @@ -0,0 +1,9 @@ +using System.Net; + +namespace Salesforce.Common.Models.Json +{ + public interface IErrorResponse + { + ForceException MapToForceException(HttpStatusCode status); + } +} diff --git a/src/ForceToolkitForNET/ForceClient.cs b/src/ForceToolkitForNET/ForceClient.cs index b30135cf..4ad8e999 100644 --- a/src/ForceToolkitForNET/ForceClient.cs +++ b/src/ForceToolkitForNET/ForceClient.cs @@ -80,6 +80,15 @@ public async Task ExecuteRestApiAsync(string apiName) var response = await _jsonHttpClient.HttpGetRestApiAsync(apiName); return response; } + + public async Task ExecuteRestApiAsync(string apiName) + where TErrorResponse : IErrorResponse + { + if (string.IsNullOrEmpty(apiName)) throw new ArgumentNullException("apiName"); + + var response = await _jsonHttpClient.HttpGetRestApiAsync(apiName); + return response; + } public async Task ExecuteRestApiAsync(string apiName, object inputObject) { @@ -90,6 +99,16 @@ public async Task ExecuteRestApiAsync(string apiName, object inputObject) return response; } + public async Task ExecuteRestApiAsync(string apiName, object inputObject) + where TErrorResponse : IErrorResponse + { + if (string.IsNullOrEmpty(apiName)) throw new ArgumentNullException("apiName"); + if (inputObject == null) throw new ArgumentNullException("inputObject"); + + var response = await _jsonHttpClient.HttpPostRestApiAsync(apiName, inputObject); + return response; + } + public async Task QueryByIdAsync(string objectName, string recordId) { if (string.IsNullOrEmpty(objectName)) throw new ArgumentNullException("objectName"); diff --git a/src/ForceToolkitForNET/IForceClient.cs b/src/ForceToolkitForNET/IForceClient.cs index aa53de42..2f7f2fa9 100644 --- a/src/ForceToolkitForNET/IForceClient.cs +++ b/src/ForceToolkitForNET/IForceClient.cs @@ -17,7 +17,9 @@ public interface IForceClient : IDisposable Task QueryAllFieldsByIdAsync(string objectName, string recordId); Task QueryAllFieldsByExternalIdAsync(string objectName, string externalIdFieldName, string externalId); Task ExecuteRestApiAsync(string apiName); + Task ExecuteRestApiAsync(string apiName) where TErrorResponse : IErrorResponse; Task ExecuteRestApiAsync(string apiName, object inputObject); + Task ExecuteRestApiAsync(string apiName, object inputObject) where TErrorResponse : IErrorResponse; Task CreateAsync(string objectName, object record); Task CreateAsync(string objectName, CreateRequest request); Task UpdateAsync(string objectName, string recordId, object record);