diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 69914d8812..4acd15dadc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -46,6 +46,9 @@ Microsoft\Data\Common\ActivityCorrelator.cs + + Microsoft\Data\Common\DbConnectionStringCommon.cs + Microsoft\Data\Common\DbConnectionPoolKey.cs @@ -466,7 +469,6 @@ - Common\Microsoft\Data\ProviderBase\DbConnectionInternal.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 8f15f1b7a5..1fb9b7e0a3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -101,6 +101,9 @@ Microsoft\Data\Common\ActivityCorrelator.cs + + Microsoft\Data\Common\DbConnectionStringCommon.cs + Microsoft\Data\Common\DbConnectionPoolKey.cs @@ -542,7 +545,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs deleted file mode 100644 index 0e1a941d06..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ /dev/null @@ -1,1387 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using Microsoft.Data.SqlClient; - -namespace Microsoft.Data.Common -{ - - /* - internal sealed class NamedConnectionStringConverter : StringConverter { - - public NamedConnectionStringConverter() { - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { - return true; - } - - public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { - // Although theoretically this could be true, some people may want to just type in a name - return false; - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { - StandardValuesCollection standardValues = null; - if (null != context) { - DbConnectionStringBuilder instance = (context.Instance as DbConnectionStringBuilder); - if (null != instance) { - string myProviderName = instance.GetType().Namespace; - - List myConnectionNames = new List(); - foreach(System.Configuration.ConnectionStringSetting setting in System.Configuration.ConfigurationManager.ConnectionStrings) { - if (myProviderName.EndsWith(setting.ProviderName)) { - myConnectionNames.Add(setting.ConnectionName); - } - } - standardValues = new StandardValuesCollection(myConnectionNames); - } - } - return standardValues; - } - } - */ - - - [Serializable()] - internal sealed class ReadOnlyCollection : System.Collections.ICollection, ICollection - { - private T[] _items; - - internal ReadOnlyCollection(T[] items) - { - _items = items; -#if DEBUG - for (int i = 0; i < items.Length; ++i) - { - Debug.Assert(null != items[i], "null item"); - } -#endif - } - - public void CopyTo(T[] array, int arrayIndex) - { - Array.Copy(_items, 0, array, arrayIndex, _items.Length); - } - - void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) - { - Array.Copy(_items, 0, array, arrayIndex, _items.Length); - } - - - IEnumerator IEnumerable.GetEnumerator() - { - return new Enumerator(_items); - } - - public System.Collections.IEnumerator GetEnumerator() - { - return new Enumerator(_items); - } - - bool System.Collections.ICollection.IsSynchronized - { - get { return false; } - } - - Object System.Collections.ICollection.SyncRoot - { - get { return _items; } - } - - bool ICollection.IsReadOnly - { - get { return true; } - } - - void ICollection.Add(T value) - { - throw new NotSupportedException(); - } - - void ICollection.Clear() - { - throw new NotSupportedException(); - } - - bool ICollection.Contains(T value) - { - return Array.IndexOf(_items, value) >= 0; - } - - bool ICollection.Remove(T value) - { - throw new NotSupportedException(); - } - - public int Count - { - get { return _items.Length; } - } - - [Serializable()] - internal struct Enumerator : IEnumerator, System.Collections.IEnumerator - { // based on List.Enumerator - private K[] _items; - private int _index; - - internal Enumerator(K[] items) - { - _items = items; - _index = -1; - } - - public void Dispose() - { - } - - public bool MoveNext() - { - return (++_index < _items.Length); - } - - public K Current - { - get - { - return _items[_index]; - } - } - - Object System.Collections.IEnumerator.Current - { - get - { - return _items[_index]; - } - } - - void System.Collections.IEnumerator.Reset() - { - _index = -1; - } - } - } - - internal static class DbConnectionStringBuilderUtil - { - - internal static bool ConvertToBoolean(object value) - { - Debug.Assert(null != value, "ConvertToBoolean(null)"); - string svalue = (value as string); - if (null != svalue) - { - if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) - return false; - else - { - string tmp = svalue.Trim(); // Remove leading & trailing white space. - if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) - return false; - } - return Boolean.Parse(svalue); - } - try - { - return ((IConvertible)value).ToBoolean(CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(Boolean), e); - } - } - - internal static bool ConvertToIntegratedSecurity(object value) - { - Debug.Assert(null != value, "ConvertToIntegratedSecurity(null)"); - string svalue = (value as string); - if (null != svalue) - { - if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) - return false; - else - { - string tmp = svalue.Trim(); // Remove leading & trailing white space. - if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) - return false; - } - return Boolean.Parse(svalue); - } - try - { - return ((IConvertible)value).ToBoolean(CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(Boolean), e); - } - } - - internal static int ConvertToInt32(object value) - { - try - { - return ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(Int32), e); - } - } - - internal static string ConvertToString(object value) - { - try - { - return ((IConvertible)value).ToString(CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(String), e); - } - } - - #region <> - const string PoolBlockingPeriodAutoString = "Auto"; - const string PoolBlockingPeriodAlwaysBlockString = "AlwaysBlock"; - const string PoolBlockingPeriodNeverBlockString = "NeverBlock"; - - internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) - { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAutoString)) - { - result = PoolBlockingPeriod.Auto; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAlwaysBlockString)) - { - result = PoolBlockingPeriod.AlwaysBlock; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodNeverBlockString)) - { - result = PoolBlockingPeriod.NeverBlock; - return true; - } - else - { - result = DbConnectionStringDefaults.PoolBlockingPeriod; - return false; - } - } - - internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) - { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock; - } - - internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) - { - Debug.Assert(IsValidPoolBlockingPeriodValue(value)); - - if (value == PoolBlockingPeriod.AlwaysBlock) - { - return PoolBlockingPeriodAlwaysBlockString; - } - if (value == PoolBlockingPeriod.NeverBlock) - { - return PoolBlockingPeriodNeverBlockString; - } - else - { - return PoolBlockingPeriodAutoString; - } - } - - /// - /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: - /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer - /// * if the value is from type PoolBlockingPeriod, it will be used as is - /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum - /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException - /// - /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. - /// - /// PoolBlockingPeriod value in the valid range - internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) - { - Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)"); - string sValue = (value as string); - PoolBlockingPeriod result; - if (null != sValue) - { - // We could use Enum.TryParse here, but it accepts value combinations like - // "ReadOnly, ReadWrite" which are unwelcome here - // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - - if (TryConvertToPoolBlockingPeriod(sValue, out result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToPoolBlockingPeriod(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - PoolBlockingPeriod eValue; - - if (value is PoolBlockingPeriod) - { - // quick path for the most common case - eValue = (PoolBlockingPeriod)value; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-PoolBlockingPeriod enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); - } - } - - // ensure value is in valid range - if (IsValidPoolBlockingPeriodValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); - } - } - } - #endregion - - const string ApplicationIntentReadWriteString = "ReadWrite"; - const string ApplicationIntentReadOnlyString = "ReadOnly"; - - internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result) - { - Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); - Debug.Assert(null != value, "TryConvertToApplicationIntent(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadOnlyString)) - { - result = ApplicationIntent.ReadOnly; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadWriteString)) - { - result = ApplicationIntent.ReadWrite; - return true; - } - else - { - result = DbConnectionStringDefaults.ApplicationIntent; - return false; - } - } - - internal static bool IsValidApplicationIntentValue(ApplicationIntent value) - { - Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); - return value == ApplicationIntent.ReadOnly || value == ApplicationIntent.ReadWrite; - } - - internal static string ApplicationIntentToString(ApplicationIntent value) - { - Debug.Assert(IsValidApplicationIntentValue(value)); - if (value == ApplicationIntent.ReadOnly) - { - return ApplicationIntentReadOnlyString; - } - else - { - return ApplicationIntentReadWriteString; - } - } - - /// - /// This method attempts to convert the given value tp ApplicationIntent enum. The algorithm is: - /// * if the value is from type string, it will be matched against ApplicationIntent enum names only, using ordinal, case-insensitive comparer - /// * if the value is from type ApplicationIntent, it will be used as is - /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum - /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException - /// - /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. - /// - /// application intent value in the valid range - internal static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) - { - Debug.Assert(null != value, "ConvertToApplicationIntent(null)"); - string sValue = (value as string); - ApplicationIntent result; - if (null != sValue) - { - // We could use Enum.TryParse here, but it accepts value combinations like - // "ReadOnly, ReadWrite" which are unwelcome here - // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - - if (TryConvertToApplicationIntent(sValue, out result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToApplicationIntent(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - ApplicationIntent eValue; - - if (value is ApplicationIntent) - { - // quick path for the most common case - eValue = (ApplicationIntent)value; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-ApplicationIntent enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (ApplicationIntent)Enum.ToObject(typeof(ApplicationIntent), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), e); - } - } - - // ensure value is in valid range - if (IsValidApplicationIntentValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); - } - } - } - - const string SqlPasswordString = "Sql Password"; - const string ActiveDirectoryPasswordString = "Active Directory Password"; - const string ActiveDirectoryIntegratedString = "Active Directory Integrated"; - const string ActiveDirectoryInteractiveString = "Active Directory Interactive"; - const string ActiveDirectoryServicePrincipalString = "Active Directory Service Principal"; - const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow"; - internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity"; - internal const string ActiveDirectoryMSIString = "Active Directory MSI"; - internal const string ActiveDirectoryDefaultString = "Active Directory Default"; - // const string SqlCertificateString = "Sql Certificate"; - -#if DEBUG - private static string[] s_supportedAuthenticationModes = - { - "NotSpecified", - "SqlPassword", - "ActiveDirectoryPassword", - "ActiveDirectoryIntegrated", - "ActiveDirectoryInteractive", - "ActiveDirectoryServicePrincipal", - "ActiveDirectoryDeviceCodeFlow", - "ActiveDirectoryManagedIdentity", - "ActiveDirectoryMSI", - "ActiveDirectoryDefault" - }; - - private static bool IsValidAuthenticationMethodEnum() - { - string[] names = Enum.GetNames(typeof(SqlAuthenticationMethod)); - int l = s_supportedAuthenticationModes.Length; - bool listValid; - if (listValid = names.Length == l) - { - for (int i = 0; i < l; i++) - { - if (s_supportedAuthenticationModes[i].CompareTo(names[i]) != 0) - { - listValid = false; - } - } - } - return listValid; - } -#endif - - internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result) - { -#if DEBUG - Debug.Assert(IsValidAuthenticationMethodEnum(), "SqlAuthenticationMethod enum has changed, update needed"); -#endif - bool isSuccess = false; - - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.SqlPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryIntegrated, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryIntegrated; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryInteractiveString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryInteractive, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryInteractive; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryServicePrincipalString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryServicePrincipal; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDeviceCodeFlowString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryManagedIdentityString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryManagedIdentity; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryMSIString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryMSI, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryMSI; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDefault; - isSuccess = true; - } -#if ADONET_CERT_AUTH - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlCertificateString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlCertificate, CultureInfo.InvariantCulture))) { - result = SqlAuthenticationMethod.SqlCertificate; - isSuccess = true; - } -#endif - else - { - result = DbConnectionStringDefaults.Authentication; - } - return isSuccess; - } - - /// - /// Column Encryption Setting. - /// - const string ColumnEncryptionSettingEnabledString = "Enabled"; - const string ColumnEncryptionSettingDisabledString = "Disabled"; - - /// - /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting. - /// - /// - /// - /// - internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) - { - bool isSuccess = false; - - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingEnabledString)) - { - result = SqlConnectionColumnEncryptionSetting.Enabled; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingDisabledString)) - { - result = SqlConnectionColumnEncryptionSetting.Disabled; - isSuccess = true; - } - else - { - result = DbConnectionStringDefaults.ColumnEncryptionSetting; - } - - return isSuccess; - } - - /// - /// Is it a valid connection level column encryption setting ? - /// - /// - /// - internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) - { - Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed"); - return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled; - } - - /// - /// Convert connection level column encryption setting value to string. - /// - /// - /// - internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) - { - Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting."); - - switch (value) - { - case SqlConnectionColumnEncryptionSetting.Enabled: - return ColumnEncryptionSettingEnabledString; - case SqlConnectionColumnEncryptionSetting.Disabled: - return ColumnEncryptionSettingDisabledString; - - default: - return null; - } - } - - internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) - { - Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 10, "SqlAuthenticationMethod enum has changed, update needed"); - return value == SqlAuthenticationMethod.SqlPassword - || value == SqlAuthenticationMethod.ActiveDirectoryPassword - || value == SqlAuthenticationMethod.ActiveDirectoryIntegrated - || value == SqlAuthenticationMethod.ActiveDirectoryInteractive - || value == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal - || value == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow - || value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity - || value == SqlAuthenticationMethod.ActiveDirectoryMSI - || value == SqlAuthenticationMethod.ActiveDirectoryDefault -#if ADONET_CERT_AUTH - || value == SqlAuthenticationMethod.SqlCertificate -#endif - || value == SqlAuthenticationMethod.NotSpecified; - } - - internal static string AuthenticationTypeToString(SqlAuthenticationMethod value) - { - Debug.Assert(IsValidAuthenticationTypeValue(value)); - - switch (value) - { - case SqlAuthenticationMethod.SqlPassword: - return SqlPasswordString; - case SqlAuthenticationMethod.ActiveDirectoryPassword: - return ActiveDirectoryPasswordString; - case SqlAuthenticationMethod.ActiveDirectoryIntegrated: - return ActiveDirectoryIntegratedString; - case SqlAuthenticationMethod.ActiveDirectoryInteractive: - return ActiveDirectoryInteractiveString; - case SqlAuthenticationMethod.ActiveDirectoryServicePrincipal: - return ActiveDirectoryServicePrincipalString; - case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow: - return ActiveDirectoryDeviceCodeFlowString; - case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity: - return ActiveDirectoryManagedIdentityString; - case SqlAuthenticationMethod.ActiveDirectoryMSI: - return ActiveDirectoryMSIString; - case SqlAuthenticationMethod.ActiveDirectoryDefault: - return ActiveDirectoryDefaultString; -#if ADONET_CERT_AUTH - case SqlAuthenticationMethod.SqlCertificate: - return SqlCertificateString; -#endif - default: - return null; - } - } - - internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) - { - if (null == value) - { - return DbConnectionStringDefaults.Authentication; - } - - string sValue = (value as string); - SqlAuthenticationMethod result; - if (null != sValue) - { - if (TryConvertToAuthenticationType(sValue, out result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToAuthenticationType(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlAuthenticationMethod eValue; - - if (value is SqlAuthenticationMethod) - { - // quick path for the most common case - eValue = (SqlAuthenticationMethod)value; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-ApplicationIntent enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlAuthenticationMethod)Enum.ToObject(typeof(SqlAuthenticationMethod), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), e); - } - } - - // ensure value is in valid range - if (IsValidAuthenticationTypeValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlAuthenticationMethod), (int)eValue); - } - } - } - - /// - /// Convert the provided value to a SqlConnectionColumnEncryptionSetting. - /// - /// - /// - /// - internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSetting(string keyword, object value) - { - if (null == value) - { - return DbConnectionStringDefaults.ColumnEncryptionSetting; - } - - string sValue = (value as string); - SqlConnectionColumnEncryptionSetting result; - if (null != sValue) - { - if (TryConvertToColumnEncryptionSetting(sValue, out result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToColumnEncryptionSetting(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionColumnEncryptionSetting eValue; - - if (value is SqlConnectionColumnEncryptionSetting) - { - // quick path for the most common case - eValue = (SqlConnectionColumnEncryptionSetting)value; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionColumnEncryptionSetting"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionColumnEncryptionSetting enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionColumnEncryptionSetting)Enum.ToObject(typeof(SqlConnectionColumnEncryptionSetting), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), e); - } - } - - // ensure value is in valid range - if (IsValidColumnEncryptionSetting(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionColumnEncryptionSetting), (int)eValue); - } - } - } - - #region <> - - /// - /// Attestation Protocol. - /// - const string AttestationProtocolHGS = "HGS"; - const string AttestationProtocolAAS = "AAS"; -#if ENCLAVE_SIMULATOR - const string AttestationProtocolSIM = "SIM"; -#endif - - /// - /// Convert a string value to the corresponding SqlConnectionAttestationProtocol - /// - /// - /// - /// - internal static bool TryConvertToAttestationProtocol(string value, out SqlConnectionAttestationProtocol result) - { - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolHGS)) - { - result = SqlConnectionAttestationProtocol.HGS; - return true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolAAS)) - { - result = SqlConnectionAttestationProtocol.AAS; - return true; - } -#if ENCLAVE_SIMULATOR - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolSIM)) - { - result = SqlConnectionAttestationProtocol.SIM; - return true; - } -#endif - else - { - result = DbConnectionStringDefaults.AttestationProtocol; - return false; - } - } - - internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) - { -#if ENCLAVE_SIMULATOR - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS - || value == SqlConnectionAttestationProtocol.SIM; -#else - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS; -#endif - } - - internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) - { - Debug.Assert(IsValidAttestationProtocol(value), "value is not a valid attestation protocol"); - - switch (value) - { - case SqlConnectionAttestationProtocol.HGS: - return AttestationProtocolHGS; - case SqlConnectionAttestationProtocol.AAS: - return AttestationProtocolAAS; -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: - return AttestationProtocolSIM; -#endif - default: - return null; - } - } - - internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) - { - if (null == value) - { - return DbConnectionStringDefaults.AttestationProtocol; - } - - string sValue = (value as string); - SqlConnectionAttestationProtocol result; - - if (null != sValue) - { - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToAttestationProtocol(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionAttestationProtocol eValue; - - if (value is SqlConnectionAttestationProtocol) - { - eValue = (SqlConnectionAttestationProtocol)value; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionAttestationProtocol"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionAttestationProtocol enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionAttestationProtocol)Enum.ToObject(typeof(SqlConnectionAttestationProtocol), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), e); - } - } - - if (IsValidAttestationProtocol(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)eValue); - } - } - } - - #endregion - - #region <> - /// - /// IP Address Preference. - /// - private readonly static Dictionary s_preferenceNames = new(StringComparer.InvariantCultureIgnoreCase); - - static DbConnectionStringBuilderUtil() - { - foreach (SqlConnectionIPAddressPreference item in Enum.GetValues(typeof(SqlConnectionIPAddressPreference))) - { - s_preferenceNames.Add(item.ToString(), item); - } - } - - /// - /// Convert a string value to the corresponding IPAddressPreference. - /// - /// The string representation of the enumeration name to convert. - /// When this method returns, `result` contains an object of type `SqlConnectionIPAddressPreference` whose value is represented by `value` if the operation succeeds. - /// If the parse operation fails, `result` contains the default value of the `SqlConnectionIPAddressPreference` type. - /// `true` if the value parameter was converted successfully; otherwise, `false`. - internal static bool TryConvertToIPAddressPreference(string value, out SqlConnectionIPAddressPreference result) - { - if (!s_preferenceNames.TryGetValue(value, out result)) - { - result = DbConnectionStringDefaults.IPAddressPreference; - return false; - } - return true; - } - - /// - /// Verifies if the `value` is defined in the expected Enum. - /// - internal static bool IsValidIPAddressPreference(SqlConnectionIPAddressPreference value) - => value == SqlConnectionIPAddressPreference.IPv4First - || value == SqlConnectionIPAddressPreference.IPv6First - || value == SqlConnectionIPAddressPreference.UsePlatformDefault; - - internal static string IPAddressPreferenceToString(SqlConnectionIPAddressPreference value) - => Enum.GetName(typeof(SqlConnectionIPAddressPreference), value); - - internal static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) - { - if (value is null) - { - return DbConnectionStringDefaults.IPAddressPreference; // IPv4First - } - - if (value is string sValue) - { - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToIPAddressPreference(sValue, out SqlConnectionIPAddressPreference result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionIPAddressPreference eValue; - - if (value is SqlConnectionIPAddressPreference preference) - { - eValue = preference; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionIPAddressPreference"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionIPAddressPreference enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionIPAddressPreference)Enum.ToObject(typeof(SqlConnectionIPAddressPreference), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), e); - } - } - - if (IsValidIPAddressPreference(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)eValue); - } - } - } - #endregion - - internal static bool IsValidCertificateValue(string value) - { - return string.IsNullOrEmpty(value) - || value.StartsWith("subject:", StringComparison.OrdinalIgnoreCase) - || value.StartsWith("sha1:", StringComparison.OrdinalIgnoreCase); - } - } - - internal static class DbConnectionStringDefaults - { - // all - // internal const string NamedConnection = ""; - private const string _emptyString = ""; - // Odbc - internal const string Driver = _emptyString; - internal const string Dsn = _emptyString; - - // OleDb - internal const bool AdoNetPooler = false; - internal const string FileName = _emptyString; - internal const int OleDbServices = ~(/*DBPROPVAL_OS_AGR_AFTERSESSION*/0x00000008 | /*DBPROPVAL_OS_CLIENTCURSOR*/0x00000004); // -13 - internal const string Provider = _emptyString; - - // OracleClient - internal const bool Unicode = false; - internal const bool OmitOracleConnectionName = false; - - // SqlClient - internal const ApplicationIntent ApplicationIntent = Microsoft.Data.SqlClient.ApplicationIntent.ReadWrite; - internal const string ApplicationName = "Framework Microsoft SqlClient Data Provider"; - internal const string AttachDBFilename = _emptyString; - internal const int CommandTimeout = 30; - internal const int ConnectTimeout = 15; - internal const bool ConnectionReset = true; - internal const bool ContextConnection = false; - internal const string CurrentLanguage = _emptyString; - internal const string DataSource = _emptyString; - internal const bool Encrypt = false; - internal const bool Enlist = true; - internal const string FailoverPartner = _emptyString; - internal const string InitialCatalog = _emptyString; - internal const bool IntegratedSecurity = false; - internal const int LoadBalanceTimeout = 0; // default of 0 means don't use - internal const bool MultipleActiveResultSets = false; - internal const bool MultiSubnetFailover = false; - internal static readonly bool TransparentNetworkIPResolution = LocalAppContextSwitches.DisableTNIRByDefault ? false : true; - internal const int MaxPoolSize = 100; - internal const int MinPoolSize = 0; - internal const string NetworkLibrary = _emptyString; - internal const int PacketSize = 8000; - internal const string Password = _emptyString; - internal const bool PersistSecurityInfo = false; - internal const bool Pooling = true; - internal const bool TrustServerCertificate = false; - internal const string TypeSystemVersion = "Latest"; - internal const string UserID = _emptyString; - internal const bool UserInstance = false; - internal const bool Replication = false; - internal const string WorkstationID = _emptyString; - internal const string TransactionBinding = "Implicit Unbind"; - internal const int ConnectRetryCount = 1; - internal const int ConnectRetryInterval = 10; - internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified; - internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; - internal const string EnclaveAttestationUrl = _emptyString; - internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; - internal const SqlConnectionIPAddressPreference IPAddressPreference = SqlConnectionIPAddressPreference.IPv4First; - internal const string Certificate = _emptyString; - internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; - } - - internal static class DbConnectionOptionKeywords - { - // Odbc - internal const string Driver = "driver"; - internal const string Pwd = "pwd"; - internal const string UID = "uid"; - - // OleDb - internal const string DataProvider = "data provider"; - internal const string ExtendedProperties = "extended properties"; - internal const string FileName = "file name"; - internal const string Provider = "provider"; - internal const string RemoteProvider = "remote provider"; - - // common keywords (OleDb, OracleClient, SqlClient) - internal const string Password = "password"; - internal const string UserID = "user id"; - } - - internal static class DbConnectionStringKeywords - { - // all - // internal const string NamedConnection = "Named Connection"; - - // Odbc - internal const string Driver = "Driver"; - internal const string Dsn = "Dsn"; - internal const string FileDsn = "FileDsn"; - internal const string SaveFile = "SaveFile"; - - // OleDb - internal const string FileName = "File Name"; - internal const string OleDbServices = "OLE DB Services"; - internal const string Provider = "Provider"; - - // OracleClient - internal const string Unicode = "Unicode"; - internal const string OmitOracleConnectionName = "Omit Oracle Connection Name"; - - // SqlClient - internal const string ApplicationIntent = "Application Intent"; - internal const string ApplicationName = "Application Name"; - internal const string AttachDBFilename = "AttachDbFilename"; - internal const string ConnectTimeout = "Connect Timeout"; - internal const string CommandTimeout = "Command Timeout"; - internal const string ConnectionReset = "Connection Reset"; - internal const string ContextConnection = "Context Connection"; - internal const string CurrentLanguage = "Current Language"; - internal const string Encrypt = "Encrypt"; - internal const string FailoverPartner = "Failover Partner"; - internal const string InitialCatalog = "Initial Catalog"; - internal const string MultipleActiveResultSets = "Multiple Active Result Sets"; - internal const string MultiSubnetFailover = "Multi Subnet Failover"; - internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; - internal const string NetworkLibrary = "Network Library"; - internal const string PacketSize = "Packet Size"; - internal const string Replication = "Replication"; - internal const string TransactionBinding = "Transaction Binding"; - internal const string TrustServerCertificate = "Trust Server Certificate"; - internal const string TypeSystemVersion = "Type System Version"; - internal const string UserInstance = "User Instance"; - internal const string WorkstationID = "Workstation ID"; - internal const string ConnectRetryCount = "Connect Retry Count"; - internal const string ConnectRetryInterval = "Connect Retry Interval"; - internal const string Authentication = "Authentication"; - internal const string Certificate = "Certificate"; - internal const string ColumnEncryptionSetting = "Column Encryption Setting"; - internal const string EnclaveAttestationUrl = "Enclave Attestation Url"; - internal const string AttestationProtocol = "Attestation Protocol"; - internal const string IPAddressPreference = "IP Address Preference"; - internal const string PoolBlockingPeriod = "Pool Blocking Period"; - - // common keywords (OleDb, OracleClient, SqlClient) - internal const string DataSource = "Data Source"; - internal const string IntegratedSecurity = "Integrated Security"; - internal const string Password = "Password"; - internal const string PersistSecurityInfo = "Persist Security Info"; - internal const string UserID = "User ID"; - - // managed pooling (OracleClient, SqlClient) - internal const string Enlist = "Enlist"; - internal const string LoadBalanceTimeout = "Load Balance Timeout"; - internal const string MaxPoolSize = "Max Pool Size"; - internal const string Pooling = "Pooling"; - internal const string MinPoolSize = "Min Pool Size"; - } - - internal static class DbConnectionStringSynonyms - { - //internal const string ApplicationName = APP; - internal const string APP = "app"; - - // internal const string IPAddressPreference = IPADDRESSPREFERENCE; - internal const string IPADDRESSPREFERENCE = "ipaddresspreference"; - - //internal const string ApplicationIntent = APPLICATIONINTENT; - internal const string APPLICATIONINTENT = "applicationintent"; - - //internal const string AttachDBFilename = EXTENDEDPROPERTIES+","+INITIALFILENAME; - internal const string EXTENDEDPROPERTIES = "extended properties"; - internal const string INITIALFILENAME = "initial file name"; - - //internal const string ConnectTimeout = CONNECTIONTIMEOUT+","+TIMEOUT; - internal const string CONNECTIONTIMEOUT = "connection timeout"; - internal const string TIMEOUT = "timeout"; - - //internal const string ConnectRetryCount = CONNECTRETRYCOUNT; - internal const string CONNECTRETRYCOUNT = "connectretrycount"; - - //internal const string ConnectRetryInterval = CONNECTRETRYINTERVAL; - internal const string CONNECTRETRYINTERVAL = "connectretryinterval"; - - //internal const string CurrentLanguage = LANGUAGE; - internal const string LANGUAGE = "language"; - - //internal const string OraDataSource = SERVER; - //internal const string SqlDataSource = ADDR+","+ADDRESS+","+SERVER+","+NETWORKADDRESS; - internal const string ADDR = "addr"; - internal const string ADDRESS = "address"; - internal const string SERVER = "server"; - internal const string NETWORKADDRESS = "network address"; - - //internal const string InitialCatalog = DATABASE; - internal const string DATABASE = "database"; - - //internal const string IntegratedSecurity = TRUSTEDCONNECTION; - internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in everett - - //internal const string LoadBalanceTimeout = ConnectionLifetime; - internal const string ConnectionLifetime = "connection lifetime"; - - //internal const string MultipleActiveResultSets = MULTIPLEACTIVERESULTSETS; - internal const string MULTIPLEACTIVERESULTSETS = "multipleactiveresultsets"; - - //internal const string MultiSubnetFailover = MULTISUBNETFAILOVER; - internal const string MULTISUBNETFAILOVER = "multisubnetfailover"; - - //internal const string NetworkLibrary = NET+","+NETWORK; - internal const string NET = "net"; - internal const string NETWORK = "network"; - - //internal const string PoolBlockingPeriod = POOLBLOCKINGPERIOD; - internal const string POOLBLOCKINGPERIOD = "poolblockingperiod"; - - internal const string WorkaroundOracleBug914652 = "Workaround Oracle Bug 914652"; - - //internal const string Password = Pwd; - internal const string Pwd = "pwd"; - - //internal const string PersistSecurityInfo = PERSISTSECURITYINFO; - internal const string PERSISTSECURITYINFO = "persistsecurityinfo"; - - //internal const string TrustServerCertificate = TRUSTSERVERCERTIFICATE; - internal const string TRUSTSERVERCERTIFICATE = "trustservercertificate"; - - //internal const string TransparentNetworkIPResolution = TRANSPARENTNETWORKIPRESOLUTION; - internal const string TRANSPARENTNETWORKIPRESOLUTION = "transparentnetworkipresolution"; - - //internal const string UserID = UID+","+User; - internal const string UID = "uid"; - internal const string User = "user"; - - //internal const string WorkstationID = WSID; - internal const string WSID = "wsid"; - } -} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index 52131cb1c0..84d032c389 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -594,15 +594,15 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G if (!string.IsNullOrEmpty(_certificate)) { - if (Authentication == SqlClient.SqlAuthenticationMethod.NotSpecified && !_integratedSecurity) { - _authType = SqlClient.SqlAuthenticationMethod.SqlCertificate; + if (Authentication == SqlAuthenticationMethod.NotSpecified && !_integratedSecurity) { + _authType = SqlAuthenticationMethod.SqlCertificate; } - if (Authentication == SqlClient.SqlAuthenticationMethod.SqlCertificate && (HasUserIdKeyword || HasPasswordKeyword || _integratedSecurity)) { + if (Authentication == SqlAuthenticationMethod.SqlCertificate && (_hasUserIdKeyword || _hasPasswordKeyword || _integratedSecurity)) { throw SQL.InvalidCertAuth(); } } - else if (Authentication == SqlClient.SqlAuthenticationMethod.SqlCertificate) { + else if (Authentication == SqlAuthenticationMethod.SqlCertificate) { throw ADP.InvalidConnectionOptionValue(KEY.Authentication); } #endif diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs index 19bec77b80..ddf8feae2e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Data; using System.Data.Common; @@ -1178,13 +1179,7 @@ public override bool IsFixedSize } /// - public override ICollection Keys - { - get - { - return new Microsoft.Data.Common.ReadOnlyCollection(_validKeywords); - } - } + public override ICollection Keys => new ReadOnlyCollection(_validKeywords); /// public override ICollection Values @@ -1198,7 +1193,7 @@ public override ICollection Values { values[i] = GetAt((Keywords)i); } - return new Microsoft.Data.Common.ReadOnlyCollection(values); + return new ReadOnlyCollection(values); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs similarity index 84% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 0530df9cac..3cb7e0ef1c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -6,18 +6,16 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using System.Reflection; using Microsoft.Data.SqlClient; namespace Microsoft.Data.Common { - internal static partial class DbConnectionStringBuilderUtil + internal static class DbConnectionStringBuilderUtil { internal static bool ConvertToBoolean(object value) { Debug.Assert(null != value, "ConvertToBoolean(null)"); - string svalue = (value as string); - if (null != svalue) + if (value is string svalue) { if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) return true; @@ -25,7 +23,7 @@ internal static bool ConvertToBoolean(object value) return false; else { - string tmp = svalue.Trim(); // Remove leading & trailing whitespace. + string tmp = svalue.Trim(); // Remove leading & trailing white space. if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) return true; else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) @@ -35,7 +33,7 @@ internal static bool ConvertToBoolean(object value) } try { - return Convert.ToBoolean(value); + return Convert.ToBoolean(value, CultureInfo.InvariantCulture); } catch (InvalidCastException e) { @@ -46,8 +44,7 @@ internal static bool ConvertToBoolean(object value) internal static bool ConvertToIntegratedSecurity(object value) { Debug.Assert(null != value, "ConvertToIntegratedSecurity(null)"); - string svalue = (value as string); - if (null != svalue) + if (value is string svalue) { if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) return true; @@ -55,7 +52,7 @@ internal static bool ConvertToIntegratedSecurity(object value) return false; else { - string tmp = svalue.Trim(); // Remove leading & trailing whitespace. + string tmp = svalue.Trim(); // Remove leading & trailing white space. if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) return true; else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) @@ -65,7 +62,7 @@ internal static bool ConvertToIntegratedSecurity(object value) } try { - return Convert.ToBoolean(value); + return Convert.ToBoolean(value, CultureInfo.InvariantCulture); } catch (InvalidCastException e) { @@ -77,7 +74,7 @@ internal static int ConvertToInt32(object value) { try { - return Convert.ToInt32(value); + return Convert.ToInt32(value, CultureInfo.InvariantCulture); } catch (InvalidCastException e) { @@ -89,7 +86,7 @@ internal static string ConvertToString(object value) { try { - return Convert.ToString(value); + return Convert.ToString(value, CultureInfo.InvariantCulture); } catch (InvalidCastException e) { @@ -97,301 +94,79 @@ internal static string ConvertToString(object value) } } - private const string ApplicationIntentReadWriteString = "ReadWrite"; - private const string ApplicationIntentReadOnlyString = "ReadOnly"; - - const string SqlPasswordString = "Sql Password"; - const string ActiveDirectoryPasswordString = "Active Directory Password"; - const string ActiveDirectoryIntegratedString = "Active Directory Integrated"; - const string ActiveDirectoryInteractiveString = "Active Directory Interactive"; - const string ActiveDirectoryServicePrincipalString = "Active Directory Service Principal"; - const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow"; - internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity"; - internal const string ActiveDirectoryMSIString = "Active Directory MSI"; - internal const string ActiveDirectoryDefaultString = "Active Directory Default"; - -#if DEBUG - private static string[] s_supportedAuthenticationModes = - { - "NotSpecified", - "SqlPassword", - "ActiveDirectoryPassword", - "ActiveDirectoryIntegrated", - "ActiveDirectoryInteractive", - "ActiveDirectoryServicePrincipal", - "ActiveDirectoryDeviceCodeFlow", - "ActiveDirectoryManagedIdentity", - "ActiveDirectoryMSI", - "ActiveDirectoryDefault" - }; - - private static bool IsValidAuthenticationMethodEnum() + #region <> + internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) { - string[] names = Enum.GetNames(typeof(SqlAuthenticationMethod)); - int l = s_supportedAuthenticationModes.Length; - bool listValid; - if (listValid = names.Length == l) - { - for (int i = 0; i < l; i++) - { - if (s_supportedAuthenticationModes[i].CompareTo(names[i]) != 0) - { - listValid = false; - } - } - } - return listValid; - } -#endif + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)"); - internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result) - { -#if DEBUG - Debug.Assert(IsValidAuthenticationMethodEnum(), "SqlAuthenticationMethod enum has changed, update needed"); -#endif - bool isSuccess = false; - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.SqlPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryIntegrated, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryIntegrated; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryInteractiveString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryInteractive, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryInteractive; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryServicePrincipalString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryServicePrincipal; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDeviceCodeFlowString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryManagedIdentityString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryManagedIdentity; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryMSIString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryMSI, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryMSI; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDefault; - isSuccess = true; - } - else + if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.Auto))) { - result = DbConnectionStringDefaults.Authentication; + result = PoolBlockingPeriod.Auto; + return true; } - return isSuccess; - } - - internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result) - { - Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); - Debug.Assert(null != value, "TryConvertToApplicationIntent(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadOnlyString)) + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.AlwaysBlock))) { - result = ApplicationIntent.ReadOnly; + result = PoolBlockingPeriod.AlwaysBlock; return true; } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadWriteString)) + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.NeverBlock))) { - result = ApplicationIntent.ReadWrite; + result = PoolBlockingPeriod.NeverBlock; return true; } else { - result = DbConnectionStringDefaults.ApplicationIntent; + result = DbConnectionStringDefaults.PoolBlockingPeriod; return false; } } - /// - /// Column Encryption Setting. - /// - const string ColumnEncryptionSettingEnabledString = "Enabled"; - const string ColumnEncryptionSettingDisabledString = "Disabled"; - - /// - /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting. - /// - /// - /// - /// - internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) - { - bool isSuccess = false; - - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingEnabledString)) - { - result = SqlConnectionColumnEncryptionSetting.Enabled; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingDisabledString)) - { - result = SqlConnectionColumnEncryptionSetting.Disabled; - isSuccess = true; - } - else - { - result = DbConnectionStringDefaults.ColumnEncryptionSetting; - } - - return isSuccess; - } - - /// - /// Is it a valid connection level column encryption setting ? - /// - /// - /// - internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) + internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) { - Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed"); - return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled; + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock; } - /// - /// Convert connection level column encryption setting value to string. - /// - /// - /// - internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) + internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) { - Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting."); + Debug.Assert(IsValidPoolBlockingPeriodValue(value)); - switch (value) + return value switch { - case SqlConnectionColumnEncryptionSetting.Enabled: - return ColumnEncryptionSettingEnabledString; - case SqlConnectionColumnEncryptionSetting.Disabled: - return ColumnEncryptionSettingDisabledString; - - default: - return null; - } + PoolBlockingPeriod.AlwaysBlock => nameof(PoolBlockingPeriod.AlwaysBlock), + PoolBlockingPeriod.NeverBlock => nameof(PoolBlockingPeriod.NeverBlock), + _ => nameof(PoolBlockingPeriod.Auto), + }; } - #region <> - - /// - /// Attestation Protocol. - /// - const string AttestationProtocolHGS = "HGS"; - const string AttestationProtocolAAS = "AAS"; -#if ENCLAVE_SIMULATOR - const string AttestationProtocolSIM = "SIM"; -#endif - /// - /// Convert a string value to the corresponding SqlConnectionAttestationProtocol + /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: + /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer + /// * if the value is from type PoolBlockingPeriod, it will be used as is + /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum + /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException + /// + /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. /// - /// - /// - /// - internal static bool TryConvertToAttestationProtocol(string value, out SqlConnectionAttestationProtocol result) - { - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolHGS)) - { - result = SqlConnectionAttestationProtocol.HGS; - return true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolAAS)) - { - result = SqlConnectionAttestationProtocol.AAS; - return true; - } -#if ENCLAVE_SIMULATOR - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, AttestationProtocolSIM)) - { - result = SqlConnectionAttestationProtocol.SIM; - return true; - } -#endif - else - { - result = DbConnectionStringDefaults.AttestationProtocol; - return false; - } - } - - internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) - { -#if ENCLAVE_SIMULATOR - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS - || value == SqlConnectionAttestationProtocol.SIM; -#else - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS; -#endif - } - - internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) - { - Debug.Assert(IsValidAttestationProtocol(value), "value is not a valid attestation protocol"); - - switch (value) - { - case SqlConnectionAttestationProtocol.HGS: - return AttestationProtocolHGS; - case SqlConnectionAttestationProtocol.AAS: - return AttestationProtocolAAS; -#if ENCLAVE_SIMULATOR - case SqlConnectionAttestationProtocol.SIM: - return AttestationProtocolSIM; -#endif - default: - return null; - } - } - - internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) + /// PoolBlockingPeriod value in the valid range + internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) { - if (null == value) + Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)"); + if (value is string sValue) { - return DbConnectionStringDefaults.AttestationProtocol; - } + // We could use Enum.TryParse here, but it accepts value combinations like + // "ReadOnly, ReadWrite" which are unwelcome here + // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - string sValue = (value as string); - SqlConnectionAttestationProtocol result; + if (TryConvertToPoolBlockingPeriod(sValue, out PoolBlockingPeriod result)) + { + return result; + } - if (null != sValue) - { // try again after remove leading & trailing whitespaces. sValue = sValue.Trim(); - if (TryConvertToAttestationProtocol(sValue, out result)) + if (TryConvertToPoolBlockingPeriod(sValue, out result)) { return result; } @@ -402,150 +177,69 @@ internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(st else { // the value is not string, try other options - SqlConnectionAttestationProtocol eValue; + PoolBlockingPeriod eValue; - if (value is SqlConnectionAttestationProtocol) + if (value is PoolBlockingPeriod period) { - eValue = (SqlConnectionAttestationProtocol)value; + // quick path for the most common case + eValue = period; } else if (value.GetType().IsEnum) { // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionAttestationProtocol"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionAttestationProtocol enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), null); + // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-PoolBlockingPeriod enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); } else { try { // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionAttestationProtocol)Enum.ToObject(typeof(SqlConnectionAttestationProtocol), value); + eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); } catch (ArgumentException e) { // to be consistent with the messages we send in case of wrong type usage, replace // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), e); + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); } } - if (IsValidAttestationProtocol(eValue)) + // ensure value is in valid range + if (IsValidPoolBlockingPeriodValue(eValue)) { return eValue; } else { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)eValue); + throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); } } } - #endregion - #region <> - /// - /// IP Address Preference. - /// - private readonly static Dictionary s_preferenceNames = new(StringComparer.InvariantCultureIgnoreCase); - - static DbConnectionStringBuilderUtil() - { - foreach (SqlConnectionIPAddressPreference item in Enum.GetValues(typeof(SqlConnectionIPAddressPreference))) - { - s_preferenceNames.Add(item.ToString(), item); - } - } - - /// - /// Convert a string value to the corresponding IPAddressPreference. - /// - /// The string representation of the enumeration name to convert. - /// When this method returns, `result` contains an object of type `SqlConnectionIPAddressPreference` whose value is represented by `value` if the operation succeeds. - /// If the parse operation fails, `result` contains the default value of the `SqlConnectionIPAddressPreference` type. - /// `true` if the value parameter was converted successfully; otherwise, `false`. - internal static bool TryConvertToIPAddressPreference(string value, out SqlConnectionIPAddressPreference result) + internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result) { - if (!s_preferenceNames.TryGetValue(value, out result)) - { - result = DbConnectionStringDefaults.IPAddressPreference; - return false; - } - return true; - } - - /// - /// Verifies if the `value` is defined in the expected Enum. - /// - internal static bool IsValidIPAddressPreference(SqlConnectionIPAddressPreference value) - => value == SqlConnectionIPAddressPreference.IPv4First - || value == SqlConnectionIPAddressPreference.IPv6First - || value == SqlConnectionIPAddressPreference.UsePlatformDefault; - - internal static string IPAddressPreferenceToString(SqlConnectionIPAddressPreference value) - => Enum.GetName(typeof(SqlConnectionIPAddressPreference), value); + Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); + Debug.Assert(null != value, "TryConvertToApplicationIntent(null,...)"); - internal static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) - { - if (value is null) + if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadOnly))) { - return DbConnectionStringDefaults.IPAddressPreference; // IPv4First + result = ApplicationIntent.ReadOnly; + return true; } - - if (value is string sValue) + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadWrite))) { - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToIPAddressPreference(sValue, out SqlConnectionIPAddressPreference result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); + result = ApplicationIntent.ReadWrite; + return true; } else { - // the value is not string, try other options - SqlConnectionIPAddressPreference eValue; - - if (value is SqlConnectionIPAddressPreference preference) - { - eValue = preference; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionIPAddressPreference"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionIPAddressPreference enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionIPAddressPreference)Enum.ToObject(typeof(SqlConnectionIPAddressPreference), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), e); - } - } - - if (IsValidIPAddressPreference(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)eValue); - } + result = DbConnectionStringDefaults.ApplicationIntent; + return false; } } - #endregion internal static bool IsValidApplicationIntentValue(ApplicationIntent value) { @@ -558,11 +252,11 @@ internal static string ApplicationIntentToString(ApplicationIntent value) Debug.Assert(IsValidApplicationIntentValue(value)); if (value == ApplicationIntent.ReadOnly) { - return ApplicationIntentReadOnlyString; + return nameof(ApplicationIntent.ReadOnly); } else { - return ApplicationIntentReadWriteString; + return nameof(ApplicationIntent.ReadWrite); } } @@ -579,20 +273,18 @@ internal static string ApplicationIntentToString(ApplicationIntent value) internal static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) { Debug.Assert(null != value, "ConvertToApplicationIntent(null)"); - string sValue = (value as string); - ApplicationIntent result; - if (null != sValue) + if (value is string sValue) { // We could use Enum.TryParse here, but it accepts value combinations like // "ReadOnly, ReadWrite" which are unwelcome here // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - if (TryConvertToApplicationIntent(sValue, out result)) + if (TryConvertToApplicationIntent(sValue, out ApplicationIntent result)) { return result; } - // try again after remove leading & trailing whitespace. + // try again after remove leading & trailing whitespaces. sValue = sValue.Trim(); if (TryConvertToApplicationIntent(sValue, out result)) { @@ -607,12 +299,12 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj // the value is not string, try other options ApplicationIntent eValue; - if (value is ApplicationIntent) + if (value is ApplicationIntent intent) { // quick path for the most common case - eValue = (ApplicationIntent)value; + eValue = intent; } - else if (value.GetType().GetTypeInfo().IsEnum) + else if (value.GetType().IsEnum) { // explicitly block scenarios in which user tries to use wrong enum types, like: // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; @@ -646,6 +338,182 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj } } + const string SqlPasswordString = "Sql Password"; + const string ActiveDirectoryPasswordString = "Active Directory Password"; + const string ActiveDirectoryIntegratedString = "Active Directory Integrated"; + const string ActiveDirectoryInteractiveString = "Active Directory Interactive"; + const string ActiveDirectoryServicePrincipalString = "Active Directory Service Principal"; + const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow"; + internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity"; + internal const string ActiveDirectoryMSIString = "Active Directory MSI"; + internal const string ActiveDirectoryDefaultString = "Active Directory Default"; + const string SqlCertificateString = "Sql Certificate"; + +#if DEBUG + private static readonly string[] s_supportedAuthenticationModes = + { + "NotSpecified", + "SqlPassword", + "ActiveDirectoryPassword", + "ActiveDirectoryIntegrated", + "ActiveDirectoryInteractive", + "ActiveDirectoryServicePrincipal", + "ActiveDirectoryDeviceCodeFlow", + "ActiveDirectoryManagedIdentity", + "ActiveDirectoryMSI", + "ActiveDirectoryDefault" + }; + + private static bool IsValidAuthenticationMethodEnum() + { + string[] names = Enum.GetNames(typeof(SqlAuthenticationMethod)); + int l = s_supportedAuthenticationModes.Length; + bool listValid; + if (listValid = names.Length == l) + { + for (int i = 0; i < l; i++) + { + if (s_supportedAuthenticationModes[i].CompareTo(names[i]) != 0) + { + listValid = false; + } + } + } + return listValid; + } +#endif + + internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result) + { +#if DEBUG + Debug.Assert(IsValidAuthenticationMethodEnum(), "SqlAuthenticationMethod enum has changed, update needed"); +#endif + bool isSuccess = false; + + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlPassword, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.SqlPassword; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryPassword, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryPassword; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryIntegrated, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryIntegrated; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryInteractiveString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryInteractive, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryInteractive; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryServicePrincipalString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryServicePrincipal; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDeviceCodeFlowString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryManagedIdentityString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryManagedIdentity; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryMSIString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryMSI, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryMSI; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryDefault; + isSuccess = true; + } +#if ADONET_CERT_AUTH && NETFRAMEWORK + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlCertificateString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlCertificate, CultureInfo.InvariantCulture))) { + result = SqlAuthenticationMethod.SqlCertificate; + isSuccess = true; + } +#endif + else + { + result = DbConnectionStringDefaults.Authentication; + } + return isSuccess; + } + + /// + /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting. + /// + /// + /// + /// + internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) + { + bool isSuccess = false; + + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Enabled))) + { + result = SqlConnectionColumnEncryptionSetting.Enabled; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Disabled))) + { + result = SqlConnectionColumnEncryptionSetting.Disabled; + isSuccess = true; + } + else + { + result = DbConnectionStringDefaults.ColumnEncryptionSetting; + } + + return isSuccess; + } + + /// + /// Is it a valid connection level column encryption setting ? + /// + /// + /// + internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) + { + Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed"); + return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled; + } + + /// + /// Convert connection level column encryption setting value to string. + /// + /// + /// + internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) + { + Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting."); + + return value switch + { + SqlConnectionColumnEncryptionSetting.Enabled => nameof(SqlConnectionColumnEncryptionSetting.Enabled), + SqlConnectionColumnEncryptionSetting.Disabled => nameof(SqlConnectionColumnEncryptionSetting.Disabled), + _ => null, + }; + } + internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) { Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 10, "SqlAuthenticationMethod enum has changed, update needed"); @@ -658,6 +526,9 @@ internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod valu || value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity || value == SqlAuthenticationMethod.ActiveDirectoryMSI || value == SqlAuthenticationMethod.ActiveDirectoryDefault +#if ADONET_CERT_AUTH && NETFRAMEWORK + || value == SqlAuthenticationMethod.SqlCertificate +#endif || value == SqlAuthenticationMethod.NotSpecified; } @@ -665,29 +536,22 @@ internal static string AuthenticationTypeToString(SqlAuthenticationMethod value) { Debug.Assert(IsValidAuthenticationTypeValue(value)); - switch (value) + return value switch { - case SqlAuthenticationMethod.SqlPassword: - return SqlPasswordString; - case SqlAuthenticationMethod.ActiveDirectoryPassword: - return ActiveDirectoryPasswordString; - case SqlAuthenticationMethod.ActiveDirectoryIntegrated: - return ActiveDirectoryIntegratedString; - case SqlAuthenticationMethod.ActiveDirectoryInteractive: - return ActiveDirectoryInteractiveString; - case SqlAuthenticationMethod.ActiveDirectoryServicePrincipal: - return ActiveDirectoryServicePrincipalString; - case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow: - return ActiveDirectoryDeviceCodeFlowString; - case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity: - return ActiveDirectoryManagedIdentityString; - case SqlAuthenticationMethod.ActiveDirectoryMSI: - return ActiveDirectoryMSIString; - case SqlAuthenticationMethod.ActiveDirectoryDefault: - return ActiveDirectoryDefaultString; - default: - return null; - } + SqlAuthenticationMethod.SqlPassword => SqlPasswordString, + SqlAuthenticationMethod.ActiveDirectoryPassword => ActiveDirectoryPasswordString, + SqlAuthenticationMethod.ActiveDirectoryIntegrated => ActiveDirectoryIntegratedString, + SqlAuthenticationMethod.ActiveDirectoryInteractive => ActiveDirectoryInteractiveString, + SqlAuthenticationMethod.ActiveDirectoryServicePrincipal => ActiveDirectoryServicePrincipalString, + SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow => ActiveDirectoryDeviceCodeFlowString, + SqlAuthenticationMethod.ActiveDirectoryManagedIdentity => ActiveDirectoryManagedIdentityString, + SqlAuthenticationMethod.ActiveDirectoryMSI => ActiveDirectoryMSIString, + SqlAuthenticationMethod.ActiveDirectoryDefault => ActiveDirectoryDefaultString, +#if ADONET_CERT_AUTH && NETFRAMEWORK + SqlAuthenticationMethod.SqlCertificate => SqlCertificateString, +#endif + _ => null + }; } internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) @@ -697,11 +561,9 @@ internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keywo return DbConnectionStringDefaults.Authentication; } - string sValue = (value as string); - SqlAuthenticationMethod result; - if (null != sValue) + if (value is string sValue) { - if (TryConvertToAuthenticationType(sValue, out result)) + if (TryConvertToAuthenticationType(sValue, out SqlAuthenticationMethod result)) { return result; } @@ -721,10 +583,10 @@ internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keywo // the value is not string, try other options SqlAuthenticationMethod eValue; - if (value is SqlAuthenticationMethod) + if (value is SqlAuthenticationMethod method) { // quick path for the most common case - eValue = (SqlAuthenticationMethod)value; + eValue = method; } else if (value.GetType().IsEnum) { @@ -773,11 +635,9 @@ internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSe return DbConnectionStringDefaults.ColumnEncryptionSetting; } - string sValue = (value as string); - SqlConnectionColumnEncryptionSetting result; - if (null != sValue) + if (value is string sValue) { - if (TryConvertToColumnEncryptionSetting(sValue, out result)) + if (TryConvertToColumnEncryptionSetting(sValue, out SqlConnectionColumnEncryptionSetting result)) { return result; } @@ -797,10 +657,10 @@ internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSe // the value is not string, try other options SqlConnectionColumnEncryptionSetting eValue; - if (value is SqlConnectionColumnEncryptionSetting) + if (value is SqlConnectionColumnEncryptionSetting setting) { // quick path for the most common case - eValue = (SqlConnectionColumnEncryptionSetting)value; + eValue = setting; } else if (value.GetType().IsEnum) { @@ -836,83 +696,187 @@ internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSe } } - #region <> - internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) + #region <> + /// + /// Convert a string value to the corresponding SqlConnectionAttestationProtocol + /// + /// + /// + /// + internal static bool TryConvertToAttestationProtocol(string value, out SqlConnectionAttestationProtocol result) { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.Auto))) + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.HGS))) { - result = PoolBlockingPeriod.Auto; + result = SqlConnectionAttestationProtocol.HGS; return true; } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.AlwaysBlock))) + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.AAS))) { - result = PoolBlockingPeriod.AlwaysBlock; + result = SqlConnectionAttestationProtocol.AAS; return true; } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.NeverBlock))) +#if ENCLAVE_SIMULATOR + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.SIM))) { - result = PoolBlockingPeriod.NeverBlock; + result = SqlConnectionAttestationProtocol.SIM; return true; } +#endif else { - result = DbConnectionStringDefaults.PoolBlockingPeriod; + result = DbConnectionStringDefaults.AttestationProtocol; return false; } } - internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) + internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - return (uint)value <= (uint)PoolBlockingPeriod.NeverBlock; +#if ENCLAVE_SIMULATOR + Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); + return value == SqlConnectionAttestationProtocol.NotSpecified + || value == SqlConnectionAttestationProtocol.HGS + || value == SqlConnectionAttestationProtocol.AAS + || value == SqlConnectionAttestationProtocol.SIM; +#else + Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 3, "SqlConnectionAttestationProtocol enum has changed, update needed"); + return value == SqlConnectionAttestationProtocol.NotSpecified + || value == SqlConnectionAttestationProtocol.HGS + || value == SqlConnectionAttestationProtocol.AAS; +#endif } - internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) + internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) { - Debug.Assert(IsValidPoolBlockingPeriodValue(value)); + Debug.Assert(IsValidAttestationProtocol(value), "value is not a valid attestation protocol"); - switch (value) + return value switch { - case PoolBlockingPeriod.AlwaysBlock: - return nameof(PoolBlockingPeriod.AlwaysBlock); - case PoolBlockingPeriod.NeverBlock: - return nameof(PoolBlockingPeriod.NeverBlock); - default: - return nameof(PoolBlockingPeriod.Auto); - } + SqlConnectionAttestationProtocol.AAS => nameof(SqlConnectionAttestationProtocol.AAS), + SqlConnectionAttestationProtocol.HGS => nameof(SqlConnectionAttestationProtocol.HGS), +#if ENCLAVE_SIMULATOR + SqlConnectionAttestationProtocol.SIM => nameof(SqlConnectionAttestationProtocol.SIM), +#endif + _ => null + }; } - /// - /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: - /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer - /// * if the value is from type PoolBlockingPeriod, it will be used as is - /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum - /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException - /// - /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. - /// - /// PoolBlockingPeriod value in the valid range - internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) + internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) { - Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)"); - string sValue = (value as string); - PoolBlockingPeriod result; - if (null != sValue) + if (null == value) { - // We could use Enum.TryParse here, but it accepts value combinations like - // "ReadOnly, ReadWrite" which are unwelcome here - // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - if (TryConvertToPoolBlockingPeriod(sValue, out result)) + return DbConnectionStringDefaults.AttestationProtocol; + } + + if (value is string sValue) + { + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToAttestationProtocol(sValue, out SqlConnectionAttestationProtocol result)) { return result; } + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + SqlConnectionAttestationProtocol eValue; + + if (value is SqlConnectionAttestationProtocol protocol) + { + eValue = protocol; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["SqlConnectionAttestationProtocol"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-SqlConnectionAttestationProtocol enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (SqlConnectionAttestationProtocol)Enum.ToObject(typeof(SqlConnectionAttestationProtocol), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), e); + } + } + + if (IsValidAttestationProtocol(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)eValue); + } + } + } + + #endregion + + #region <> + /// + /// IP Address Preference. + /// + private readonly static Dictionary s_preferenceNames = new(StringComparer.InvariantCultureIgnoreCase); + + static DbConnectionStringBuilderUtil() + { + foreach (SqlConnectionIPAddressPreference item in Enum.GetValues(typeof(SqlConnectionIPAddressPreference))) + { + s_preferenceNames.Add(item.ToString(), item); + } + } + + /// + /// Convert a string value to the corresponding IPAddressPreference. + /// + /// The string representation of the enumeration name to convert. + /// When this method returns, `result` contains an object of type `SqlConnectionIPAddressPreference` whose value is represented by `value` if the operation succeeds. + /// If the parse operation fails, `result` contains the default value of the `SqlConnectionIPAddressPreference` type. + /// `true` if the value parameter was converted successfully; otherwise, `false`. + internal static bool TryConvertToIPAddressPreference(string value, out SqlConnectionIPAddressPreference result) + { + if (!s_preferenceNames.TryGetValue(value, out result)) + { + result = DbConnectionStringDefaults.IPAddressPreference; + return false; + } + return true; + } + + /// + /// Verifies if the `value` is defined in the expected Enum. + /// + internal static bool IsValidIPAddressPreference(SqlConnectionIPAddressPreference value) + => value == SqlConnectionIPAddressPreference.IPv4First + || value == SqlConnectionIPAddressPreference.IPv6First + || value == SqlConnectionIPAddressPreference.UsePlatformDefault; + + internal static string IPAddressPreferenceToString(SqlConnectionIPAddressPreference value) + => Enum.GetName(typeof(SqlConnectionIPAddressPreference), value); + + internal static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) + { + if (value is null) + { + return DbConnectionStringDefaults.IPAddressPreference; // IPv4First + } + + if (value is string sValue) + { // try again after remove leading & trailing whitespaces. sValue = sValue.Trim(); - if (TryConvertToPoolBlockingPeriod(sValue, out result)) + if (TryConvertToIPAddressPreference(sValue, out SqlConnectionIPAddressPreference result)) { return result; } @@ -923,67 +887,81 @@ internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, o else { // the value is not string, try other options - PoolBlockingPeriod eValue; + SqlConnectionIPAddressPreference eValue; - if (value is PoolBlockingPeriod) + if (value is SqlConnectionIPAddressPreference preference) { - // quick path for the most common case - eValue = (PoolBlockingPeriod)value; + eValue = preference; } else if (value.GetType().IsEnum) { // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-PoolBlockingPeriod enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); + // builder["SqlConnectionIPAddressPreference"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-SqlConnectionIPAddressPreference enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), null); } else { try { // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); + eValue = (SqlConnectionIPAddressPreference)Enum.ToObject(typeof(SqlConnectionIPAddressPreference), value); } catch (ArgumentException e) { - // to be consistent with the messages we send in case of wrong type usage, replace + // to be consistent with the messages we send in case of wrong type usage, replace // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), e); } } - // ensure value is in valid range - if (IsValidPoolBlockingPeriodValue(eValue)) + if (IsValidIPAddressPreference(eValue)) { return eValue; } else { - throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); + throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)eValue); } } } #endregion + +#if ADONET_CERT_AUTH && NETFRAMEWORK + internal static bool IsValidCertificateValue(string value) => string.IsNullOrEmpty(value) + || value.StartsWith("subject:", StringComparison.OrdinalIgnoreCase) + || value.StartsWith("sha1:", StringComparison.OrdinalIgnoreCase); +#endif } - internal static partial class DbConnectionStringDefaults + internal static class DbConnectionStringDefaults { - // all - // internal const string NamedConnection = ""; - - private const string _emptyString = ""; - // SqlClient internal const ApplicationIntent ApplicationIntent = Microsoft.Data.SqlClient.ApplicationIntent.ReadWrite; - internal const string ApplicationName = "Core Microsoft SqlClient Data Provider"; - internal const string AttachDBFilename = _emptyString; + internal const string ApplicationName = +#if NETFRAMEWORK + "Framework Microsoft SqlClient Data Provider"; +#else + "Core Microsoft SqlClient Data Provider"; +#endif + internal const string AttachDBFilename = ""; internal const int CommandTimeout = 30; internal const int ConnectTimeout = 15; - internal const string CurrentLanguage = _emptyString; - internal const string DataSource = _emptyString; - internal const bool Encrypt = false; + +#if NETFRAMEWORK + internal const bool ConnectionReset = true; + internal const bool ContextConnection = false; + internal static readonly bool TransparentNetworkIPResolution = !LocalAppContextSwitches.DisableTNIRByDefault; + internal const string NetworkLibrary = ""; +#if ADONET_CERT_AUTH + internal const string Certificate = ""; +#endif +#endif + internal const string CurrentLanguage = ""; + internal const string DataSource = ""; + internal const bool Encrypt = true; internal const bool Enlist = true; - internal const string FailoverPartner = _emptyString; - internal const string InitialCatalog = _emptyString; + internal const string FailoverPartner = ""; + internal const string InitialCatalog = ""; internal const bool IntegratedSecurity = false; internal const int LoadBalanceTimeout = 0; // default of 0 means don't use internal const bool MultipleActiveResultSets = false; @@ -991,37 +969,54 @@ internal static partial class DbConnectionStringDefaults internal const int MaxPoolSize = 100; internal const int MinPoolSize = 0; internal const int PacketSize = 8000; - internal const string Password = _emptyString; + internal const string Password = ""; internal const bool PersistSecurityInfo = false; internal const bool Pooling = true; internal const bool TrustServerCertificate = false; internal const string TypeSystemVersion = "Latest"; - internal const string UserID = _emptyString; + internal const string UserID = ""; internal const bool UserInstance = false; internal const bool Replication = false; - internal const string WorkstationID = _emptyString; + internal const string WorkstationID = ""; internal const string TransactionBinding = "Implicit Unbind"; internal const int ConnectRetryCount = 1; internal const int ConnectRetryInterval = 10; - internal const PoolBlockingPeriod PoolBlockingPeriod = Microsoft.Data.SqlClient.PoolBlockingPeriod.Auto; internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified; - internal const SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; - internal const string EnclaveAttestationUrl = _emptyString; + internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; + internal const string EnclaveAttestationUrl = ""; internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; internal const SqlConnectionIPAddressPreference IPAddressPreference = SqlConnectionIPAddressPreference.IPv4First; + internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; } - internal static partial class DbConnectionStringKeywords + internal static class DbConnectionStringKeywords { - // all - // internal const string NamedConnection = "Named Connection"; +#if NETFRAMEWORK + // Odbc + internal const string Driver = "Driver"; + internal const string Dsn = "Dsn"; + internal const string FileDsn = "FileDsn"; + internal const string SaveFile = "SaveFile"; + // OleDb + internal const string FileName = "File Name"; + internal const string OleDbServices = "OLE DB Services"; + internal const string Provider = "Provider"; + + // OracleClient + internal const string Unicode = "Unicode"; + internal const string OmitOracleConnectionName = "Omit Oracle Connection Name"; + + // SqlClient + internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; + internal const string Certificate = "Certificate"; +#endif // SqlClient internal const string ApplicationIntent = "Application Intent"; internal const string ApplicationName = "Application Name"; internal const string AttachDBFilename = "AttachDbFilename"; - internal const string CommandTimeout = "Command Timeout"; internal const string ConnectTimeout = "Connect Timeout"; + internal const string CommandTimeout = "Command Timeout"; internal const string ConnectionReset = "Connection Reset"; internal const string ContextConnection = "Context Connection"; internal const string CurrentLanguage = "Current Language"; @@ -1050,7 +1045,6 @@ internal static partial class DbConnectionStringKeywords internal const string DataSource = "Data Source"; internal const string IntegratedSecurity = "Integrated Security"; internal const string Password = "Password"; - internal const string Driver = "Driver"; internal const string PersistSecurityInfo = "Persist Security Info"; internal const string UserID = "User ID"; @@ -1065,14 +1059,18 @@ internal static partial class DbConnectionStringKeywords internal static class DbConnectionStringSynonyms { +#if NETFRAMEWORK + //internal const string TransparentNetworkIPResolution = TRANSPARENTNETWORKIPRESOLUTION; + internal const string TRANSPARENTNETWORKIPRESOLUTION = "transparentnetworkipresolution"; +#endif //internal const string ApplicationName = APP; internal const string APP = "app"; // internal const string IPAddressPreference = IPADDRESSPREFERENCE; - internal const string IPADDRESSPREFERENCE = "IPAddressPreference"; + internal const string IPADDRESSPREFERENCE = "ipaddresspreference"; //internal const string ApplicationIntent = APPLICATIONINTENT; - internal const string APPLICATIONINTENT = "ApplicationIntent"; + internal const string APPLICATIONINTENT = "applicationintent"; //internal const string AttachDBFilename = EXTENDEDPROPERTIES+","+INITIALFILENAME; internal const string EXTENDEDPROPERTIES = "extended properties"; @@ -1083,10 +1081,10 @@ internal static class DbConnectionStringSynonyms internal const string TIMEOUT = "timeout"; //internal const string ConnectRetryCount = CONNECTRETRYCOUNT; - internal const string CONNECTRETRYCOUNT = "ConnectRetryCount"; + internal const string CONNECTRETRYCOUNT = "connectretrycount"; //internal const string ConnectRetryInterval = CONNECTRETRYINTERVAL; - internal const string CONNECTRETRYINTERVAL = "ConnectRetryInterval"; + internal const string CONNECTRETRYINTERVAL = "connectretryinterval"; //internal const string CurrentLanguage = LANGUAGE; internal const string LANGUAGE = "language"; @@ -1102,23 +1100,23 @@ internal static class DbConnectionStringSynonyms internal const string DATABASE = "database"; //internal const string IntegratedSecurity = TRUSTEDCONNECTION; - internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in Everett + internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in everett //internal const string LoadBalanceTimeout = ConnectionLifetime; internal const string ConnectionLifetime = "connection lifetime"; //internal const string MultipleActiveResultSets = MULTIPLEACTIVERESULTSETS; - internal const string MULTIPLEACTIVERESULTSETS = "MultipleActiveResultSets"; + internal const string MULTIPLEACTIVERESULTSETS = "multipleactiveresultsets"; //internal const string MultiSubnetFailover = MULTISUBNETFAILOVER; - internal const string MULTISUBNETFAILOVER = "MultiSubnetFailover"; + internal const string MULTISUBNETFAILOVER = "multisubnetfailover"; //internal const string NetworkLibrary = NET+","+NETWORK; internal const string NET = "net"; internal const string NETWORK = "network"; //internal const string PoolBlockingPeriod = POOLBLOCKINGPERIOD; - internal const string POOLBLOCKINGPERIOD = "PoolBlockingPeriod"; + internal const string POOLBLOCKINGPERIOD = "poolblockingperiod"; //internal const string Password = Pwd; internal const string Pwd = "pwd"; @@ -1127,7 +1125,7 @@ internal static class DbConnectionStringSynonyms internal const string PERSISTSECURITYINFO = "persistsecurityinfo"; //internal const string TrustServerCertificate = TRUSTSERVERCERTIFICATE; - internal const string TRUSTSERVERCERTIFICATE = "TrustServerCertificate"; + internal const string TRUSTSERVERCERTIFICATE = "trustservercertificate"; //internal const string UserID = UID+","+User; internal const string UID = "uid"; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 5ad2d85615..bf08250e83 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -88,6 +88,7 @@ public void ConnectionStringTests(string connectionString) } [Theory] + [InlineData("Connection Reset = false")] [InlineData("Context Connection = false")] [InlineData("Network Library = dbmssocn")] [InlineData("Network = dbnmpntw")]