diff --git a/CoinGecko.Net.UnitTests/RestRequestTests.cs b/CoinGecko.Net.UnitTests/RestRequestTests.cs index 8419bd4..e6c5d10 100644 --- a/CoinGecko.Net.UnitTests/RestRequestTests.cs +++ b/CoinGecko.Net.UnitTests/RestRequestTests.cs @@ -19,7 +19,7 @@ public async Task ValidateAuthCalls() var client = new CoinGeckoRestClient(opts => { opts.AutoTimestamp = false; - opts.ApiCredentials = new Objects.CoinGeckoApiCredentials("123"); + opts.ApiCredentials = new CoinGeckoCredentials("123"); }); var tester = new RestRequestValidator(client, "Endpoints", "https://pro-api.coingecko.com", IsAuthenticated); await tester.ValidateAsync(client => client.Api.GetApiUsageAsync(), "GetApiUsage"); diff --git a/CoinGecko.Net/Clients/CoinGeckoRestClient.cs b/CoinGecko.Net/Clients/CoinGeckoRestClient.cs index 3692f1b..6916b1d 100644 --- a/CoinGecko.Net/Clients/CoinGeckoRestClient.cs +++ b/CoinGecko.Net/Clients/CoinGeckoRestClient.cs @@ -10,7 +10,7 @@ namespace CoinGecko.Net.Clients { /// - public class CoinGeckoRestClient: BaseRestClient, ICoinGeckoRestClient + public class CoinGeckoRestClient: BaseRestClient, ICoinGeckoRestClient { /// public ICoinGeckoRestClientApi Api { get; } @@ -40,12 +40,6 @@ public CoinGeckoRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory } #endregion - /// - public void SetOptions(UpdateOptions options) - { - Api.SetOptions(options); - } - /// /// Set the default options to be used when creating new clients /// diff --git a/CoinGecko.Net/Clients/CoinGeckoRestClientApi.cs b/CoinGecko.Net/Clients/CoinGeckoRestClientApi.cs index c6e554c..dfb519b 100644 --- a/CoinGecko.Net/Clients/CoinGeckoRestClientApi.cs +++ b/CoinGecko.Net/Clients/CoinGeckoRestClientApi.cs @@ -24,7 +24,7 @@ namespace CoinGecko.Net.Clients { /// - internal class CoinGeckoRestClientApi : RestApiClient, ICoinGeckoRestClientApi + internal class CoinGeckoRestClientApi : RestApiClient, ICoinGeckoRestClientApi { private static readonly RequestDefinitionCache _definitions = new RequestDefinitionCache(); private readonly CoinGeckoRestOptions _options; @@ -676,6 +676,7 @@ private string GetBaseAddress() } /// - protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) => new CoinGeckoAuthenticationProvider((CoinGeckoApiCredentials)credentials); + protected override CoinGeckoAuthenticationProvider CreateAuthenticationProvider(CoinGeckoCredentials credentials) + => new CoinGeckoAuthenticationProvider(credentials); } } diff --git a/CoinGecko.Net/CoinGecko.Net.csproj b/CoinGecko.Net/CoinGecko.Net.csproj index 0ea3246..302efa1 100644 --- a/CoinGecko.Net/CoinGecko.Net.csproj +++ b/CoinGecko.Net/CoinGecko.Net.csproj @@ -23,6 +23,7 @@ true true https://github.com/JKorf/CoinGecko.Net?tab=readme-ov-file#release-notes + $(NoWarn);SYSLIB1100;SYSLIB1101 true @@ -52,7 +53,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/CoinGecko.Net/CoinGeckoAuthenticationProvider.cs b/CoinGecko.Net/CoinGeckoAuthenticationProvider.cs index 147e828..dbeba15 100644 --- a/CoinGecko.Net/CoinGeckoAuthenticationProvider.cs +++ b/CoinGecko.Net/CoinGeckoAuthenticationProvider.cs @@ -6,16 +6,14 @@ namespace CoinGecko.Net { - internal class CoinGeckoAuthenticationProvider : AuthenticationProvider + internal class CoinGeckoAuthenticationProvider : AuthenticationProvider { /// /// Whether or not a demo key is configured /// - public bool IsDemo => _credentials.DemoKey; + public bool IsDemo => ApiCredentials.DemoKey; - public override ApiCredentialsType[] SupportedCredentialTypes => [ApiCredentialsType.Hmac]; - - public CoinGeckoAuthenticationProvider(CoinGeckoApiCredentials credentials) : base(credentials) + public CoinGeckoAuthenticationProvider(CoinGeckoCredentials credentials) : base(credentials, credentials.Credential) { } @@ -23,10 +21,10 @@ public override void ProcessRequest(RestApiClient apiClient, RestRequestConfigur { request.QueryParameters ??= new Dictionary(); - if (_credentials.DemoKey) - request.QueryParameters.Add("x_cg_demo_api_key", _credentials.Key); + if (IsDemo) + request.QueryParameters.Add("x_cg_demo_api_key", Credential.Key); else - request.QueryParameters.Add("x_cg_pro_api_key", _credentials.Key); + request.QueryParameters.Add("x_cg_pro_api_key", Credential.Key); } } } diff --git a/CoinGecko.Net/CoinGeckoCredentials.cs b/CoinGecko.Net/CoinGeckoCredentials.cs new file mode 100644 index 0000000..41c437f --- /dev/null +++ b/CoinGecko.Net/CoinGeckoCredentials.cs @@ -0,0 +1,74 @@ +using CryptoExchange.Net.Authentication; +using System; + +namespace CoinGecko.Net +{ + /// + /// CoinGecko credentials + /// + public class CoinGeckoCredentials : ApiCredentials + { + /// + /// Whether using a demo key + /// + public bool DemoKey { get; set; } + + /// + /// API key credential + /// + public ApiKeyCredential Credential { get; set; } + + /// + /// Create new credentials + /// +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + public CoinGeckoCredentials() { } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + + /// + /// Create new credentials providing Api key credentials + /// + /// Api key credentials + public CoinGeckoCredentials(ApiKeyCredential credential) + { + Credential = credential; + } + + /// + /// Create new credentials providing Api key credentials + /// + /// The API key + /// Whether this is a demo key + public CoinGeckoCredentials(string key, bool demoKey = false) + { + Credential = new ApiKeyCredential(key); + DemoKey = demoKey; + } + + /// + /// Specify the ApiKey + /// + /// The API key + /// Whether this is a demo key + public CoinGeckoCredentials WithApiKey(string key, bool demoKey = false) + { + if (Credential != null) throw new InvalidOperationException("Credentials already set"); + + DemoKey = demoKey; + Credential = new ApiKeyCredential(key); + return this; + } + + /// + public override ApiCredentials Copy() => new CoinGeckoCredentials { Credential = Credential }; + + /// + public override void Validate() + { + if (Credential == null) + throw new ArgumentException($"No credentials provided on {GetType().Name}"); + + Credential.Validate(); + } + } +} diff --git a/CoinGecko.Net/CryptoClientExtensions.cs b/CoinGecko.Net/CryptoClientExtensions.cs deleted file mode 100644 index acd6da6..0000000 --- a/CoinGecko.Net/CryptoClientExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using CoinGecko.Net.Clients; -using CoinGecko.Net.Interfaces; -using CryptoExchange.Net.Interfaces; -using CryptoExchange.Net.Interfaces.Clients; - -namespace CryptoExchange.Net.Clients -{ - /// - /// Extensions for the ICryptoRestClient and ICryptoSocketClient interfaces - /// - public static class CryptoClientExtensions - { - /// - /// Get the CoinGecko REST Api client - /// - /// - /// - public static ICoinGeckoRestClient CoinGecko(this ICryptoRestClient baseClient) => baseClient.TryGet(() => new CoinGeckoRestClient()); - } -} diff --git a/CoinGecko.Net/ExtensionMethods/CryptoClientExtensions.cs b/CoinGecko.Net/ExtensionMethods/CryptoClientExtensions.cs deleted file mode 100644 index 363db9b..0000000 --- a/CoinGecko.Net/ExtensionMethods/CryptoClientExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using CoinGecko.Net.Clients; -using CoinGecko.Net.Interfaces; -using CryptoExchange.Net.Interfaces.Clients; - -namespace CryptoExchange.Net.Interfaces -{ - /// - /// Extensions for the ICryptoRestClient and ICryptoSocketClient interfaces - /// - public static class CryptoClientExtensions - { - /// - /// Get the CoinGecko REST Api client - /// - /// - /// - public static ICoinGeckoRestClient CoinGecko(this ICryptoRestClient baseClient) => baseClient.TryGet(() => new CoinGeckoRestClient()); - } -} diff --git a/CoinGecko.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/CoinGecko.Net/ExtensionMethods/ServiceCollectionExtensions.cs index b7c227e..c4958fc 100644 --- a/CoinGecko.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/CoinGecko.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -21,6 +21,7 @@ public static class ServiceCollectionExtensions { /// /// Add services such as the ICoinGeckoRestClient. Configures the services based on the provided configuration. + /// See for an example of how to set up the configuration. /// /// The service collection /// The configuration(section) containing the options @@ -30,7 +31,15 @@ public static IServiceCollection AddCoinGecko( IConfiguration configuration) { var options = new CoinGeckoRestOptions(); - configuration.Bind(options); + + try + { + configuration.Bind(options); + } + catch (InvalidOperationException ex) + { + throw new InvalidOperationException("Invalid configuration provided", ex); + } var restEnvName = options.Environment?.Name ?? options.Environment?.Name ?? CoinGeckoEnvironment.Live.Name; options.Environment = CoinGeckoEnvironment.GetEnvironmentByName(restEnvName) ?? options.Environment!; @@ -69,7 +78,6 @@ private static IServiceCollection AddCoinGeckoCore( return LibraryHelpers.CreateHttpClientMessageHandler(options); }).SetHandlerLifetime(Timeout.InfiniteTimeSpan); - services.AddTransient(); return services; } } diff --git a/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs b/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs index f3b3bfc..a47ec22 100644 --- a/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs +++ b/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs @@ -1,22 +1,17 @@ -using CryptoExchange.Net.Objects.Options; +using CryptoExchange.Net.Interfaces.Clients; +using CryptoExchange.Net.Objects.Options; namespace CoinGecko.Net.Interfaces { /// /// Client for accessing the CoinGecko Rest API. /// - public interface ICoinGeckoRestClient + public interface ICoinGeckoRestClient : IRestClient { /// /// Api endpoints /// /// ICoinGeckoRestClientApi Api { get; } - - /// - /// Update specific options - /// - /// Options to update. Only specific options are changeable after the client has been created - void SetOptions(UpdateOptions options); } } diff --git a/CoinGecko.Net/Interfaces/ICoinGeckoRestClientApi.cs b/CoinGecko.Net/Interfaces/ICoinGeckoRestClientApi.cs index 6d79ffd..753cf1d 100644 --- a/CoinGecko.Net/Interfaces/ICoinGeckoRestClientApi.cs +++ b/CoinGecko.Net/Interfaces/ICoinGeckoRestClientApi.cs @@ -13,7 +13,7 @@ namespace CoinGecko.Net.Interfaces /// /// CoinGecko API endpoints /// - public interface ICoinGeckoRestClientApi: IRestApiClient + public interface ICoinGeckoRestClientApi: IRestApiClient { /// /// Get asset categories diff --git a/CoinGecko.Net/Objects/CoinGeckoApiCredentials.cs b/CoinGecko.Net/Objects/CoinGeckoApiCredentials.cs deleted file mode 100644 index 97162f1..0000000 --- a/CoinGecko.Net/Objects/CoinGeckoApiCredentials.cs +++ /dev/null @@ -1,34 +0,0 @@ -using CryptoExchange.Net.Authentication; - -namespace CoinGecko.Net.Objects -{ - /// - /// CoinGecko API credentials - /// - public class CoinGeckoApiCredentials : ApiCredentials - { - /// - /// Wheter using a demo key - /// - public bool DemoKey { get; } - - /// - /// ctor - /// - /// The API key - /// Whether or not this is a demo key - public CoinGeckoApiCredentials(string key, bool demoKey = false) : base(key, "-") - { - DemoKey = demoKey; - } - - /// - /// Copy - /// - /// - public override ApiCredentials Copy() - { - return new CoinGeckoApiCredentials(Key, DemoKey); - } - } -} diff --git a/CoinGecko.Net/Objects/Options/CoinGeckoRestOptions.cs b/CoinGecko.Net/Objects/Options/CoinGeckoRestOptions.cs index 4eefb7b..e251e5f 100644 --- a/CoinGecko.Net/Objects/Options/CoinGeckoRestOptions.cs +++ b/CoinGecko.Net/Objects/Options/CoinGeckoRestOptions.cs @@ -5,7 +5,7 @@ namespace CoinGecko.Net.Objects.Options /// /// CoinGecko Rest API options /// - public class CoinGeckoRestOptions : RestExchangeOptions + public class CoinGeckoRestOptions : RestExchangeOptions { /// /// Default options for the CoinGecko client diff --git a/Examples/example-config.json b/Examples/example-config.json new file mode 100644 index 0000000..02bf49f --- /dev/null +++ b/Examples/example-config.json @@ -0,0 +1,25 @@ +{ + // Options section, select this section during DI registration using Configuration.GetSection("CoinGecko") + "CoinGecko": { + // API credentials for both REST and Websocket client + "ApiCredentials": { + "DemoKey": false, + "Credential": { + "Key": "APIKEY" + } + }, + // Set the environment by name + "Environment": { + "name": "live" + }, + "RequestTimeout": "00:00:20", + "CachingEnabled": true, + "OutputOriginalData": true, + "Proxy": { + "Host": "https://127.0.0.1", + "Port": 8080, + "Login": "User", + "Password": "Pass" + } + } +} \ No newline at end of file