/// <summary> /// An extenstion method on HttpClient that sends a request to <c>client</c>, using /// the request type (Get, Put, Post) specified by <c>invocation</c>. /// </summary> /// <param name="client">The target client.</param> /// <param name="invocation">A delegate that issues the required request type.</param> /// <param name="requestUrn">The URN representing the request.</param> /// <returns>The client's response as a <see cref="HttpResponseMessage"/>.</returns> /// public static Task <HttpResponseMessage> Invoke(this HttpClient client, HttpClientHelpers.EndPointInvocation invocation, string requestUrn, StringContent content = null) { return(invocation(client, requestUrn, content)); }
/// <summary> /// Makes a call to the specified endpoint of Accounts API, using the specified Invocation (Get, Put or Post). /// Content can be passed for Put and Post as <see cref="StringContent"/>. /// </summary> /// <param name="httpClient">The HttpClient instance serving as <c>this</c>.</param> /// <param name="invocation">A delegate that will pass the </param> /// <param name="requestUrn">The URN to be appended to the Accounts API URL in order to /// obtain the full request URL.</param> /// <param name="content">The content, if any. Only used if <c>invocation</c> is /// <see cref="HttpClientHelpers.Put"/> or <see cref="HttpClientHelpers.Post"/></param> /// <returns>An object representing the response by the Accounts API.</returns> /// <example> /// var response = InvokeManagementApi(Put, "accounts/credit/1234?sum=100"); /// /// Where "1234" is an account number and "100" is the sum to be credited to that account. /// </example> public static async Task <HttpResponseMessage> InvokeApiAsync(this HttpClient httpClient, HttpClientHelpers.EndPointInvocation invocation, string requestUrn, StringContent content = null) { var response = await httpClient.Invoke(invocation, requestUrn, content); return(response); }
/// <summary> /// Makes a call to the specified endpoint of Accounts API, using the specified Invocation (Get, Put or Post). /// This call only supports requests that can be fully encoded in the URL. /// </summary> /// <param name="invocation">A delegate that will pass the </param> /// <param name="requestUrn">The URN to be appended to the Accounts API URL in order to /// obtain the full request URL.</param> /// <returns>An object representing the response by the Accounts API.</returns> /// <example> /// var response = await InvokeApiAsync(Put, "accounts/credit/1234?sum=100"); /// /// Where "1234" is an account number and "100" is the sum to be credited to that account. /// </example> private async Task <HttpResponseMessage> InvokeApiAsync(HttpClientHelpers.EndPointInvocation invocation, string requestUrn) { HttpResponseMessage response; var accessToken = TokenManager.GetAccessTokens().AccessToken; using (var apiClient = new AccountsApiClient(_accountsApiUrl, accessToken)) { response = await apiClient.Invoke(invocation, requestUrn); } return(response); }
/// <summary> /// Submits a request URL to the Accounts API. Contains the retry logic required in order to /// deal with expired Access/Refresh Tokens. /// </summary> /// <param name="invocation">The calling method (Get, Put, or Post).</param> /// <param name="requestUrn">The request to be submitted to the Accounts API. /// See: <see cref="InvokeApiAsync(HttpClientHelpers.EndPointInvocation,string)"/> /// </param> /// <param name="userCredentialsCallback"> /// A delegate that can be invoked to obtain username/password credentials from the user. /// </param> /// <returns>The response from the Accounts API.</returns> /// private async Task <HttpResponseMessage> InvokeApiAsync(HttpClientHelpers.EndPointInvocation invocation, string requestUrn, UserCredentialsCallback userCredentialsCallback) { // ReSharper disable once NotAccessedVariable AccessTokenPair accessTokens; //-------------------------------------------------------------------------------------------- // Have we been authenticated? Check the Token Manager for an Access Token. If we don't have // one, go get one. //-------------------------------------------------------------------------------------------- // ReSharper disable once RedundantAssignment if ((accessTokens = TokenManager.GetAccessTokens()).IsNull()) { var(username, password) = await userCredentialsCallback(); await GetAndStoreApiAccessTokens(username, password); } // TODO handle failure //-------------------------------------------------------------------------------------------- // We have an Access Token; issue the request to the Accounts API. //-------------------------------------------------------------------------------------------- var response = await InvokeApiAsync(invocation, requestUrn); //-------------------------------------------------------------------------------------------- // Did the request fail? //-------------------------------------------------------------------------------------------- if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); //------------------------------------------------------------------------------------------ // Failed. Was it because our access token timed out? //------------------------------------------------------------------------------------------ if (response.IsAccessTokenExpired()) { //---------------------------------------------------------------------------------------- // Yes. Use our refresh token to get a new access token. //---------------------------------------------------------------------------------------- // ReSharper disable once NotAccessedVariable var accessToken = await GetAndStoreApiAccessTokens(); //---------------------------------------------------------------------------------------- // Re-submit the original request with the new access token. //---------------------------------------------------------------------------------------- response = await InvokeApiAsync(invocation, requestUrn); //---------------------------------------------------------------------------------------- // Is the Accounts API still reporting an expired token? //---------------------------------------------------------------------------------------- if (response.IsAccessTokenExpired()) { //-------------------------------------------------------------------------------------- // Yes. Apparently, our refresh token has expired too. At this point we must ask the // user to re-authenticate with their username/password. Use the caller-provided // callback to obtain them. //-------------------------------------------------------------------------------------- var(username, password) = await userCredentialsCallback(); //-------------------------------------------------------------------------------------- // Try to get a new access token one more time, using the user's credentials. //-------------------------------------------------------------------------------------- // ReSharper disable once RedundantAssignment accessToken = await GetAndStoreApiAccessTokens(username, password); //-------------------------------------------------------------------------------------- // Either that worked, or it didn't. Either way, we're done here. Return the final // response to the caller. //-------------------------------------------------------------------------------------- response = await InvokeApiAsync(invocation, requestUrn); } } } return(response); }