
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Configurations\XHttpServiceConfiguration.cs

namespace xHttpService.Configurations {
    public partial class XHttpServiceConfiguration {
        /// <summary>
        /// Determines Http Handler Check SSL or not ...
        /// </summary>
        /// <value></value>
        public bool DisableSSLCheck { get; set; }
        public int DefaultClientTimeout { get; set; } = 360;
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Constants\ConfigurationNodeNames.cs

namespace xHttpService.Constants {
    public partial struct ConfigurationNodeNames {
        public const string HTTP_SERVICE_NODE_NAME = "HttpServiceConfiguration";
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Constants\XHttpMethod.cs

using xExceptions.Attributes;

namespace xHttpService.Constants {
    public enum XHttpMethod {
        [StringValue ("GET")]
        GET,

        [StringValue ("POST")]
        POST,

        [StringValue ("PUT")]
        PUT,

        [StringValue ("DELETE")]
        DELETE
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\DI\XDIHelperExtension.cs

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using xCommons.Extensions;
using xHttpService.Configurations;
using xHttpService.Constants;
using xHttpService.Interfaces;
using xHttpService.Providers;

namespace xHttpService.DI {
    public static partial class XDIHelperExtension {
        /// <summary>
        /// Retrieve XHttpService Configuration from AppSettings
        /// </summary>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static XHttpServiceConfiguration GetXHttpServiceConfiguration (this IConfiguration configuration) {
            //
            var xHttpSection = configuration.GetSection (ConfigurationNodeNames.HTTP_SERVICE_NODE_NAME);
            return xHttpSection.Get<XHttpServiceConfiguration> ();
        }

        /// <summary>
        /// Register XHttpService Configuration
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddXHttpServiceConfiguration (
            this IServiceCollection services,
            IConfiguration configuration
        ) {
            //
            var httpServiceConfiguration = configuration.GetXHttpServiceConfiguration ();
            services.AddXHttpServiceConfiguration(httpServiceConfiguration);
        }

        /// <summary>
        /// Register XHttpService Configuration
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        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<XHttpServiceConfiguration> (configuration);
        }

        /// <summary>
        /// Register XHttpService on DI ...
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddXHttpService (
            this IServiceCollection services,
            IConfiguration configuration
        ) {
            //
            // Register Service Configuration ...
            if (services.GetRegisteredService<XHttpServiceConfiguration> ().IsNull ()) {
                services.AddXHttpServiceConfiguration (configuration);
            }

            //
            // Register Service ...
            services.AddSingleton<IXHttpProvider, XHttpProvider> ();
        }

        /// <summary>
        /// Register XHttpService on DI ...
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddXHttpService (
            this IServiceCollection services,
            XHttpServiceConfiguration configuration
        ) {
            //
            // Register Service Configuration ...
            if (services.GetRegisteredService<XHttpServiceConfiguration> ().IsNull ()) {
                services.AddXHttpServiceConfiguration (configuration);
            }

            //
            // Register Service ...
            services.AddSingleton<IXHttpProvider, XHttpProvider> ();
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Extensions\RestSharpExtensions.cs

using System.ComponentModel.DataAnnotations;
using AutoMapper.Mappers;
using RestSharp;
using xCommons.Constants;
using xCommons.Extensions;
using xModels.Dtos;

namespace xHttpService.Extensions
{
    public static partial class RestSharpExtensions
    {
        /// <summary>
        /// Attach an instance of XQuery to a RestRequest object
        /// </summary>
        /// <param name="source"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Add Dest User to Query Strings ...
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destUser"></param>
        /// <returns></returns>
        public static RestRequest AttachDestUser(
            this RestRequest source,
            string destUser
        )
        {
            //
            if (destUser.IsNullOrEmpty())
            {
                return source;
            }

            //
            var destUserKey = System.Uri.EscapeDataString(nameof(destUser));
            var destUserValue = destUser.AsHttpParamString();
            source.AddQueryParameter(destUserKey, destUserValue);

            //
            return source;
        }

        /// <summary>
        /// Add XPoweredBy Header to specific RestRequest Headers ...
        /// </summary>
        /// <param name="source"></param>
        /// <param name="poweredByValue"></param>
        /// <returns></returns>
        public static RestRequest AddXPoweredBy(
            this RestRequest source,
            string poweredByValue
        )
        {
            //
            source.AddHeader(
                XAuthorization.XPoweredBy,
                poweredByValue
            );

            //
            return source;
        }

        /// <summary>
        /// Add XAccessToken Header to specific RestRequest Headers ...
        /// </summary>
        /// <param name="source"></param>
        /// <param name="poweredByValue"></param>
        /// <returns></returns>
        public static RestRequest AddXAccessToken(
            this RestRequest source,
            string token
        )
        {
            //
            token = $"{XAuthentication.BEARER} {token}";

            //
            source.AddHeader(
                XAuthorization.Header,
                token
            );

            //
            return source;
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Interfaces\IXHttpProvider.cs

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<string, string> @params = null,
            IDictionary<string, string> headers = null,
            IDictionary<string, string> queryStrings = null
        );
        Task<T> RunRestRequest<T> (
            RestClient client,
            RestRequest request,
            XHttpMethod method
        );
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xHttpService\Providers\XHttpProvider.cs

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 ...
        /// <summary>
        /// Get an Instance of Http Client 
        /// </summary>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Get an Instance of RestClient
        /// </summary>
        /// <param name="baseUrl"></param>
        /// <param name="poweredByValue"></param>
        /// <param name="tokens"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Get an Instance of RestRequest 
        /// </summary>
        /// <param name="endpoint"></param>
        /// <param name="params"></param>
        /// <param name="headers"></param>
        /// <param name="queryStrings"></param>
        /// <returns></returns>
        public RestRequest GetRestRequet (
            string endpoint,
            IDictionary<string, string> @params = null,
            IDictionary<string, string> headers = null,
            IDictionary<string, string> 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;
        }

        /// <summary>
        /// Handle Call Specific Request and retrieve Response
        /// </summary>
        /// <param name="client"></param>
        /// <param name="request"></param>
        /// <param name="method"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public async Task<T> RunRestRequest<T> (
            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<T> ();
                return result;
            });

            //
            return response;
        }
        #endregion
    }
}
