From a92ba3e5b7fee651f9eb5b8ca46921aea3a9e465 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:24:37 +0000 Subject: [PATCH 01/16] Update Src/VTEX.Health/VtexHealthClient.cs --- Src/VTEX.Health/VtexHealthClient.cs | 172 +++++++++++++++------------- 1 file changed, 91 insertions(+), 81 deletions(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index 9219e6f0a..8705472a5 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -1,81 +1,91 @@ -// *********************************************************************** -// Assembly : VTEX.Health -// Author : Guilherme Branco Stracini -// Created : 01-15-2023 -// -// Last Modified By : Guilherme Branco Stracini -// Last Modified On : 01-15-2023 -// *********************************************************************** -// -// © 2020 Guilherme Branco Stracini. All rights reserved. -// -// -// *********************************************************************** -namespace VTEX.Health -{ - using System; - using System.Collections.Generic; - using System.Net.Http; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.Extensions.Logging; - using Newtonsoft.Json; - - /// - /// Class VtexHealthClient. - /// Implements the - /// - /// - public class VtexHealthClient : IVtexHealthClient - { - /// - /// The logger - /// - private readonly ILogger _logger; - - /// - /// The HTTP client - /// - private readonly HttpClient _httpClient; - - #region ~ctors - - /// - /// Initializes a new instance of the class. - /// - /// The logger factory. - /// The HTTP client. - /// loggerFactory - /// httpClient - public VtexHealthClient(ILoggerFactory loggerFactory, HttpClient httpClient) - { - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _logger = loggerFactory.CreateLogger(); - _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); - } - - #endregion - - #region Implementation of IVtexHealthClient - - /// - public async Task> GetPlatformStatuesAsync( - CancellationToken cancellationToken - ) - { - _logger.LogDebug("Getting platform status"); - var response = await _httpClient.GetAsync("/", cancellationToken).ConfigureAwait(false); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - _logger.LogDebug($"Platform status response: {response.StatusCode}"); - return response.IsSuccessStatusCode - ? JsonConvert.DeserializeObject(responseContent) - : default; - } - - #endregion - } -} +// *********************************************************************** +// Assembly : VTEX.Health +// Author : Guilherme Branco Stracini +// Created : 01-15-2023 + private readonly IHttpClientFactory _httpClientFactory; + + public VtexHealthClient(IHttpClientFactory httpClientFactory) + { +// +// Last Modified By : Guilherme Branco Stracini +// Last Modified On : 01-15-2023 +// *********************************************************************** +// +// © 2020 Guilherme Branco Stracini. All rights reserved. +// +// +// *********************************************************************** +namespace VTEX.Health +{ + using System; + using System.Collections.Generic; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Extensions.Logging; + using Newtonsoft.Json; + + /// + /// Class VtexHealthClient. + /// Implements the + /// + /// + public class VtexHealthClient : IVtexHealthClient + { + /// + /// The logger + /// + private readonly ILogger _logger; + + /// + /// The HTTP client + /// + _httpClientFactory = httpClientFactory; + + #region ~ctors + + } + + private HttpClient CreateClient() + { + /// + /// Initializes a new instance of the class. + return _httpClientFactory.CreateClient(); + } + /// + /// The logger factory. + /// The HTTP client. + /// loggerFactory + /// httpClient + public VtexHealthClient(ILoggerFactory loggerFactory, HttpClient httpClient) + { + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + _logger = loggerFactory.CreateLogger(); + _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); + } + + #endregion + + #region Implementation of IVtexHealthClient + + /// + public async Task> GetPlatformStatuesAsync( + CancellationToken cancellationToken + ) + { + _logger.LogDebug("Getting platform status"); + var response = await _httpClient.GetAsync("/", cancellationToken).ConfigureAwait(false); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + _logger.LogDebug($"Platform status response: {response.StatusCode}"); + return response.IsSuccessStatusCode + ? JsonConvert.DeserializeObject(responseContent) + : default; + } + + #endregion + } +} From 996f08498b0b2f0494aaf2b074cd677d8effb39a Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:24:52 +0000 Subject: [PATCH 02/16] Update Src/VTEX/VTEXWrapper.cs --- Src/VTEX/VTEXWrapper.cs | 1068 ++++++++++++++++++++------------------- 1 file changed, 537 insertions(+), 531 deletions(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index 3140fe613..7a5db9848 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -1,531 +1,537 @@ -// *********************************************************************** -// Assembly : VTEX -// Author : Guilherme Branco Stracini -// Created : 01-15-2023 -// -// Last Modified By : Guilherme Branco Stracini -// Last Modified On : 01-16-2023 -// *********************************************************************** -// -// © 2020 Guilherme Branco Stracini. All rights reserved. -// -// -// *********************************************************************** -namespace VTEX -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - using System.Net; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Text; - using System.Threading; - using System.Threading.Tasks; - using CrispyWaffle.Extensions; - using CrispyWaffle.Log; - using CrispyWaffle.Telemetry; - using CrispyWaffle.Utilities; - using Enums; - using GoodPractices; - - /// - /// Class Wrapper. This class cannot be inherited. - /// - /// - // TODO change public to internal after remove from Integração Service - public sealed class VTEXWrapper : IDisposable - { - #region Private fields - - /// - /// The application key - /// - private string _appKey; - - /// - /// The application token - /// - private string _appToken; - - /// - /// The authentication cookie - /// - private string _authCookie; - - /// - /// The account name - /// - private readonly string _accountName; - - /// - /// The internal user agent - /// - private static string _internalUserAgent; - - /// - /// Gets the internal user agent. - /// - /// The internal user agent. - private static string InternalUserAgent - { - get - { - if (!string.IsNullOrWhiteSpace(_internalUserAgent)) - { - return _internalUserAgent; - } - - var assembly = System - .Reflection.Assembly.GetAssembly(typeof(VTEXWrapper)) - .GetName(); - _internalUserAgent = $@"{assembly.Name}/{assembly.Version}"; - return _internalUserAgent; - } - } - - /// - /// The request mediator - /// - private readonly ManualResetEvent _requestMediator = new ManualResetEvent(false); - - #endregion - - #region ~Ctor - - /// - /// Initializes a new instance of the class. - /// - /// The account name. - public VTEXWrapper(string accountName) - { - _accountName = accountName; - _requestMediator.Set(); - } - - #endregion - - #region Implementation of IDisposable - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - _appKey = null; - _appToken = null; - _requestMediator.Dispose(); - } - - #endregion - - #region Private methods - - /// - /// Services the invoker internal. - /// - /// The method. - /// The endpoint. - /// The token. - /// The data. - /// The URI builder. - /// The cookie. - /// if set to true [requires authentication]. - /// if set to true [is retry]. - /// System.String. - private async Task ServiceInvokerInternal( - HttpRequestMethod method, - string endpoint, - CancellationToken token, - string data, - UriBuilder uriBuilder, - Cookie cookie, - bool requiresAuthentication, - bool isRetry = false - ) - { - HttpResponseMessage response = null; - string result = null; - Exception exr; - try - { - _requestMediator.WaitOne(); - - LogConsumer.Trace( - "ServiceInvokerAsync -> Method: {0} | Endpoint: {1}", - method.GetHumanReadableValue(), - endpoint - ); - - LogConsumer.Debug(uriBuilder.ToString()); - - var cookieContainer = new CookieContainer(); - - using var handler = new HttpClientHandler { CookieContainer = cookieContainer }; - - using var client = new HttpClient(handler); - - ConfigureClient(client, requiresAuthentication); - - if (cookie != null) - { - cookieContainer.Add(uriBuilder.Uri, cookie); - } - - response = await RequestInternalAsync(method, token, data, client, uriBuilder) - .ConfigureAwait(false); - - token.ThrowIfCancellationRequested(); - - result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - response.EnsureSuccessStatusCode(); - - return result; - } - catch (AggregateException e) - { - var ex = e.InnerExceptions.FirstOrDefault() ?? e.InnerException ?? e; - - exr = HandleException(ex, response, uriBuilder.Uri, method, data, result); - - if (isRetry) - { - throw exr; - } - } - catch (Exception e) - { - exr = HandleException(e, response, uriBuilder.Uri, method, data, result); - - if (isRetry) - { - throw exr; - } - } - - return await ServiceInvokerInternal( - method, - endpoint, - token, - data, - uriBuilder, - cookie, - requiresAuthentication, - true - ) - .ConfigureAwait(false); - } - - /// - /// Handles the exception. - /// - /// The exception. - /// The response. - /// The URI. - /// The method. - /// The data. - /// The result. - /// Exception. - /// - private Exception HandleException( - Exception exception, - HttpResponseMessage response, - Uri uri, - HttpRequestMethod method, - string data, - string result - ) - { - var statusCode = 0; - if (response != null) - { - statusCode = (int)response.StatusCode; - } - - var ex = new UnexpectedApiResponseException( - uri, - method.ToString(), - data, - result, - statusCode, - exception - ); - if (statusCode == 429 || statusCode == 503) - { - _requestMediator.Reset(); - LogConsumer.Warning( - "HTTP {2} status code on method {0} - uri {1}", - method.ToString(), - uri, - statusCode - ); - Thread.Sleep(60 * 1000); - _requestMediator.Set(); - return ex; - } - if (statusCode != 0 && statusCode != 408 && statusCode != 500 && statusCode != 502) - { - throw ex; - } - - LogConsumer.Warning("Retrying the {0} request", method.ToString()); - TelemetryAnalytics.TrackHit( - $"VTEX_handle_exception_retrying_{method.ToString()}_request" - ); - return ex; - } - - /// - /// Configures the client. - /// - /// The client. - /// if set to true [requires authentication]. - private void ConfigureClient(HttpClient client, bool requiresAuthentication) - { - client.DefaultRequestHeaders.ExpectContinue = false; - client.DefaultRequestHeaders.Accept.Clear(); - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue(@"application/json") - ); - client.DefaultRequestHeaders.TryAddWithoutValidation( - @"User-Agent", - $@"guiBranco-VTEX-SDK-dotnet {InternalUserAgent} +https://github.com/guibranco/VTEX-SDK-dotnet" - ); - if (!requiresAuthentication) - { - return; - } - - client.DefaultRequestHeaders.Add(@"X-VTEX-API-AppKey", _appKey); - client.DefaultRequestHeaders.Add(@"X-VTEX-API-AppToken", _appToken); - } - - /// - /// Sends an HTTP request asynchronously using the specified method and returns the response. - /// - /// The HTTP method to use for the request (e.g., GET, POST, DELETE, etc.). - /// A cancellation token to cancel the operation if needed. - /// The data to be sent in the request body, if applicable. - /// The HttpClient instance used to send the request. - /// The UriBuilder that constructs the URI for the request. - /// A task that represents the asynchronous operation, containing the HttpResponseMessage received from the server. - /// - /// This method handles different HTTP methods such as GET, POST, PUT, DELETE, and PATCH. - /// It constructs the appropriate request based on the provided method and sends it using the specified HttpClient. - /// If the method requires a body (like POST, PUT, or PATCH), it creates a StringContent object with the provided data. - /// The method also supports cancellation through the provided CancellationToken. - /// The response from the server is returned as an HttpResponseMessage, which can be used to inspect the result of the request. - /// - /// Thrown when an unsupported HTTP method is provided. - private static async Task RequestInternalAsync( - HttpRequestMethod method, - CancellationToken token, - string data, - HttpClient client, - UriBuilder uriBuilder - ) - { - HttpResponseMessage response; - StringContent content = null; - if (!string.IsNullOrWhiteSpace(data)) - { - content = new StringContent(data, Encoding.UTF8, @"application/json"); - } - - switch (method) - { - case HttpRequestMethod.DELETE: - response = await client - .DeleteAsync(uriBuilder.Uri, token) - .ConfigureAwait(false); - break; - case HttpRequestMethod.GET: - response = await client.GetAsync(uriBuilder.Uri, token).ConfigureAwait(false); - break; - case HttpRequestMethod.POST: - response = await client - .PostAsync(uriBuilder.Uri, content, token) - .ConfigureAwait(false); - break; - case HttpRequestMethod.PUT: - response = await client - .PutAsync(uriBuilder.Uri, content, token) - .ConfigureAwait(false); - break; - case HttpRequestMethod.PATCH: - var request = new HttpRequestMessage(new HttpMethod(@"PATCH"), uriBuilder.Uri) - { - Content = content, - }; - response = await client.SendAsync(request, token).ConfigureAwait(false); - request.Dispose(); - break; - default: - throw new ArgumentOutOfRangeException(nameof(method), method, null); - } - - return response; - } - - #endregion - - #region Public methods - - /// - /// Sets the rest credentials. - /// - /// The application key. - /// The application token. - public void SetRestCredentials(string appKey, string appToken) - { - _appKey = appKey; - _appToken = appToken; - } - - /// - /// Sets the vtex identifier client authentication cookie. - /// - /// The cookie value. - public void SetVtexIdClientAuthCookie(string cookieValue) - { - _authCookie = cookieValue; - } - - /// - /// Asynchronously invokes a service endpoint with the specified HTTP method and parameters. - /// - /// The HTTP request method to be used (e.g., GET, POST). - /// The endpoint of the service to be invoked. This should not be localizable. - /// A cancellation token to observe while waiting for the task to complete. - /// An optional dictionary of query string parameters to be included in the request. - /// An optional string containing data to be sent with the request. - /// An optional parameter specifying the REST endpoint type. Defaults to . - /// A task that represents the asynchronous operation, containing the response as a string. - /// - /// This method constructs a URI using the provided endpoint and query string parameters, - /// and then invokes the service asynchronously. It handles authentication and cookie management - /// as needed based on the service requirements. The method is designed to work with various - /// HTTP methods and can send data in the request body if specified. - /// The response from the service is returned as a string, allowing for further processing or - /// parsing as needed by the caller. - /// - public async Task ServiceInvokerAsync( - HttpRequestMethod method, - [Localizable(false)] string endpoint, - CancellationToken token, - Dictionary queryString = null, - string data = null, - RequestEndpoint restEndpoint = RequestEndpoint.DEFAULT - ) - { - Cookie cookie = null; - var requiresAuthentication = true; - var protocol = @"https"; - var port = 443; - var host = GetHostData( - ref endpoint, - ref queryString, - restEndpoint, - ref cookie, - ref protocol, - ref port, - ref requiresAuthentication - ); - var query = string.Empty; - if (queryString is { Count: > 0 }) - { - query = new QueryStringBuilder().AddRange(queryString).ToString(); - } - - var builder = new UriBuilder(protocol, host, port, endpoint) - { - Query = query.Replace(@"?", string.Empty), - }; - return await ServiceInvokerInternal( - method, - endpoint, - token, - data, - builder, - cookie, - requiresAuthentication - ) - .ConfigureAwait(false); - } - - /// - /// Gets the host data. - /// - /// The endpoint. - /// The query string. - /// The rest endpoint. - /// The cookie. - /// The protocol. - /// The port. - /// if set to true [requires authentication]. - /// System.String. - /// restEndpoint - null - private string GetHostData( - ref string endpoint, - ref Dictionary queryString, - RequestEndpoint restEndpoint, - ref Cookie cookie, - ref string protocol, - ref int port, - ref bool requiresAuthentication - ) - { - string host; - switch (restEndpoint) - { - case RequestEndpoint.DEFAULT: - host = $@"{_accountName}.{VTEXConstants.PlatformStableDomain}"; - endpoint = $@"api/{endpoint}"; - break; - case RequestEndpoint.PAYMENTS: - host = $@"{_accountName}.{VTEXConstants.PaymentsDomain}"; - endpoint = $@"api/{endpoint}"; - break; - case RequestEndpoint.LOGISTICS: - host = VTEXConstants.LogisticsDomain; - endpoint = $@"api/{endpoint}"; - if (queryString == null) - { - queryString = new(); - } - - queryString.Add(@"an", _accountName); - break; - case RequestEndpoint.API: - case RequestEndpoint.MASTER_DATA: - host = VTEXConstants.ApiDomain; - endpoint = $@"{_accountName}/{endpoint}"; - break; - case RequestEndpoint.BRIDGE: - host = $@"{_accountName}.{VTEXConstants.MyVtexDomain}"; - endpoint = $@"api/{endpoint}"; - if (!string.IsNullOrWhiteSpace(_authCookie)) - { - cookie = new(VTEXConstants.VtexIdClientAuthCookieName, _authCookie); - } - - break; - case RequestEndpoint.HEALTH: - protocol = @"http"; - port = 80; - host = VTEXConstants.MonitoringDomain; - endpoint = @"api/healthcheck/modules"; - requiresAuthentication = false; - break; - default: - throw new ArgumentOutOfRangeException(nameof(restEndpoint), restEndpoint, null); - } - - return host; - } - - #endregion - } -} +// *********************************************************************** +// Assembly : VTEX +// Author : Guilherme Branco Stracini +// Created : 01-15-2023 +// +// Last Modified By : Guilherme Branco Stracini +// Last Modified On : 01-16-2023 +// *********************************************************************** +// +// © 2020 Guilherme Branco Stracini. All rights reserved. +// +// +// *********************************************************************** +namespace VTEX +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Net.Http.Headers; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + using CrispyWaffle.Extensions; + using CrispyWaffle.Log; + using CrispyWaffle.Telemetry; + using CrispyWaffle.Utilities; + using Enums; + using GoodPractices; + + /// + /// Class Wrapper. This class cannot be inherited. + /// + /// + // TODO change public to internal after remove from Integração Service + public sealed class VTEXWrapper : IDisposable + { + #region Private fields + + /// + /// The application key + /// + private string _appKey; + + /// + /// The application token + /// + private string _appToken; + + /// + /// The authentication cookie + /// + private string _authCookie; + + /// + /// The account name + /// + private readonly string _accountName; + + /// + /// The internal user agent + /// + private static string _internalUserAgent; + + /// + /// Gets the internal user agent. + /// + /// The internal user agent. + private static string InternalUserAgent + { + get + { + if (!string.IsNullOrWhiteSpace(_internalUserAgent)) + { + return _internalUserAgent; + } + + var assembly = System + .Reflection.Assembly.GetAssembly(typeof(VTEXWrapper)) + .GetName(); + _internalUserAgent = $@"{assembly.Name}/{assembly.Version}"; + return _internalUserAgent; + } + } + + /// + /// The request mediator + /// + private readonly ManualResetEvent _requestMediator = new ManualResetEvent(false); + + #endregion + + #region ~Ctor + + /// + /// Initializes a new instance of the class. + /// + /// The account name. + public VTEXWrapper(string accountName) + { + _accountName = accountName; + _requestMediator.Set(); + } + + #endregion + + #region Implementation of IDisposable + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + _appKey = null; + _appToken = null; + _requestMediator.Dispose(); + } + + #endregion + + #region Private methods + + /// + /// Services the invoker internal. + /// + /// The method. + /// The endpoint. + /// The token. + /// The data. + /// The URI builder. + /// The cookie. + /// if set to true [requires authentication]. + /// if set to true [is retry]. + /// System.String. + private async Task ServiceInvokerInternal( + HttpRequestMethod method, + string endpoint, + CancellationToken token, + string data, + UriBuilder uriBuilder, + Cookie cookie, + bool requiresAuthentication, + bool isRetry = false + ) + { + HttpResponseMessage response = null; + string result = null; + Exception exr; + try + { + _requestMediator.WaitOne(); + + LogConsumer.Trace( + "ServiceInvokerAsync -> Method: {0} | Endpoint: {1}", + method.GetHumanReadableValue(), + endpoint + ); + + private readonly IHttpClientFactory _httpClientFactory; + + public VTEXWrapper(IHttpClientFactory httpClientFactory) + { + LogConsumer.Debug(uriBuilder.ToString()); + + _httpClientFactory = httpClientFactory; + } + var cookieContainer = new CookieContainer(); + + using var client = new HttpClient(handler); + var client = _httpClientFactory.CreateClient(); + + + ConfigureClient(client, requiresAuthentication); + + if (cookie != null) + { + cookieContainer.Add(uriBuilder.Uri, cookie); + } + + response = await RequestInternalAsync(method, token, data, client, uriBuilder) + .ConfigureAwait(false); + + token.ThrowIfCancellationRequested(); + + result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + response.EnsureSuccessStatusCode(); + + return result; + } + catch (AggregateException e) + { + var ex = e.InnerExceptions.FirstOrDefault() ?? e.InnerException ?? e; + + exr = HandleException(ex, response, uriBuilder.Uri, method, data, result); + + if (isRetry) + { + throw exr; + } + } + catch (Exception e) + { + exr = HandleException(e, response, uriBuilder.Uri, method, data, result); + + if (isRetry) + { + throw exr; + } + } + + return await ServiceInvokerInternal( + method, + endpoint, + token, + data, + uriBuilder, + cookie, + requiresAuthentication, + true + ) + .ConfigureAwait(false); + } + + /// + /// Handles the exception. + /// + /// The exception. + /// The response. + /// The URI. + /// The method. + /// The data. + /// The result. + /// Exception. + /// + private Exception HandleException( + Exception exception, + HttpResponseMessage response, + Uri uri, + HttpRequestMethod method, + string data, + string result + ) + { + var statusCode = 0; + if (response != null) + { + statusCode = (int)response.StatusCode; + } + + var ex = new UnexpectedApiResponseException( + uri, + method.ToString(), + data, + result, + statusCode, + exception + ); + if (statusCode == 429 || statusCode == 503) + { + _requestMediator.Reset(); + LogConsumer.Warning( + "HTTP {2} status code on method {0} - uri {1}", + method.ToString(), + uri, + statusCode + ); + Thread.Sleep(60 * 1000); + _requestMediator.Set(); + return ex; + } + if (statusCode != 0 && statusCode != 408 && statusCode != 500 && statusCode != 502) + { + throw ex; + } + + LogConsumer.Warning("Retrying the {0} request", method.ToString()); + TelemetryAnalytics.TrackHit( + $"VTEX_handle_exception_retrying_{method.ToString()}_request" + ); + return ex; + } + + /// + /// Configures the client. + /// + /// The client. + /// if set to true [requires authentication]. + private void ConfigureClient(HttpClient client, bool requiresAuthentication) + { + client.DefaultRequestHeaders.ExpectContinue = false; + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue(@"application/json") + ); + client.DefaultRequestHeaders.TryAddWithoutValidation( + @"User-Agent", + $@"guiBranco-VTEX-SDK-dotnet {InternalUserAgent} +https://github.com/guibranco/VTEX-SDK-dotnet" + ); + if (!requiresAuthentication) + { + return; + } + + client.DefaultRequestHeaders.Add(@"X-VTEX-API-AppKey", _appKey); + client.DefaultRequestHeaders.Add(@"X-VTEX-API-AppToken", _appToken); + } + + /// + /// Sends an HTTP request asynchronously using the specified method and returns the response. + /// + /// The HTTP method to use for the request (e.g., GET, POST, DELETE, etc.). + /// A cancellation token to cancel the operation if needed. + /// The data to be sent in the request body, if applicable. + /// The HttpClient instance used to send the request. + /// The UriBuilder that constructs the URI for the request. + /// A task that represents the asynchronous operation, containing the HttpResponseMessage received from the server. + /// + /// This method handles different HTTP methods such as GET, POST, PUT, DELETE, and PATCH. + /// It constructs the appropriate request based on the provided method and sends it using the specified HttpClient. + /// If the method requires a body (like POST, PUT, or PATCH), it creates a StringContent object with the provided data. + /// The method also supports cancellation through the provided CancellationToken. + /// The response from the server is returned as an HttpResponseMessage, which can be used to inspect the result of the request. + /// + /// Thrown when an unsupported HTTP method is provided. + private static async Task RequestInternalAsync( + HttpRequestMethod method, + CancellationToken token, + string data, + HttpClient client, + UriBuilder uriBuilder + ) + { + HttpResponseMessage response; + StringContent content = null; + if (!string.IsNullOrWhiteSpace(data)) + { + content = new StringContent(data, Encoding.UTF8, @"application/json"); + } + + switch (method) + { + case HttpRequestMethod.DELETE: + response = await client + .DeleteAsync(uriBuilder.Uri, token) + .ConfigureAwait(false); + break; + case HttpRequestMethod.GET: + response = await client.GetAsync(uriBuilder.Uri, token).ConfigureAwait(false); + break; + case HttpRequestMethod.POST: + response = await client + .PostAsync(uriBuilder.Uri, content, token) + .ConfigureAwait(false); + break; + case HttpRequestMethod.PUT: + response = await client + .PutAsync(uriBuilder.Uri, content, token) + .ConfigureAwait(false); + break; + case HttpRequestMethod.PATCH: + var request = new HttpRequestMessage(new HttpMethod(@"PATCH"), uriBuilder.Uri) + { + Content = content, + }; + response = await client.SendAsync(request, token).ConfigureAwait(false); + request.Dispose(); + break; + default: + throw new ArgumentOutOfRangeException(nameof(method), method, null); + } + + return response; + } + + #endregion + + #region Public methods + + /// + /// Sets the rest credentials. + /// + /// The application key. + /// The application token. + public void SetRestCredentials(string appKey, string appToken) + { + _appKey = appKey; + _appToken = appToken; + } + + /// + /// Sets the vtex identifier client authentication cookie. + /// + /// The cookie value. + public void SetVtexIdClientAuthCookie(string cookieValue) + { + _authCookie = cookieValue; + } + + /// + /// Asynchronously invokes a service endpoint with the specified HTTP method and parameters. + /// + /// The HTTP request method to be used (e.g., GET, POST). + /// The endpoint of the service to be invoked. This should not be localizable. + /// A cancellation token to observe while waiting for the task to complete. + /// An optional dictionary of query string parameters to be included in the request. + /// An optional string containing data to be sent with the request. + /// An optional parameter specifying the REST endpoint type. Defaults to . + /// A task that represents the asynchronous operation, containing the response as a string. + /// + /// This method constructs a URI using the provided endpoint and query string parameters, + /// and then invokes the service asynchronously. It handles authentication and cookie management + /// as needed based on the service requirements. The method is designed to work with various + /// HTTP methods and can send data in the request body if specified. + /// The response from the service is returned as a string, allowing for further processing or + /// parsing as needed by the caller. + /// + public async Task ServiceInvokerAsync( + HttpRequestMethod method, + [Localizable(false)] string endpoint, + CancellationToken token, + Dictionary queryString = null, + string data = null, + RequestEndpoint restEndpoint = RequestEndpoint.DEFAULT + ) + { + Cookie cookie = null; + var requiresAuthentication = true; + var protocol = @"https"; + var port = 443; + var host = GetHostData( + ref endpoint, + ref queryString, + restEndpoint, + ref cookie, + ref protocol, + ref port, + ref requiresAuthentication + ); + var query = string.Empty; + if (queryString is { Count: > 0 }) + { + query = new QueryStringBuilder().AddRange(queryString).ToString(); + } + + var builder = new UriBuilder(protocol, host, port, endpoint) + { + Query = query.Replace(@"?", string.Empty), + }; + return await ServiceInvokerInternal( + method, + endpoint, + token, + data, + builder, + cookie, + requiresAuthentication + ) + .ConfigureAwait(false); + } + + /// + /// Gets the host data. + /// + /// The endpoint. + /// The query string. + /// The rest endpoint. + /// The cookie. + /// The protocol. + /// The port. + /// if set to true [requires authentication]. + /// System.String. + /// restEndpoint - null + private string GetHostData( + ref string endpoint, + ref Dictionary queryString, + RequestEndpoint restEndpoint, + ref Cookie cookie, + ref string protocol, + ref int port, + ref bool requiresAuthentication + ) + { + string host; + switch (restEndpoint) + { + case RequestEndpoint.DEFAULT: + host = $@"{_accountName}.{VTEXConstants.PlatformStableDomain}"; + endpoint = $@"api/{endpoint}"; + break; + case RequestEndpoint.PAYMENTS: + host = $@"{_accountName}.{VTEXConstants.PaymentsDomain}"; + endpoint = $@"api/{endpoint}"; + break; + case RequestEndpoint.LOGISTICS: + host = VTEXConstants.LogisticsDomain; + endpoint = $@"api/{endpoint}"; + if (queryString == null) + { + queryString = new(); + } + + queryString.Add(@"an", _accountName); + break; + case RequestEndpoint.API: + case RequestEndpoint.MASTER_DATA: + host = VTEXConstants.ApiDomain; + endpoint = $@"{_accountName}/{endpoint}"; + break; + case RequestEndpoint.BRIDGE: + host = $@"{_accountName}.{VTEXConstants.MyVtexDomain}"; + endpoint = $@"api/{endpoint}"; + if (!string.IsNullOrWhiteSpace(_authCookie)) + { + cookie = new(VTEXConstants.VtexIdClientAuthCookieName, _authCookie); + } + + break; + case RequestEndpoint.HEALTH: + protocol = @"http"; + port = 80; + host = VTEXConstants.MonitoringDomain; + endpoint = @"api/healthcheck/modules"; + requiresAuthentication = false; + break; + default: + throw new ArgumentOutOfRangeException(nameof(restEndpoint), restEndpoint, null); + } + + return host; + } + + #endregion + } +} From a44b3406baaedd2fb67fc00bdf2adac9ee22cf79 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:26:00 +0000 Subject: [PATCH 03/16] Update Src/VTEX.Health/VtexHealthClient.cs --- Src/VTEX.Health/VtexHealthClient.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index 8705472a5..0f73e25fb 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -4,9 +4,16 @@ // Created : 01-15-2023 private readonly IHttpClientFactory _httpClientFactory; - public VtexHealthClient(IHttpClientFactory httpClientFactory) + public VtexHealthClient(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFactory) { // + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + _logger = loggerFactory.CreateLogger(); + _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); // Last Modified By : Guilherme Branco Stracini // Last Modified On : 01-15-2023 // *********************************************************************** From 8b5327643a6cb66eb40a43cf0084e219924eefc6 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:26:07 +0000 Subject: [PATCH 04/16] Update Src/VTEX/VTEXWrapper.cs --- Src/VTEX/VTEXWrapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index 7a5db9848..247c6219d 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -168,7 +168,6 @@ public VTEXWrapper(IHttpClientFactory httpClientFactory) } var cookieContainer = new CookieContainer(); - using var client = new HttpClient(handler); var client = _httpClientFactory.CreateClient(); From ccd4e3c3328528434bbff866ce6fec8913c07bae Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:26:09 +0000 Subject: [PATCH 05/16] Update Src/VTEX/VTEXWrapper.cs --- Src/VTEX/VTEXWrapper.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index 247c6219d..e5ed94b65 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -160,8 +160,15 @@ private async Task ServiceInvokerInternal( private readonly IHttpClientFactory _httpClientFactory; - public VTEXWrapper(IHttpClientFactory httpClientFactory) + public VTEXWrapper(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFactory) { + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + _logger = loggerFactory.CreateLogger(); + _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); LogConsumer.Debug(uriBuilder.ToString()); _httpClientFactory = httpClientFactory; From 79f391106a48e13fed5b0a3fd245cbc141584ce6 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:26:55 +0000 Subject: [PATCH 06/16] Update Src/VTEX.Health/VtexHealthClient.cs --- Src/VTEX.Health/VtexHealthClient.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index 0f73e25fb..b389c8015 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -64,12 +64,6 @@ private HttpClient CreateClient() /// The HTTP client. /// loggerFactory /// httpClient - public VtexHealthClient(ILoggerFactory loggerFactory, HttpClient httpClient) - { - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } _logger = loggerFactory.CreateLogger(); _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); From ae311a9afd507cae288e1de79d56d78233396f91 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:27:02 +0000 Subject: [PATCH 07/16] Update Src/VTEX/VTEXWrapper.cs --- Src/VTEX/VTEXWrapper.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index e5ed94b65..b789d4bf6 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -98,12 +98,6 @@ private static string InternalUserAgent /// Initializes a new instance of the class. /// /// The account name. - public VTEXWrapper(string accountName) - { - _accountName = accountName; - _requestMediator.Set(); - } - #endregion #region Implementation of IDisposable From 66d471e51cb9add0db70db409ee03d2fa7db3d1a Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:27:10 +0000 Subject: [PATCH 08/16] Update Src/VTEX/Startup.cs --- Src/VTEX/Startup.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Src/VTEX/Startup.cs diff --git a/Src/VTEX/Startup.cs b/Src/VTEX/Startup.cs new file mode 100644 index 000000000..f279be1c3 --- /dev/null +++ b/Src/VTEX/Startup.cs @@ -0,0 +1,10 @@ +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddHttpClient(); + services.AddScoped(); + services.AddScoped(); + } + +} From 8ef3aa1b21c7e01b47902aa5af84064bbedfbd63 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:27:18 +0000 Subject: [PATCH 09/16] Update Src/VTEX.Health/VtexHealthClient.cs --- Src/VTEX.Health/VtexHealthClient.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index b389c8015..a444e09dd 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -2,9 +2,7 @@ // Assembly : VTEX.Health // Author : Guilherme Branco Stracini // Created : 01-15-2023 - private readonly IHttpClientFactory _httpClientFactory; - public VtexHealthClient(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFactory) { // if (loggerFactory == null) @@ -79,12 +77,13 @@ CancellationToken cancellationToken ) { _logger.LogDebug("Getting platform status"); - var response = await _httpClient.GetAsync("/", cancellationToken).ConfigureAwait(false); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); _logger.LogDebug($"Platform status response: {response.StatusCode}"); return response.IsSuccessStatusCode + var httpClient = _httpClientFactory.CreateClient(); ? JsonConvert.DeserializeObject(responseContent) : default; + var response = await httpClient.GetAsync("/", cancellationToken).ConfigureAwait(false); } #endregion From eead33626360dbd8e5f7ef8a294f27b658f466df Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:27:19 +0000 Subject: [PATCH 10/16] Update .github/workflows/dotnet.yml --- .github/workflows/dotnet.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 000000000..e7cf114de --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,23 @@ +name: .NET + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '6.0.x' + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal From 762811b448bdac5e74655057587715cbd47ddab0 Mon Sep 17 00:00:00 2001 From: codefactor-io Date: Fri, 8 Nov 2024 00:27:28 +0000 Subject: [PATCH 11/16] [CodeFactor] Apply fixes --- Src/VTEX.Health/VtexHealthClient.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index a444e09dd..ac0ef9a38 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -1,8 +1,7 @@ -// *********************************************************************** +// *********************************************************************** // Assembly : VTEX.Health // Author : Guilherme Branco Stracini // Created : 01-15-2023 - { // if (loggerFactory == null) From d248f3db1f2a6284f20842c1abcd1c63c8cc8eed Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:28:09 +0000 Subject: [PATCH 12/16] Update .github/workflows/dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index e7cf114de..855f596a8 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -14,7 +14,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Restore dependencies run: dotnet restore - name: Build From 36686578315ef183bd7e9fafb0a6270161318af7 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:29:32 +0000 Subject: [PATCH 13/16] Update Src/VTEX.Health/VtexHealthClient.cs --- Src/VTEX.Health/VtexHealthClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/VTEX.Health/VtexHealthClient.cs b/Src/VTEX.Health/VtexHealthClient.cs index ac0ef9a38..9df21fc35 100644 --- a/Src/VTEX.Health/VtexHealthClient.cs +++ b/Src/VTEX.Health/VtexHealthClient.cs @@ -48,7 +48,6 @@ public class VtexHealthClient : IVtexHealthClient #region ~ctors - } private HttpClient CreateClient() { @@ -88,3 +87,4 @@ CancellationToken cancellationToken #endregion } } + } From b8c75efedf206bc0c9200092b60a53de306982c1 Mon Sep 17 00:00:00 2001 From: "gitauto-ai[bot]" <161652217+gitauto-ai[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:46:05 +0000 Subject: [PATCH 14/16] Update Src/VTEX/VTEXWrapper.cs --- Src/VTEX/VTEXWrapper.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index b789d4bf6..199d963f0 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -152,7 +152,6 @@ private async Task ServiceInvokerInternal( endpoint ); - private readonly IHttpClientFactory _httpClientFactory; public VTEXWrapper(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFactory) { @@ -162,10 +161,7 @@ public VTEXWrapper(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFa } _logger = loggerFactory.CreateLogger(); - _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); - LogConsumer.Debug(uriBuilder.ToString()); - _httpClientFactory = httpClientFactory; } var cookieContainer = new CookieContainer(); From e6cde23b8431fecfb5c5ab2dc33ffb9a1ae2d480 Mon Sep 17 00:00:00 2001 From: codefactor-io Date: Mon, 11 Nov 2024 01:46:15 +0000 Subject: [PATCH 15/16] [CodeFactor] Apply fixes to commit b8c75ef --- Src/VTEX/VTEXWrapper.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/VTEX/VTEXWrapper.cs b/Src/VTEX/VTEXWrapper.cs index 199d963f0..f46888e47 100644 --- a/Src/VTEX/VTEXWrapper.cs +++ b/Src/VTEX/VTEXWrapper.cs @@ -1,4 +1,4 @@ -// *********************************************************************** +// *********************************************************************** // Assembly : VTEX // Author : Guilherme Branco Stracini // Created : 01-15-2023 @@ -161,7 +161,6 @@ public VTEXWrapper(ILoggerFactory loggerFactory, IHttpClientFactory httpClientFa } _logger = loggerFactory.CreateLogger(); - } var cookieContainer = new CookieContainer(); From 1e5276d7579651d46ff97b3c48e149ed4d8847b5 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Tue, 12 Nov 2024 13:44:35 +0000 Subject: [PATCH 16/16] Delete .github/workflows/dotnet.yml --- .github/workflows/dotnet.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml deleted file mode 100644 index 855f596a8..000000000 --- a/.github/workflows/dotnet.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: .NET - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '8.0.x' - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --no-restore - - name: Test - run: dotnet test --no-build --verbosity normal