/******************************************************************************* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * AWS SDK for .NET * */ using System; using System.ComponentModel; using System.Globalization; using Amazon.Util; using Amazon.Util.Internal; using System.Collections.Generic; using Amazon.Runtime; namespace Amazon { /// /// Configuration options that apply to the entire SDK. /// /// These settings can be configured through app.config or web.config. /// Below is a full sample configuration that illustrates all the possible options. /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws region="us-west-2"> /// <logging logTo="Log4Net, SystemDiagnostics" logResponses="Always" logMetrics="true" /> /// <s3 useSignatureVersion4="true" /> /// <proxy host="localhost" port="8888" username="1" password="1" /> /// /// <dynamoDB> /// <dynamoDBContext tableNamePrefix="Prod-"> /// /// <tableAliases> /// <alias fromTable="FakeTable" toTable="People" /> /// <alias fromTable="Persons" toTable="People" /> /// </tableAliases> /// /// <mappings> /// <map type="Sample.Tests.Author, SampleDLL" targetTable="People" /> /// <map type="Sample.Tests.Editor, SampleDLL" targetTable="People"> /// <property name="FullName" attribute="Name" /> /// <property name="EmployeeId" attribute="Id" /> /// <property name="ComplexData" converter="Sample.Tests.ComplexDataConverter, SampleDLL" /> /// <property name="Version" version="true" /> /// <property name="Password" ignore="true" /> /// </map> /// </mappings> /// /// </dynamoDBContext> /// </dynamoDB> /// </aws> /// /// public static partial class AWSConfigs { #region Private static members private static char[] validSeparators = new char[] { ' ', ',' }; // Tests can override this DateTime source. internal static Func utcNowSource = GetUtcNow; // Deprecated configs internal static string _awsRegion = GetConfig(AWSRegionKey); internal static LoggingOptions _logging = GetLoggingSetting(); internal static ResponseLoggingOption _responseLogging = GetConfigEnum(ResponseLoggingKey); internal static bool _logMetrics = GetConfigBool(LogMetricsKey); internal static string _endpointDefinition = GetConfig(EndpointDefinitionKey); internal static string _awsProfileName = GetConfig(AWSProfileNameKey); internal static string _awsAccountsLocation = GetConfig(AWSProfilesLocationKey); internal static bool _useSdkCache = GetConfigBool(UseSdkCacheKey, defaultValue: true); // for reading from awsconfigs.xml private static object _lock = new object(); private static List standardConfigs = new List() { "region", "logging", "correctForClockSkew" }; #pragma warning disable 414 private static bool configPresent = true; #pragma warning restore 414 // New config section private static RootConfig _rootConfig = new RootConfig(); #endregion #region Clock Skew /// /// Manual offset to apply to client clock. This is a global setting that overrides /// ClockOffset value calculated for all service endpoints. /// public static TimeSpan? ManualClockCorrection { get { return Runtime.CorrectClockSkew.GlobalClockCorrection; } set { Runtime.CorrectClockSkew.GlobalClockCorrection = value; } } /// /// Determines if the SDK should correct for client clock skew /// by determining the correct server time and reissuing the /// request with the correct time. /// Default value of this field is True. /// will be updated with the calculated /// offset even if this field is set to false, though requests /// will not be corrected or retried. /// Ignored if is set. /// public static bool CorrectForClockSkew { get { return _rootConfig.CorrectForClockSkew; } set { _rootConfig.CorrectForClockSkew = value; } } /// /// The calculated clock skew correction, if there is one. /// This field will be set if a service call resulted in an exception /// and the SDK has determined that there is a difference between local /// and server times. /// /// If is set to true, this /// value will be set to the correction, but it will not be used by the /// SDK and clock skew errors will not be retried. /// [Obsolete("This value is deprecated in favor of IClientConfig.ClockOffset")] public static TimeSpan ClockOffset { get; internal set; } #endregion #region Region /// /// Key for the AWSRegion property. /// /// public const string AWSRegionKey = "AWSRegion"; /// /// Configures the default AWS region for clients which have not explicitly specified a region. /// Changes to this setting will only take effect for newly constructed instances of AWS clients. /// /// This setting can be configured through the App.config. For example: /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws region="us-west-2" /> /// /// public static string AWSRegion { get { return _rootConfig.Region; } set { _rootConfig.Region = value; } } #endregion #region Account Name /// /// Key for the AWSProfileName property. /// /// public const string AWSProfileNameKey = "AWSProfileName"; /// /// Profile name for stored AWS credentials that will be used to make service calls. /// Changes to this setting will only take effect in newly-constructed clients. /// /// To reference the account from an application's App.config or Web.config use the AWSProfileName setting. /// /// <?xml version="1.0" encoding="utf-8" ?> /// <configuration> /// <appSettings> /// <add key="AWSProfileName" value="development"/> /// </appSettings> /// </configuration> /// /// /// public static string AWSProfileName { get { return _rootConfig.ProfileName; } set { _rootConfig.ProfileName = value; } } #endregion #region Accounts Location /// /// Key for the AWSProfilesLocation property. /// /// public const string AWSProfilesLocationKey = "AWSProfilesLocation"; /// /// Location of the credentials file shared with other AWS SDKs. /// By default, the credentials file is stored in the .aws directory in the current user's home directory. /// /// Changes to this setting will only take effect in newly-constructed clients. /// /// To reference the profile from an application's App.config or Web.config use the AWSProfileName setting. /// /// <?xml version="1.0" encoding="utf-8" ?> /// <configuration> /// <appSettings> /// <add key="AWSProfilesLocation" value="c:\config"/> /// </appSettings> /// </configuration> /// /// /// public static string AWSProfilesLocation { get { return _rootConfig.ProfilesLocation; } set { _rootConfig.ProfilesLocation = value; } } #endregion #region Logging /// /// Key for the Logging property. /// /// public const string LoggingKey = "AWSLogging"; /// /// Configures how the SDK should log events, if at all. /// Changes to this setting will only take effect in newly-constructed clients. /// /// The setting can be configured through App.config, for example: /// /// <appSettings> /// <add key="AWSLogging" value="log4net"/> /// </appSettings> /// /// [Obsolete("This property is obsolete. Use LoggingConfig.LogTo instead.")] public static LoggingOptions Logging { get { return _rootConfig.Logging.LogTo; } set { _rootConfig.Logging.LogTo = value; } } private static LoggingOptions GetLoggingSetting() { string value = GetConfig(LoggingKey); if (string.IsNullOrEmpty(value)) return LoggingOptions.None; string[] settings = value.Split(validSeparators, StringSplitOptions.RemoveEmptyEntries); if (settings == null || settings.Length == 0) return LoggingOptions.None; LoggingOptions totalSetting = LoggingOptions.None; foreach (string setting in settings) { LoggingOptions l = ParseEnum(setting); totalSetting |= l; } return totalSetting; } #endregion #region Response Logging /// /// Key for the ResponseLogging property. /// /// /// public const string ResponseLoggingKey = "AWSResponseLogging"; /// /// Configures when the SDK should log service responses. /// Changes to this setting will take effect immediately. /// /// The setting can be configured through App.config, for example: /// /// <appSettings> /// <add key="AWSResponseLogging" value="OnError"/> /// </appSettings> /// /// [Obsolete("This property is obsolete. Use LoggingConfig.LogResponses instead.")] public static ResponseLoggingOption ResponseLogging { get { return _rootConfig.Logging.LogResponses; } set { _rootConfig.Logging.LogResponses = value; } } #endregion #region Log Metrics /// /// Key for the LogMetrics property. /// /// public const string LogMetricsKey = "AWSLogMetrics"; /// /// Configures if the SDK should log performance metrics. /// This setting configures the default LogMetrics property for all clients/configs. /// Changes to this setting will only take effect in newly-constructed clients. /// /// The setting can be configured through App.config, for example: /// /// <appSettings> /// <add key="AWSLogMetrics" value="true"/> /// </appSettings> /// /// [Obsolete("This property is obsolete. Use LoggingConfig.LogMetrics instead.")] public static bool LogMetrics { get { return _rootConfig.Logging.LogMetrics; } set { _rootConfig.Logging.LogMetrics = value; } } #endregion #region Endpoint Configuration /// /// Key for the EndpointDefinition property. /// /// public const string EndpointDefinitionKey = "AWSEndpointDefinition"; /// /// Configures if the SDK should use a custom configuration file that defines the regions and endpoints. /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws endpointDefinition="c:\config\endpoints.json" /> /// /// public static string EndpointDefinition { get { return _rootConfig.EndpointDefinition; } set { _rootConfig.EndpointDefinition = value; } } #endregion #region SDK Cache /// /// Key for the UseSdkCache property. /// /// public const string UseSdkCacheKey = "AWSCache"; /// /// Configures if the SDK Cache should be used, the default value is true. /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws useSdkCache="true" /> /// /// public static bool UseSdkCache { get { return _rootConfig.UseSdkCache; } set { _rootConfig.UseSdkCache = value; } } #endregion #region AWS Config Sections /// /// Configuration for the Logging section of AWS configuration. /// Changes to some settings may not take effect until a new client is constructed. /// /// Example section: /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws> /// <logging logTo="Log4Net, SystemDiagnostics" logResponses="Always" logMetrics="true" /> /// </aws> /// /// public static LoggingConfig LoggingConfig { get { return _rootConfig.Logging; } } /// /// Configuration for the Proxy section of AWS configuration. /// Changes to some settings may not take effect until a new client is constructed. /// /// Example section: /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws> /// <proxy host="localhost" port="8888" username="1" password="1" bypassList="addressexpr1;addressexpr2;..." bypassOnLocal="true" /> /// </aws> /// /// public static ProxyConfig ProxyConfig { get { return _rootConfig.Proxy; } } /// /// When set to true, the service client will use the x-amz-user-agent /// header instead of the User-Agent header to report version and /// environment information to the AWS service. /// /// Note: This is especially useful when using a platform like WebAssembly /// which doesn't allow to specify the User-Agent header. /// public static bool UseAlternateUserAgentHeader { get { return _rootConfig.UseAlternateUserAgentHeader; } set { _rootConfig.UseAlternateUserAgentHeader = value; } } /// /// Configuration for the region endpoint section of AWS configuration. /// Changes may not take effect until a new client is constructed. /// /// Example section: /// /// <configSections> /// <section name="aws" type="Amazon.AWSSection, AWSSDK.Core"/> /// </configSections> /// <aws region="us-west-2" /> /// /// public static RegionEndpoint RegionEndpoint { get { return _rootConfig.RegionEndpoint; } set { _rootConfig.RegionEndpoint = value; } } public static CSMConfig CSMConfig { get { return _rootConfig.CSMConfig; } set { _rootConfig.CSMConfig = value; } } #endregion #region Internal members internal const string LoggingDestinationProperty = "LogTo"; internal static PropertyChangedEventHandler mPropertyChanged; /// /// Lock for SomeEvent delegate access. /// internal static readonly object propertyChangedLock = new object(); internal static event PropertyChangedEventHandler PropertyChanged { add { lock (propertyChangedLock) { mPropertyChanged += value; } } remove { lock (propertyChangedLock) { mPropertyChanged -= value; } } } internal static void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = mPropertyChanged; if (handler != null) { handler(null, new PropertyChangedEventArgs(name)); } } #endregion #region Private general methods private static bool GetConfigBool(string name, bool defaultValue = false) { string value = GetConfig(name); bool result; if (bool.TryParse(value, out result)) return result; return defaultValue; } private static T GetConfigEnum(string name) { var type = TypeFactory.GetTypeInfo(typeof(T)); if (!type.IsEnum) throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Type {0} must be enum", type.FullName)); string value = GetConfig(name); if (string.IsNullOrEmpty(value)) return default(T); T result = ParseEnum(value); return result; } private static T ParseEnum(string value) { T t; if (TryParseEnum(value, out t)) return t; Type type = typeof(T); string messageFormat = "Unable to parse value {0} as enum of type {1}. Valid values are: {2}"; string enumNames = string.Join(", ", Enum.GetNames(type)); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, messageFormat, value, type.FullName, enumNames)); } private static bool TryParseEnum(string value, out T result) { result = default(T); if (string.IsNullOrEmpty(value)) return false; try { T t = (T)Enum.Parse(typeof(T), value, true); result = t; return true; } catch (ArgumentException) { return false; } } /// /// This method should never be called directly. /// Call AWSSDKUtils.CorrectedUtcNow instead. /// /// [System.Diagnostics.CodeAnalysis.SuppressMessage("AwsSdkRules", "CR1003:PreventDateTimeNowUseRule")] private static DateTime GetUtcNow() { return DateTime.UtcNow; } #endregion } /// /// Logging options. /// Can be combined to enable multiple loggers. /// [Flags] public enum LoggingOptions { /// /// No logging /// None = 0, /// /// Log using log4net /// Log4Net = 1, /// /// Log using System.Diagnostics /// SystemDiagnostics = 2, /// /// Log to the console /// Console = 16 } /// /// Response logging option. /// public enum ResponseLoggingOption { /// /// Never log service response /// Never = 0, /// /// Only log service response when there's an error /// OnError = 1, /// /// Always log service response /// Always = 2 } /// /// Format for metrics data in the logs /// public enum LogMetricsFormatOption { /// /// Emit metrics in human-readable format /// Standard = 0, /// /// Emit metrics as JSON data /// JSON = 1 } }