DbConnectionStringCommon.cs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DbConnectionStringBuilder.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.ComponentModel;
  12. using System.Data;
  13. using System.Data.Common;
  14. using System.Diagnostics;
  15. using System.Globalization;
  16. using System.Runtime.Serialization;
  17. using System.Security.Permissions;
  18. using System.Text;
  19. using System.Text.RegularExpressions;
  20. using System.Data.SqlClient;
  21. namespace System.Data.Common {
  22. /*
  23. internal sealed class NamedConnectionStringConverter : StringConverter {
  24. public NamedConnectionStringConverter() {
  25. }
  26. public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
  27. return true;
  28. }
  29. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
  30. // Although theoretically this could be true, some people may want to just type in a name
  31. return false;
  32. }
  33. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
  34. StandardValuesCollection standardValues = null;
  35. if (null != context) {
  36. DbConnectionStringBuilder instance = (context.Instance as DbConnectionStringBuilder);
  37. if (null != instance) {
  38. string myProviderName = instance.GetType().Namespace;
  39. List<string> myConnectionNames = new List<string>();
  40. foreach(System.Configuration.ConnectionStringSetting setting in System.Configuration.ConfigurationManager.ConnectionStrings) {
  41. if (myProviderName.EndsWith(setting.ProviderName)) {
  42. myConnectionNames.Add(setting.ConnectionName);
  43. }
  44. }
  45. standardValues = new StandardValuesCollection(myConnectionNames);
  46. }
  47. }
  48. return standardValues;
  49. }
  50. }
  51. */
  52. internal class DbConnectionStringBuilderDescriptor : PropertyDescriptor {
  53. private Type _componentType;
  54. private Type _propertyType;
  55. private bool _isReadOnly;
  56. private bool _refreshOnChange;
  57. internal DbConnectionStringBuilderDescriptor(string propertyName, Type componentType, Type propertyType, bool isReadOnly, Attribute[] attributes) : base(propertyName, attributes) {
  58. //Bid.Trace("<comm.DbConnectionStringBuilderDescriptor|INFO> propertyName='%ls', propertyType='%ls'\n", propertyName, propertyType.Name);
  59. _componentType = componentType;
  60. _propertyType = propertyType;
  61. _isReadOnly = isReadOnly;
  62. }
  63. internal bool RefreshOnChange {
  64. get {
  65. return _refreshOnChange;
  66. }
  67. set {
  68. _refreshOnChange = value;
  69. }
  70. }
  71. public override Type ComponentType {
  72. get {
  73. return _componentType;
  74. }
  75. }
  76. public override bool IsReadOnly {
  77. get {
  78. return _isReadOnly;
  79. }
  80. }
  81. public override Type PropertyType {
  82. get {
  83. return _propertyType;
  84. }
  85. }
  86. public override bool CanResetValue(object component) {
  87. DbConnectionStringBuilder builder = (component as DbConnectionStringBuilder);
  88. return ((null != builder) && builder.ShouldSerialize(DisplayName));
  89. }
  90. public override object GetValue(object component) {
  91. DbConnectionStringBuilder builder = (component as DbConnectionStringBuilder);
  92. if (null != builder) {
  93. object value;
  94. if (builder.TryGetValue(DisplayName, out value)) {
  95. return value;
  96. }
  97. }
  98. return null;
  99. }
  100. public override void ResetValue(object component) {
  101. DbConnectionStringBuilder builder = (component as DbConnectionStringBuilder);
  102. if (null != builder) {
  103. builder.Remove(DisplayName);
  104. if (RefreshOnChange) {
  105. builder.ClearPropertyDescriptors();
  106. }
  107. }
  108. }
  109. public override void SetValue(object component, object value) {
  110. DbConnectionStringBuilder builder = (component as DbConnectionStringBuilder);
  111. if (null != builder) {
  112. // via the editor, empty string does a defacto Reset
  113. if ((typeof(string) == PropertyType) && String.Empty.Equals(value)) {
  114. value = null;
  115. }
  116. builder[DisplayName] = value;
  117. if (RefreshOnChange) {
  118. builder.ClearPropertyDescriptors();
  119. }
  120. }
  121. }
  122. public override bool ShouldSerializeValue(object component) {
  123. DbConnectionStringBuilder builder = (component as DbConnectionStringBuilder);
  124. return ((null != builder) && builder.ShouldSerialize(DisplayName));
  125. }
  126. }
  127. [Serializable()]
  128. internal sealed class ReadOnlyCollection<T> : System.Collections.ICollection, ICollection<T> {
  129. private T[] _items;
  130. internal ReadOnlyCollection(T[] items) {
  131. _items = items;
  132. #if DEBUG
  133. for(int i = 0; i < items.Length; ++i) {
  134. Debug.Assert(null != items[i], "null item");
  135. }
  136. #endif
  137. }
  138. public void CopyTo(T[] array, int arrayIndex) {
  139. Array.Copy(_items, 0, array, arrayIndex, _items.Length);
  140. }
  141. void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) {
  142. Array.Copy(_items, 0, array, arrayIndex, _items.Length);
  143. }
  144. IEnumerator<T> IEnumerable<T>.GetEnumerator() {
  145. return new Enumerator<T>(_items);
  146. }
  147. public System.Collections.IEnumerator GetEnumerator() {
  148. return new Enumerator<T>(_items);
  149. }
  150. bool System.Collections.ICollection.IsSynchronized {
  151. get { return false; }
  152. }
  153. Object System.Collections.ICollection.SyncRoot {
  154. get { return _items; }
  155. }
  156. bool ICollection<T>.IsReadOnly {
  157. get { return true;}
  158. }
  159. void ICollection<T>.Add(T value) {
  160. throw new NotSupportedException();
  161. }
  162. void ICollection<T>.Clear() {
  163. throw new NotSupportedException();
  164. }
  165. bool ICollection<T>.Contains(T value) {
  166. return Array.IndexOf(_items, value) >= 0;
  167. }
  168. bool ICollection<T>.Remove(T value) {
  169. throw new NotSupportedException();
  170. }
  171. public int Count {
  172. get { return _items.Length; }
  173. }
  174. [Serializable()]
  175. internal struct Enumerator<K> : IEnumerator<K>, System.Collections.IEnumerator { // based on List<T>.Enumerator
  176. private K[] _items;
  177. private int _index;
  178. internal Enumerator(K[] items) {
  179. _items = items;
  180. _index = -1;
  181. }
  182. public void Dispose() {
  183. }
  184. public bool MoveNext() {
  185. return (++_index < _items.Length);
  186. }
  187. public K Current {
  188. get {
  189. return _items[_index];
  190. }
  191. }
  192. Object System.Collections.IEnumerator.Current {
  193. get {
  194. return _items[_index];
  195. }
  196. }
  197. void System.Collections.IEnumerator.Reset() {
  198. _index = -1;
  199. }
  200. }
  201. }
  202. internal static class DbConnectionStringBuilderUtil
  203. {
  204. internal static bool ConvertToBoolean(object value)
  205. {
  206. Debug.Assert(null != value, "ConvertToBoolean(null)");
  207. string svalue = (value as string);
  208. if (null != svalue)
  209. {
  210. if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes"))
  211. return true;
  212. else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no"))
  213. return false;
  214. else
  215. {
  216. string tmp = svalue.Trim(); // Remove leading & trailing white space.
  217. if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes"))
  218. return true;
  219. else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no"))
  220. return false;
  221. }
  222. return Boolean.Parse(svalue);
  223. }
  224. try
  225. {
  226. return ((IConvertible)value).ToBoolean(CultureInfo.InvariantCulture);
  227. }
  228. catch (InvalidCastException e)
  229. {
  230. throw ADP.ConvertFailed(value.GetType(), typeof(Boolean), e);
  231. }
  232. }
  233. internal static bool ConvertToIntegratedSecurity(object value)
  234. {
  235. Debug.Assert(null != value, "ConvertToIntegratedSecurity(null)");
  236. string svalue = (value as string);
  237. if (null != svalue)
  238. {
  239. if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes"))
  240. return true;
  241. else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no"))
  242. return false;
  243. else
  244. {
  245. string tmp = svalue.Trim(); // Remove leading & trailing white space.
  246. if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes"))
  247. return true;
  248. else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no"))
  249. return false;
  250. }
  251. return Boolean.Parse(svalue);
  252. }
  253. try
  254. {
  255. return ((IConvertible)value).ToBoolean(CultureInfo.InvariantCulture);
  256. }
  257. catch (InvalidCastException e)
  258. {
  259. throw ADP.ConvertFailed(value.GetType(), typeof(Boolean), e);
  260. }
  261. }
  262. internal static int ConvertToInt32(object value)
  263. {
  264. try
  265. {
  266. return ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture);
  267. }
  268. catch (InvalidCastException e)
  269. {
  270. throw ADP.ConvertFailed(value.GetType(), typeof(Int32), e);
  271. }
  272. }
  273. internal static string ConvertToString(object value)
  274. {
  275. try
  276. {
  277. return ((IConvertible)value).ToString(CultureInfo.InvariantCulture);
  278. }
  279. catch (InvalidCastException e)
  280. {
  281. throw ADP.ConvertFailed(value.GetType(), typeof(String), e);
  282. }
  283. }
  284. #region <<PoolBlockingPeriod Utility>>
  285. const string PoolBlockingPeriodAutoString = "Auto";
  286. const string PoolBlockingPeriodAlwaysBlockString = "AlwaysBlock";
  287. const string PoolBlockingPeriodNeverBlockString = "NeverBlock";
  288. internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result)
  289. {
  290. Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
  291. Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)");
  292. if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAutoString))
  293. {
  294. result = PoolBlockingPeriod.Auto;
  295. return true;
  296. }
  297. else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAlwaysBlockString))
  298. {
  299. result = PoolBlockingPeriod.AlwaysBlock;
  300. return true;
  301. }
  302. else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodNeverBlockString))
  303. {
  304. result = PoolBlockingPeriod.NeverBlock;
  305. return true;
  306. }
  307. else
  308. {
  309. result = DbConnectionStringDefaults.PoolBlockingPeriod;
  310. return false;
  311. }
  312. }
  313. internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value)
  314. {
  315. Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
  316. return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock;
  317. }
  318. internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value)
  319. {
  320. Debug.Assert(IsValidPoolBlockingPeriodValue(value));
  321. if (value == PoolBlockingPeriod.AlwaysBlock)
  322. {
  323. return PoolBlockingPeriodAlwaysBlockString;
  324. }
  325. if (value == PoolBlockingPeriod.NeverBlock)
  326. {
  327. return PoolBlockingPeriodNeverBlockString;
  328. }
  329. else
  330. {
  331. return PoolBlockingPeriodAutoString;
  332. }
  333. }
  334. /// <summary>
  335. /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is:
  336. /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer
  337. /// * if the value is from type PoolBlockingPeriod, it will be used as is
  338. /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum
  339. /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException
  340. ///
  341. /// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException.
  342. /// </summary>
  343. /// <returns>PoolBlockingPeriod value in the valid range</returns>
  344. internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
  345. {
  346. Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)");
  347. string sValue = (value as string);
  348. PoolBlockingPeriod result;
  349. if (null != sValue)
  350. {
  351. // We could use Enum.TryParse<PoolBlockingPeriod> here, but it accepts value combinations like
  352. // "ReadOnly, ReadWrite" which are unwelcome here
  353. // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method.
  354. if (TryConvertToPoolBlockingPeriod(sValue, out result))
  355. {
  356. return result;
  357. }
  358. // try again after remove leading & trailing whitespaces.
  359. sValue = sValue.Trim();
  360. if (TryConvertToPoolBlockingPeriod(sValue, out result))
  361. {
  362. return result;
  363. }
  364. // string values must be valid
  365. throw ADP.InvalidConnectionOptionValue(keyword);
  366. }
  367. else
  368. {
  369. // the value is not string, try other options
  370. PoolBlockingPeriod eValue;
  371. if (value is PoolBlockingPeriod)
  372. {
  373. // quick path for the most common case
  374. eValue = (PoolBlockingPeriod)value;
  375. }
  376. else if (value.GetType().IsEnum)
  377. {
  378. // explicitly block scenarios in which user tries to use wrong enum types, like:
  379. // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process;
  380. // workaround: explicitly cast non-PoolBlockingPeriod enums to int
  381. throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null);
  382. }
  383. else
  384. {
  385. try
  386. {
  387. // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
  388. eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value);
  389. }
  390. catch (ArgumentException e)
  391. {
  392. // to be consistent with the messages we send in case of wrong type usage, replace
  393. // the error with our exception, and keep the original one as inner one for troubleshooting
  394. throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e);
  395. }
  396. }
  397. // ensure value is in valid range
  398. if (IsValidPoolBlockingPeriodValue(eValue))
  399. {
  400. return eValue;
  401. }
  402. else
  403. {
  404. throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue);
  405. }
  406. }
  407. }
  408. #endregion
  409. const string ApplicationIntentReadWriteString = "ReadWrite";
  410. const string ApplicationIntentReadOnlyString = "ReadOnly";
  411. internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result)
  412. {
  413. Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed");
  414. Debug.Assert(null != value, "TryConvertToApplicationIntent(null,...)");
  415. if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadOnlyString))
  416. {
  417. result = ApplicationIntent.ReadOnly;
  418. return true;
  419. }
  420. else if (StringComparer.OrdinalIgnoreCase.Equals(value, ApplicationIntentReadWriteString))
  421. {
  422. result = ApplicationIntent.ReadWrite;
  423. return true;
  424. }
  425. else
  426. {
  427. result = DbConnectionStringDefaults.ApplicationIntent;
  428. return false;
  429. }
  430. }
  431. internal static bool IsValidApplicationIntentValue(ApplicationIntent value)
  432. {
  433. Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed");
  434. return value == ApplicationIntent.ReadOnly || value == ApplicationIntent.ReadWrite;
  435. }
  436. internal static string ApplicationIntentToString(ApplicationIntent value)
  437. {
  438. Debug.Assert(IsValidApplicationIntentValue(value));
  439. if (value == ApplicationIntent.ReadOnly)
  440. {
  441. return ApplicationIntentReadOnlyString;
  442. }
  443. else
  444. {
  445. return ApplicationIntentReadWriteString;
  446. }
  447. }
  448. /// <summary>
  449. /// This method attempts to convert the given value tp ApplicationIntent enum. The algorithm is:
  450. /// * if the value is from type string, it will be matched against ApplicationIntent enum names only, using ordinal, case-insensitive comparer
  451. /// * if the value is from type ApplicationIntent, it will be used as is
  452. /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum
  453. /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException
  454. ///
  455. /// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException.
  456. /// </summary>
  457. /// <returns>applicaiton intent value in the valid range</returns>
  458. internal static ApplicationIntent ConvertToApplicationIntent(string keyword, object value)
  459. {
  460. Debug.Assert(null != value, "ConvertToApplicationIntent(null)");
  461. string sValue = (value as string);
  462. ApplicationIntent result;
  463. if (null != sValue)
  464. {
  465. // We could use Enum.TryParse<ApplicationIntent> here, but it accepts value combinations like
  466. // "ReadOnly, ReadWrite" which are unwelcome here
  467. // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method.
  468. if (TryConvertToApplicationIntent(sValue, out result))
  469. {
  470. return result;
  471. }
  472. // try again after remove leading & trailing whitespaces.
  473. sValue = sValue.Trim();
  474. if (TryConvertToApplicationIntent(sValue, out result))
  475. {
  476. return result;
  477. }
  478. // string values must be valid
  479. throw ADP.InvalidConnectionOptionValue(keyword);
  480. }
  481. else
  482. {
  483. // the value is not string, try other options
  484. ApplicationIntent eValue;
  485. if (value is ApplicationIntent)
  486. {
  487. // quick path for the most common case
  488. eValue = (ApplicationIntent)value;
  489. }
  490. else if (value.GetType().IsEnum)
  491. {
  492. // explicitly block scenarios in which user tries to use wrong enum types, like:
  493. // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process;
  494. // workaround: explicitly cast non-ApplicationIntent enums to int
  495. throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), null);
  496. }
  497. else
  498. {
  499. try
  500. {
  501. // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
  502. eValue = (ApplicationIntent)Enum.ToObject(typeof(ApplicationIntent), value);
  503. }
  504. catch (ArgumentException e)
  505. {
  506. // to be consistent with the messages we send in case of wrong type usage, replace
  507. // the error with our exception, and keep the original one as inner one for troubleshooting
  508. throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), e);
  509. }
  510. }
  511. // ensure value is in valid range
  512. if (IsValidApplicationIntentValue(eValue))
  513. {
  514. return eValue;
  515. }
  516. else
  517. {
  518. throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue);
  519. }
  520. }
  521. }
  522. const string SqlPasswordString = "Sql Password";
  523. const string ActiveDirectoryPasswordString = "Active Directory Password";
  524. const string ActiveDirectoryIntegratedString = "Active Directory Integrated";
  525. internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result)
  526. {
  527. Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 4, "SqlAuthenticationMethod enum has changed, update needed");
  528. bool isSuccess = false;
  529. if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString))
  530. {
  531. result = SqlAuthenticationMethod.SqlPassword;
  532. isSuccess = true;
  533. }
  534. else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString))
  535. {
  536. result = SqlAuthenticationMethod.ActiveDirectoryPassword;
  537. isSuccess = true;
  538. }
  539. else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString))
  540. {
  541. result = SqlAuthenticationMethod.ActiveDirectoryIntegrated;
  542. isSuccess = true;
  543. }
  544. else
  545. {
  546. result = DbConnectionStringDefaults.Authentication;
  547. }
  548. return isSuccess;
  549. }
  550. /// <summary>
  551. /// Column Encryption Setting.
  552. /// </summary>
  553. const string ColumnEncryptionSettingEnabledString = "Enabled";
  554. const string ColumnEncryptionSettingDisabledString = "Disabled";
  555. /// <summary>
  556. /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting.
  557. /// </summary>
  558. /// <param name="value"></param>
  559. /// <param name="result"></param>
  560. /// <returns></returns>
  561. internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) {
  562. bool isSuccess = false;
  563. if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingEnabledString)) {
  564. result = SqlConnectionColumnEncryptionSetting.Enabled;
  565. isSuccess = true;
  566. }
  567. else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ColumnEncryptionSettingDisabledString)) {
  568. result = SqlConnectionColumnEncryptionSetting.Disabled;
  569. isSuccess = true;
  570. }
  571. else {
  572. result = DbConnectionStringDefaults.ColumnEncryptionSetting;
  573. }
  574. return isSuccess;
  575. }
  576. /// <summary>
  577. /// Is it a valid connection level column encryption setting ?
  578. /// </summary>
  579. /// <param name="value"></param>
  580. /// <returns></returns>
  581. internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) {
  582. Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed");
  583. return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled;
  584. }
  585. /// <summary>
  586. /// Convert connection level column encryption setting value to string.
  587. /// </summary>
  588. /// <param name="value"></param>
  589. /// <returns></returns>
  590. internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) {
  591. Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting.");
  592. switch (value) {
  593. case SqlConnectionColumnEncryptionSetting.Enabled:
  594. return ColumnEncryptionSettingEnabledString;
  595. case SqlConnectionColumnEncryptionSetting.Disabled:
  596. return ColumnEncryptionSettingDisabledString;
  597. default:
  598. return null;
  599. }
  600. }
  601. internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) {
  602. Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 4, "SqlAuthenticationMethod enum has changed, update needed");
  603. return value == SqlAuthenticationMethod.SqlPassword
  604. || value == SqlAuthenticationMethod.ActiveDirectoryPassword
  605. || value == SqlAuthenticationMethod.ActiveDirectoryIntegrated
  606. || value == SqlAuthenticationMethod.NotSpecified;
  607. }
  608. internal static string AuthenticationTypeToString(SqlAuthenticationMethod value)
  609. {
  610. Debug.Assert(IsValidAuthenticationTypeValue(value));
  611. switch (value)
  612. {
  613. case SqlAuthenticationMethod.SqlPassword:
  614. return SqlPasswordString;
  615. case SqlAuthenticationMethod.ActiveDirectoryPassword:
  616. return ActiveDirectoryPasswordString;
  617. case SqlAuthenticationMethod.ActiveDirectoryIntegrated:
  618. return ActiveDirectoryIntegratedString;
  619. default:
  620. return null;
  621. }
  622. }
  623. internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value)
  624. {
  625. if (null == value)
  626. {
  627. return DbConnectionStringDefaults.Authentication;
  628. }
  629. string sValue = (value as string);
  630. SqlAuthenticationMethod result;
  631. if (null != sValue)
  632. {
  633. if (TryConvertToAuthenticationType(sValue, out result))
  634. {
  635. return result;
  636. }
  637. // try again after remove leading & trailing whitespaces.
  638. sValue = sValue.Trim();
  639. if (TryConvertToAuthenticationType(sValue, out result))
  640. {
  641. return result;
  642. }
  643. // string values must be valid
  644. throw ADP.InvalidConnectionOptionValue(keyword);
  645. }
  646. else
  647. {
  648. // the value is not string, try other options
  649. SqlAuthenticationMethod eValue;
  650. if (value is SqlAuthenticationMethod)
  651. {
  652. // quick path for the most common case
  653. eValue = (SqlAuthenticationMethod)value;
  654. }
  655. else if (value.GetType().IsEnum)
  656. {
  657. // explicitly block scenarios in which user tries to use wrong enum types, like:
  658. // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process;
  659. // workaround: explicitly cast non-ApplicationIntent enums to int
  660. throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), null);
  661. }
  662. else
  663. {
  664. try
  665. {
  666. // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
  667. eValue = (SqlAuthenticationMethod)Enum.ToObject(typeof(SqlAuthenticationMethod), value);
  668. }
  669. catch (ArgumentException e)
  670. {
  671. // to be consistent with the messages we send in case of wrong type usage, replace
  672. // the error with our exception, and keep the original one as inner one for troubleshooting
  673. throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), e);
  674. }
  675. }
  676. // ensure value is in valid range
  677. if (IsValidAuthenticationTypeValue(eValue))
  678. {
  679. return eValue;
  680. }
  681. else
  682. {
  683. throw ADP.InvalidEnumerationValue(typeof(SqlAuthenticationMethod), (int)eValue);
  684. }
  685. }
  686. }
  687. /// <summary>
  688. /// Convert the provided value to a SqlConnectionColumnEncryptionSetting.
  689. /// </summary>
  690. /// <param name="keyword"></param>
  691. /// <param name="value"></param>
  692. /// <returns></returns>
  693. internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSetting(string keyword, object value) {
  694. if (null == value) {
  695. return DbConnectionStringDefaults.ColumnEncryptionSetting;
  696. }
  697. string sValue = (value as string);
  698. SqlConnectionColumnEncryptionSetting result;
  699. if (null != sValue) {
  700. if (TryConvertToColumnEncryptionSetting(sValue, out result)) {
  701. return result;
  702. }
  703. // try again after remove leading & trailing whitespaces.
  704. sValue = sValue.Trim();
  705. if (TryConvertToColumnEncryptionSetting(sValue, out result)) {
  706. return result;
  707. }
  708. // string values must be valid
  709. throw ADP.InvalidConnectionOptionValue(keyword);
  710. }
  711. else {
  712. // the value is not string, try other options
  713. SqlConnectionColumnEncryptionSetting eValue;
  714. if (value is SqlConnectionColumnEncryptionSetting) {
  715. // quick path for the most common case
  716. eValue = (SqlConnectionColumnEncryptionSetting)value;
  717. }
  718. else if (value.GetType().IsEnum) {
  719. // explicitly block scenarios in which user tries to use wrong enum types, like:
  720. // builder["SqlConnectionColumnEncryptionSetting"] = EnvironmentVariableTarget.Process;
  721. // workaround: explicitly cast non-SqlConnectionColumnEncryptionSetting enums to int
  722. throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), null);
  723. }
  724. else {
  725. try {
  726. // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
  727. eValue = (SqlConnectionColumnEncryptionSetting)Enum.ToObject(typeof(SqlConnectionColumnEncryptionSetting), value);
  728. }
  729. catch (ArgumentException e) {
  730. // to be consistent with the messages we send in case of wrong type usage, replace
  731. // the error with our exception, and keep the original one as inner one for troubleshooting
  732. throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), e);
  733. }
  734. }
  735. // ensure value is in valid range
  736. if (IsValidColumnEncryptionSetting(eValue)) {
  737. return eValue;
  738. }
  739. else {
  740. throw ADP.InvalidEnumerationValue(typeof(SqlConnectionColumnEncryptionSetting), (int)eValue);
  741. }
  742. }
  743. }
  744. }
  745. internal static class DbConnectionStringDefaults {
  746. // all
  747. // internal const string NamedConnection = "";
  748. // Odbc
  749. internal const string Driver = "";
  750. internal const string Dsn = "";
  751. // OleDb
  752. internal const bool AdoNetPooler = false;
  753. internal const string FileName = "";
  754. internal const int OleDbServices = ~(/*DBPROPVAL_OS_AGR_AFTERSESSION*/0x00000008 | /*DBPROPVAL_OS_CLIENTCURSOR*/0x00000004); // -13
  755. internal const string Provider = "";
  756. // OracleClient
  757. internal const bool Unicode = false;
  758. internal const bool OmitOracleConnectionName = false;
  759. // SqlClient
  760. internal const ApplicationIntent ApplicationIntent = System.Data.SqlClient.ApplicationIntent.ReadWrite;
  761. internal const string ApplicationName = ".Net SqlClient Data Provider";
  762. internal const bool AsynchronousProcessing = false;
  763. internal const string AttachDBFilename = "";
  764. internal const int ConnectTimeout = 15;
  765. internal const bool ConnectionReset = true;
  766. internal const bool ContextConnection = false;
  767. internal const string CurrentLanguage = "";
  768. internal const string DataSource = "";
  769. internal const bool Encrypt = false;
  770. internal const bool Enlist = true;
  771. internal const string FailoverPartner = "";
  772. internal const string InitialCatalog = "";
  773. internal const bool IntegratedSecurity = false;
  774. internal const int LoadBalanceTimeout = 0; // default of 0 means don't use
  775. internal const bool MultipleActiveResultSets = false;
  776. internal const bool MultiSubnetFailover = false;
  777. internal const bool TransparentNetworkIPResolution = true;
  778. internal const int MaxPoolSize = 100;
  779. internal const int MinPoolSize = 0;
  780. internal const string NetworkLibrary = "";
  781. internal const int PacketSize = 8000;
  782. internal const string Password = "";
  783. internal const bool PersistSecurityInfo = false;
  784. internal const bool Pooling = true;
  785. internal const bool TrustServerCertificate = false;
  786. internal const string TypeSystemVersion = "Latest";
  787. internal const string UserID = "";
  788. internal const bool UserInstance = false;
  789. internal const bool Replication = false;
  790. internal const string WorkstationID = "";
  791. internal const string TransactionBinding = "Implicit Unbind";
  792. internal const int ConnectRetryCount = 1;
  793. internal const int ConnectRetryInterval = 10;
  794. internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified;
  795. internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled;
  796. internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto;
  797. }
  798. internal static class DbConnectionOptionKeywords {
  799. // Odbc
  800. internal const string Driver = "driver";
  801. internal const string Pwd = "pwd";
  802. internal const string UID = "uid";
  803. // OleDb
  804. internal const string DataProvider = "data provider";
  805. internal const string ExtendedProperties = "extended properties";
  806. internal const string FileName = "file name";
  807. internal const string Provider = "provider";
  808. internal const string RemoteProvider = "remote provider";
  809. // common keywords (OleDb, OracleClient, SqlClient)
  810. internal const string Password = "password";
  811. internal const string UserID = "user id";
  812. }
  813. internal static class DbConnectionStringKeywords {
  814. // all
  815. // internal const string NamedConnection = "Named Connection";
  816. // Odbc
  817. internal const string Driver = "Driver";
  818. internal const string Dsn = "Dsn";
  819. internal const string FileDsn = "FileDsn";
  820. internal const string SaveFile = "SaveFile";
  821. // OleDb
  822. internal const string FileName = "File Name";
  823. internal const string OleDbServices = "OLE DB Services";
  824. internal const string Provider = "Provider";
  825. // OracleClient
  826. internal const string Unicode = "Unicode";
  827. internal const string OmitOracleConnectionName = "Omit Oracle Connection Name";
  828. // SqlClient
  829. internal const string ApplicationIntent = "ApplicationIntent";
  830. internal const string ApplicationName = "Application Name";
  831. internal const string AsynchronousProcessing = "Asynchronous Processing";
  832. internal const string AttachDBFilename = "AttachDbFilename";
  833. internal const string ConnectTimeout = "Connect Timeout";
  834. internal const string ConnectionReset = "Connection Reset";
  835. internal const string ContextConnection = "Context Connection";
  836. internal const string CurrentLanguage = "Current Language";
  837. internal const string Encrypt = "Encrypt";
  838. internal const string FailoverPartner = "Failover Partner";
  839. internal const string InitialCatalog = "Initial Catalog";
  840. internal const string MultipleActiveResultSets = "MultipleActiveResultSets";
  841. internal const string MultiSubnetFailover = "MultiSubnetFailover";
  842. internal const string TransparentNetworkIPResolution = "TransparentNetworkIPResolution";
  843. internal const string NetworkLibrary = "Network Library";
  844. internal const string PacketSize = "Packet Size";
  845. internal const string Replication = "Replication";
  846. internal const string TransactionBinding = "Transaction Binding";
  847. internal const string TrustServerCertificate = "TrustServerCertificate";
  848. internal const string TypeSystemVersion = "Type System Version";
  849. internal const string UserInstance = "User Instance";
  850. internal const string WorkstationID = "Workstation ID";
  851. internal const string ConnectRetryCount = "ConnectRetryCount";
  852. internal const string ConnectRetryInterval = "ConnectRetryInterval";
  853. internal const string Authentication = "Authentication";
  854. internal const string Certificate = "Certificate";
  855. internal const string ColumnEncryptionSetting = "Column Encryption Setting";
  856. internal const string PoolBlockingPeriod = "PoolBlockingPeriod";
  857. // common keywords (OleDb, OracleClient, SqlClient)
  858. internal const string DataSource = "Data Source";
  859. internal const string IntegratedSecurity = "Integrated Security";
  860. internal const string Password = "Password";
  861. internal const string PersistSecurityInfo = "Persist Security Info";
  862. internal const string UserID = "User ID";
  863. // managed pooling (OracleClient, SqlClient)
  864. internal const string Enlist = "Enlist";
  865. internal const string LoadBalanceTimeout = "Load Balance Timeout";
  866. internal const string MaxPoolSize = "Max Pool Size";
  867. internal const string Pooling = "Pooling";
  868. internal const string MinPoolSize = "Min Pool Size";
  869. }
  870. internal static class DbConnectionStringSynonyms {
  871. //internal const string AsynchronousProcessing = Async;
  872. internal const string Async = "async";
  873. //internal const string ApplicationName = APP;
  874. internal const string APP = "app";
  875. //internal const string AttachDBFilename = EXTENDEDPROPERTIES+","+INITIALFILENAME;
  876. internal const string EXTENDEDPROPERTIES = "extended properties";
  877. internal const string INITIALFILENAME = "initial file name";
  878. //internal const string ConnectTimeout = CONNECTIONTIMEOUT+","+TIMEOUT;
  879. internal const string CONNECTIONTIMEOUT = "connection timeout";
  880. internal const string TIMEOUT = "timeout";
  881. //internal const string CurrentLanguage = LANGUAGE;
  882. internal const string LANGUAGE = "language";
  883. //internal const string OraDataSource = SERVER;
  884. //internal const string SqlDataSource = ADDR+","+ADDRESS+","+SERVER+","+NETWORKADDRESS;
  885. internal const string ADDR = "addr";
  886. internal const string ADDRESS = "address";
  887. internal const string SERVER = "server";
  888. internal const string NETWORKADDRESS = "network address";
  889. //internal const string InitialCatalog = DATABASE;
  890. internal const string DATABASE = "database";
  891. //internal const string IntegratedSecurity = TRUSTEDCONNECTION;
  892. internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in everett
  893. //internal const string LoadBalanceTimeout = ConnectionLifetime;
  894. internal const string ConnectionLifetime = "connection lifetime";
  895. //internal const string NetworkLibrary = NET+","+NETWORK;
  896. internal const string NET = "net";
  897. internal const string NETWORK = "network";
  898. internal const string WorkaroundOracleBug914652 = "Workaround Oracle Bug 914652";
  899. //internal const string Password = Pwd;
  900. internal const string Pwd = "pwd";
  901. //internal const string PersistSecurityInfo = PERSISTSECURITYINFO;
  902. internal const string PERSISTSECURITYINFO = "persistsecurityinfo";
  903. //internal const string UserID = UID+","+User;
  904. internal const string UID = "uid";
  905. internal const string User = "user";
  906. //internal const string WorkstationID = WSID;
  907. internal const string WSID = "wsid";
  908. }
  909. }