From 57fe22e3db9d1b5c0b1e70b7f2628d5eeddd1eef Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 25 Jan 2024 04:45:40 +0330 Subject: [PATCH] Initial Commit ... --- .gitignore | 8 + Configurations/XHttpServiceConfiguration.cs | 10 + Constants/ConfigurationNodeNames.cs | 5 + Constants/XHttpMethod.cs | 17 ++ DI/XDIHelperExtension.cs | 97 +++++++ Extensions/RestSharpExtensions.cs | 189 ++++++++++++++ Helpers/.gitkeep | 0 Interfaces/IXHttpProvider.cs | 28 ++ Models/.gitkeep | 0 Providers/XHttpProvider.cs | 275 ++++++++++++++++++++ README.md | 15 ++ nuget.config | 7 + xHttpService.csproj | 36 +++ 13 files changed, 687 insertions(+) create mode 100644 .gitignore create mode 100644 Configurations/XHttpServiceConfiguration.cs create mode 100644 Constants/ConfigurationNodeNames.cs create mode 100644 Constants/XHttpMethod.cs create mode 100644 DI/XDIHelperExtension.cs create mode 100644 Extensions/RestSharpExtensions.cs create mode 100644 Helpers/.gitkeep create mode 100644 Interfaces/IXHttpProvider.cs create mode 100644 Models/.gitkeep create mode 100644 Providers/XHttpProvider.cs create mode 100644 README.md create mode 100644 nuget.config create mode 100644 xHttpService.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bd9d0b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# +# DotNet ... +bin +obj + +# +# Natural Docs ... +Documentation/* diff --git a/Configurations/XHttpServiceConfiguration.cs b/Configurations/XHttpServiceConfiguration.cs new file mode 100644 index 0000000..8fa1d2e --- /dev/null +++ b/Configurations/XHttpServiceConfiguration.cs @@ -0,0 +1,10 @@ +namespace xHttpService.Configurations { + public partial class XHttpServiceConfiguration { + /// + /// Determines Http Handler Check SSL or not ... + /// + /// + public bool DisableSSLCheck { get; set; } + public int DefaultClientTimeout { get; set; } = 360; + } +} \ No newline at end of file diff --git a/Constants/ConfigurationNodeNames.cs b/Constants/ConfigurationNodeNames.cs new file mode 100644 index 0000000..258bcc8 --- /dev/null +++ b/Constants/ConfigurationNodeNames.cs @@ -0,0 +1,5 @@ +namespace xHttpService.Constants { + public partial struct ConfigurationNodeNames { + public const string HTTP_SERVICE_NODE_NAME = "HttpServiceConfiguration"; + } +} \ No newline at end of file diff --git a/Constants/XHttpMethod.cs b/Constants/XHttpMethod.cs new file mode 100644 index 0000000..c74bd0a --- /dev/null +++ b/Constants/XHttpMethod.cs @@ -0,0 +1,17 @@ +using xExceptions.Attributes; + +namespace xHttpService.Constants { + public enum XHttpMethod { + [StringValue ("GET")] + GET, + + [StringValue ("POST")] + POST, + + [StringValue ("PUT")] + PUT, + + [StringValue ("DELETE")] + DELETE + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs new file mode 100644 index 0000000..a6303e1 --- /dev/null +++ b/DI/XDIHelperExtension.cs @@ -0,0 +1,97 @@ +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using xCommons.Extensions; +using xCommons.Models; +using xHttpService.Configurations; +using xHttpService.Constants; +using xHttpService.Interfaces; +using xHttpService.Providers; + +namespace xHttpService.DI { + public static partial class XDIHelperExtension { + /// + /// Retrieve XHttpService Configuration from AppSettings + /// + /// + /// + public static XHttpServiceConfiguration GetXHttpServiceConfiguration (this IConfiguration configuration) { + // + var xHttpSection = configuration.GetSection (ConfigurationNodeNames.HTTP_SERVICE_NODE_NAME); + return xHttpSection.Get (); + } + + /// + /// Register XHttpService Configuration + /// + /// + /// + public static void AddXHttpServiceConfiguration ( + this IServiceCollection services, + IConfiguration configuration + ) { + // + var httpServiceConfiguration = configuration.GetXHttpServiceConfiguration (); + services.AddXHttpServiceConfiguration(httpServiceConfiguration); + } + + /// + /// Register XHttpService Configuration + /// + /// + /// + public static void AddXHttpServiceConfiguration ( + this IServiceCollection services, + XHttpServiceConfiguration configuration + ) { + // + if (configuration.IsNull ()) { + Console.WriteLine($"xHttpService: there is no provided configurations, using default ..."); + configuration = new XHttpServiceConfiguration (); + } + + // + services.AddSingleton (configuration); + } + + /// + /// Register XHttpService on DI ... + /// + /// + /// + public static void AddXHttpService ( + this IServiceCollection services, + IConfiguration configuration + ) { + // + // Register Service Configuration ... + if (services.GetRegisteredService ().IsNull ()) { + services.AddXHttpServiceConfiguration (configuration); + } + + // + // Register Service ... + services.AddSingleton (); + } + + /// + /// Register XHttpService on DI ... + /// + /// + /// + public static void AddXHttpService ( + this IServiceCollection services, + XHttpServiceConfiguration configuration + ) { + // + // Register Service Configuration ... + if (services.GetRegisteredService ().IsNull ()) { + services.AddXHttpServiceConfiguration (configuration); + } + + // + // Register Service ... + services.AddSingleton (); + } + } +} \ No newline at end of file diff --git a/Extensions/RestSharpExtensions.cs b/Extensions/RestSharpExtensions.cs new file mode 100644 index 0000000..5d7eab5 --- /dev/null +++ b/Extensions/RestSharpExtensions.cs @@ -0,0 +1,189 @@ +using RestSharp; +using xCommons.Constants; +using xCommons.Extensions; +using xModels.Dtos; + +namespace xHttpService.Extensions { + public static partial class RestSharpExtensions { + /// + /// Attach an instance of XQuery to a RestRequest object + /// + /// + /// + /// + public static RestRequest AttachXQuery ( + this RestRequest source, + XQuery query + ) { + // + if (query.IsNull ()) { + return source; + } + + // + // ContainsDetail ... + // + var containsDetailKey = System.Uri.EscapeDataString (nameof (query.ContainsDetail)); + var containsDetailValue = query.ContainsDetail.AsHttpParamString (); + source.AddQueryParameter (containsDetailKey, containsDetailValue); + + // + // IsAscending ... + var isAscendingKey = System.Uri.EscapeDataString (nameof (query.IsAscending)); + var isAscendingValue = query.IsAscending.AsHttpParamString (); + source.AddQueryParameter (isAscendingKey, isAscendingValue); + + // + // Filter ... + if (!query.Filter.IsNullOrEmpty ()) { + // + var key = System.Uri.EscapeDataString (nameof (query.Filter)); + var value = query.Filter.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // SortBy ... + if (!query.SortBy.IsNullOrEmpty ()) { + // + var key = System.Uri.EscapeDataString (nameof (query.SortBy)); + var value = query.SortBy.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // Page ... + if (query.Page > 0) { + // + var key = System.Uri.EscapeDataString (nameof (query.Page)); + var value = query.Page.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // PageSize ... + if (query.PageSize > 0) { + // + var key = System.Uri.EscapeDataString (nameof (query.PageSize)); + var value = query.PageSize.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + return source; + } + + /// + /// Attach an instance of XPageRequest to a RestRequest object + /// + /// + /// + /// + public static RestRequest AttachXPageRequest ( + this RestRequest source, + XPageRequest request + ) { + // + if (request.IsNull ()) { + return source; + } + + // + // First ... + if (request.First.HasValue) { + // + var key = System.Uri.EscapeDataString (nameof (request.First)); + var value = request.First.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // Last ... + if (request.Last.HasValue) { + // + var key = System.Uri.EscapeDataString (nameof (request.Last)); + var value = request.Last.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // After ... + if (!request.After.IsNullOrEmpty ()) { + // + var key = System.Uri.EscapeDataString (nameof (request.After)); + var value = request.After.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // Before ... + if (!request.Before.IsNullOrEmpty ()) { + // + var key = System.Uri.EscapeDataString (nameof (request.Before)); + var value = request.Before.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // SortBy ... + if (!request.SortBy.IsNullOrEmpty ()) { + // + var key = System.Uri.EscapeDataString (nameof (request.SortBy)); + var value = request.SortBy.AsHttpParamString (); + source.AddQueryParameter (key, value); + } + + // + // DescendingSort ... + var descendingSortKey = System.Uri.EscapeDataString (nameof (request.DescendingSort)); + var descendingSortValue = request.DescendingSort.AsHttpParamString (); + source.AddQueryParameter (descendingSortKey, descendingSortValue); + + // + return source; + } + + /// + /// Add XPoweredBy Header to specific RestRequest Headers ... + /// + /// + /// + /// + public static RestRequest AddXPoweredBy ( + this RestRequest source, + string poweredByValue + ) { + // + source.AddHeader ( + XAuthorization.XPoweredBy, + poweredByValue + ); + + // + return source; + } + + /// + /// Add XAccessToken Header to specific RestRequest Headers ... + /// + /// + /// + /// + public static RestRequest AddXAccessToken ( + this RestRequest source, + string token + ) { + // + token = $"{XAuthentication.BEARER} {token}"; + + // + source.AddHeader ( + XAuthorization.Header, + token + ); + + // + return source; + } + } +} \ No newline at end of file diff --git a/Helpers/.gitkeep b/Helpers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Interfaces/IXHttpProvider.cs b/Interfaces/IXHttpProvider.cs new file mode 100644 index 0000000..6931a24 --- /dev/null +++ b/Interfaces/IXHttpProvider.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using RestSharp; +using xHttpService.Constants; +using xIdentityModels.Models; + +namespace xHttpService.Interfaces { + public partial interface IXHttpProvider { + HttpClient GetHttpClient (); + RestClient GetRestClient ( + string baseUrl = null, + string poweredByValue = null, + XTokenResponse tokens = null + ); + RestRequest GetRestRequet ( + string endpoint, + IDictionary @params = null, + IDictionary headers = null, + IDictionary queryStrings = null + ); + Task RunRestRequest ( + RestClient client, + RestRequest request, + XHttpMethod method + ); + } +} \ No newline at end of file diff --git a/Models/.gitkeep b/Models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Providers/XHttpProvider.cs b/Providers/XHttpProvider.cs new file mode 100644 index 0000000..036ce1c --- /dev/null +++ b/Providers/XHttpProvider.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using RestSharp; +using RestSharp.Authenticators; +using xCommons.Constants; +using xCommons.Extensions; +using xExceptions.Constants; +using xHttpService.Configurations; +using xHttpService.Constants; +using xHttpService.Interfaces; +using xIdentityModels.Models; +using xModels.Base; + +namespace xHttpService.Providers { + public partial class XHttpProvider : XBaseClass, IXHttpProvider { + + private readonly XHttpServiceConfiguration configuration; + + public XHttpProvider ( + ILoggerFactory loggerFactory, + XHttpServiceConfiguration configuration + ) : base (loggerFactory) { + this.configuration = configuration; + } + + // + #region Actions ... + /// + /// Get an Instance of Http Client + /// + /// + public HttpClient GetHttpClient () { + // + HttpClient httpClient = null; + httpClient = new HttpClient (); + + // + if (configuration.DisableSSLCheck) { + // + var httpHandler = new HttpClientHandler (); + httpHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + + // + httpClient = new HttpClient (httpHandler); + } + + // + // Set Timeout ... + httpClient.Timeout = TimeSpan + .FromSeconds (configuration.DefaultClientTimeout); + + // + return httpClient; + } + + /// + /// Get an Instance of RestClient + /// + /// + /// + /// + /// + public RestClient GetRestClient ( + string baseUrl = null, + string poweredByValue = null, + XTokenResponse tokens = null + ) { + // + var client = new RestClient (baseUrl); + + // + // Add XPowered By to Default Headers ... + if (!poweredByValue.IsNullOrEmpty ()) { + client.AddDefaultHeader (XAuthorization.XPoweredBy, poweredByValue); + } + + // + // Set Authenticator ... + if (!tokens.IsNull () && + !tokens.AccessToken.IsNullOrEmpty ()) { + client.Authenticator = new JwtAuthenticator (tokens.AccessToken); + } + + // + // Refresh Token ... + if (!tokens.IsNull () && + !tokens.RefreshToken.IsNullOrEmpty ()) { + client.AddDefaultHeader (XAuthorization.RefreshToken, tokens.RefreshToken); + } + + // + // ExpiresAt ... + if (!tokens.IsNull () && + tokens.ExpiresAt > 0) { + client.AddDefaultHeader (XAuthorization.ExpiresAt, tokens.ExpiresAt.AsHttpParamString ()); + } + + // + // Set Default Timeout ... + client.Timeout = configuration.DefaultClientTimeout; + + // + // SSL Validation Handler ... + if (configuration.DisableSSLCheck) { + client.RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true; + } + + // + return client; + } + + /// + /// Get an Instance of RestRequest + /// + /// + /// + /// + /// + /// + public RestRequest GetRestRequet ( + string endpoint, + IDictionary @params = null, + IDictionary headers = null, + IDictionary queryStrings = null + ) { + // + var url = endpoint.ToString (); + + // + // Add Route Payloads ... + if (!@params.IsNull () && @params.Count > 0) { + // + var enumerator = @params.GetEnumerator (); + while (enumerator.MoveNext ()) { + // + var item = enumerator.Current; + + // + url = url.Replace (item.Key, item.Value.ToUrlEncoded ()); + } + } + + // + // Add Query Strings ... + if (!queryStrings.IsNull () && queryStrings.Count > 0) { + // + url = $"{url}?"; + var enumerator = queryStrings.GetEnumerator (); + while (enumerator.MoveNext ()) { + // + var item = enumerator.Current; + + // + url += $"{item.Key}={item.Value.ToUrlEncoded ()}&"; + } + + // + // remove lates & ... + if (url.EndsWith ("&")) { + url = url.Substring (0, url.Length - 1); + } + } + + // + // Create request ... + var request = new RestRequest (url, DataFormat.Json); + + // + // Add Headers to request ... + if (!headers.IsNull () && headers.Count > 0) { + // + var enumerator = headers.GetEnumerator (); + while (enumerator.MoveNext ()) { + // + var item = enumerator.Current; + request.AddHeader (item.Key, item.Value); + } + } + + // + return request; + } + + /// + /// Handle Call Specific Request and retrieve Response + /// + /// + /// + /// + /// + /// + public async Task RunRestRequest ( + RestClient client, + RestRequest request, + XHttpMethod method + ) { + // + var response = await Task.Run (() => { + // + IRestResponse resp = null; + + // + // Call Endpoint Service using Specified Method ... + switch (method) { + // + // Get ... + case XHttpMethod.GET: + resp = client.Get (request); + break; + + // + // Put ... + case XHttpMethod.PUT: + resp = client.Put (request); + break; + + // + // Post ... + case XHttpMethod.POST: + resp = client.Post (request); + break; + + // + // Delete ... + case XHttpMethod.DELETE: + resp = client.Delete (request); + break; + } + + // + if (!resp.IsSuccessful) { + // + // UnAuthorized ... + if (resp.StatusCode == System.Net.HttpStatusCode.Unauthorized) { + XException.NotAuthorized.Throw (); + } + + // + // NotFound ... + if (resp.StatusCode == System.Net.HttpStatusCode.NotFound) { + XException.NotFound.Throw (); + } + + // + // Timeout ... + if (!resp.ErrorMessage.IsNullOrEmpty () && + resp.ErrorMessage.Contains ("timed out")) { + XException.Timeout.Throw (); + } + + // + // ErrorMessage ... + if (!resp.ErrorMessage.IsNullOrEmpty ()) { + throw new Exception (resp.ErrorMessage); + } + + // + // Default Exception ... + XException.BadRequest.Throw (); + } + + // + var result = resp.Content.FromJSON (); + return result; + }); + + // + return response; + } + #endregion + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f15f346 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# xHttpService + +it is a part of xDashboard project which contains: + +- required tools to call api endpoints. +- add and retrieve OAuth tokens based on xDashboard implementation. +- ... + +## Maintainer + +Hadi Khazaee asl + +[https://www.saherelm.ir](https://www.saherelm.ir) + +[hadi_khazaee_asl@yahoo.com](mailto:hadi_khazaee_asl@yahoo.com) diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..87b6eb0 --- /dev/null +++ b/nuget.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/xHttpService.csproj b/xHttpService.csproj new file mode 100644 index 0000000..f3bcfaa --- /dev/null +++ b/xHttpService.csproj @@ -0,0 +1,36 @@ + + + + + netstandard2.0 + xDashboard.xHttpService + 1.0.0 + Hadi Khazaee Asl + SaherElm IT Center + + provide all required tools for calling Http Apis and OAuth handling to xDashboard project. + + + + icon.png + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file