DbConnectionStringBuilder.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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. namespace System.Data.Common {
  9. using System;
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.ComponentModel;
  13. using System.Data;
  14. using System.Data.Common;
  15. using System.Diagnostics;
  16. using System.Globalization;
  17. using System.Runtime.Serialization;
  18. using System.Security.Permissions;
  19. using System.Text;
  20. using System.Text.RegularExpressions;
  21. using System.Diagnostics.CodeAnalysis;
  22. public class DbConnectionStringBuilder : System.Collections.IDictionary, ICustomTypeDescriptor {
  23. // keyword->value currently listed in the connection string
  24. private Dictionary<string,object> _currentValues;
  25. // cached connectionstring to avoid constant rebuilding
  26. // and to return a user's connectionstring as is until editing occurs
  27. private string _connectionString = "";
  28. private PropertyDescriptorCollection _propertyDescriptors;
  29. private bool _browsableConnectionString = true;
  30. private readonly bool UseOdbcRules;
  31. private static int _objectTypeCount; // Bid counter
  32. internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  33. public DbConnectionStringBuilder() {
  34. }
  35. public DbConnectionStringBuilder(bool useOdbcRules) {
  36. UseOdbcRules = useOdbcRules;
  37. }
  38. private ICollection Collection {
  39. get { return (ICollection)CurrentValues; }
  40. }
  41. private IDictionary Dictionary {
  42. get { return (IDictionary)CurrentValues; }
  43. }
  44. private Dictionary<string,object> CurrentValues {
  45. get {
  46. Dictionary<string,object> values = _currentValues;
  47. if (null == values) {
  48. values = new Dictionary<string,object>(StringComparer.OrdinalIgnoreCase);
  49. _currentValues = values;
  50. }
  51. return values;
  52. }
  53. }
  54. object System.Collections.IDictionary.this[object keyword] {
  55. // delegate to this[string keyword]
  56. get { return this[ObjectToString(keyword)]; }
  57. set { this[ObjectToString(keyword)] = value; }
  58. }
  59. [Browsable(false)]
  60. public virtual object this[string keyword] {
  61. get {
  62. Bid.Trace("<comm.DbConnectionStringBuilder.get_Item|API> %d#, keyword='%ls'\n", ObjectID, keyword);
  63. ADP.CheckArgumentNull(keyword, "keyword");
  64. object value;
  65. if (CurrentValues.TryGetValue(keyword, out value)) {
  66. return value;
  67. }
  68. throw ADP.KeywordNotSupported(keyword);
  69. }
  70. set {
  71. ADP.CheckArgumentNull(keyword, "keyword");
  72. bool flag = false;
  73. if (null != value) {
  74. string keyvalue = DbConnectionStringBuilderUtil.ConvertToString(value);
  75. DbConnectionOptions.ValidateKeyValuePair(keyword, keyvalue);
  76. flag = CurrentValues.ContainsKey(keyword);
  77. // store keyword/value pair
  78. CurrentValues[keyword] = keyvalue;
  79. }
  80. else {
  81. flag = Remove(keyword);
  82. }
  83. _connectionString = null;
  84. if (flag) {
  85. _propertyDescriptors = null;
  86. }
  87. }
  88. }
  89. [Browsable(false)]
  90. [DesignOnly(true)]
  91. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  92. [EditorBrowsableAttribute(EditorBrowsableState.Never)]
  93. public bool BrowsableConnectionString {
  94. get {
  95. return _browsableConnectionString;
  96. }
  97. set {
  98. _browsableConnectionString = value;
  99. _propertyDescriptors = null;
  100. }
  101. }
  102. [RefreshPropertiesAttribute(RefreshProperties.All)]
  103. [ResCategoryAttribute(Res.DataCategory_Data)]
  104. [ResDescriptionAttribute(Res.DbConnectionString_ConnectionString)]
  105. public string ConnectionString {
  106. get {
  107. Bid.Trace("<comm.DbConnectionStringBuilder.get_ConnectionString|API> %d#\n", ObjectID);
  108. string connectionString = _connectionString;
  109. if (null == connectionString) {
  110. StringBuilder builder = new StringBuilder();
  111. foreach(string keyword in Keys) {
  112. object value;
  113. if (ShouldSerialize(keyword) && TryGetValue(keyword, out value)) {
  114. string keyvalue = ConvertValueToString(value);
  115. AppendKeyValuePair(builder, keyword, keyvalue, UseOdbcRules);
  116. }
  117. }
  118. connectionString = builder.ToString();
  119. _connectionString = connectionString;
  120. }
  121. return connectionString;
  122. }
  123. set {
  124. Bid.Trace("<comm.DbConnectionStringBuilder.set_ConnectionString|API> %d#\n", ObjectID);
  125. DbConnectionOptions constr = new DbConnectionOptions(value, null, UseOdbcRules);
  126. string originalValue = ConnectionString;
  127. Clear();
  128. try {
  129. for(NameValuePair pair = constr.KeyChain; null != pair; pair = pair.Next) {
  130. if (null != pair.Value) {
  131. this[pair.Name] = pair.Value;
  132. }
  133. else {
  134. Remove(pair.Name);
  135. }
  136. }
  137. _connectionString = null;
  138. }
  139. catch(ArgumentException) { // restore original string
  140. ConnectionString = originalValue;
  141. _connectionString = originalValue;
  142. throw;
  143. }
  144. }
  145. }
  146. [Browsable(false)]
  147. public virtual int Count {
  148. get { return CurrentValues.Count; }
  149. }
  150. [Browsable(false)]
  151. public bool IsReadOnly {
  152. get { return false; }
  153. }
  154. [Browsable(false)]
  155. public virtual bool IsFixedSize {
  156. get { return false; }
  157. }
  158. bool System.Collections.ICollection.IsSynchronized {
  159. get { return Collection.IsSynchronized; }
  160. }
  161. [Browsable(false)]
  162. public virtual ICollection Keys {
  163. get {
  164. Bid.Trace("<comm.DbConnectionStringBuilder.Keys|API> %d#\n", ObjectID);
  165. return Dictionary.Keys;
  166. }
  167. }
  168. internal int ObjectID {
  169. get {
  170. return _objectID;
  171. }
  172. }
  173. object System.Collections.ICollection.SyncRoot {
  174. get { return Collection.SyncRoot; }
  175. }
  176. [Browsable(false)]
  177. public virtual ICollection Values {
  178. get {
  179. Bid.Trace("<comm.DbConnectionStringBuilder.Values|API> %d#\n", ObjectID);
  180. System.Collections.Generic.ICollection<string> keys = (System.Collections.Generic.ICollection<string>)Keys;
  181. System.Collections.Generic.IEnumerator<string> keylist = keys.GetEnumerator();
  182. object[] values = new object[keys.Count];
  183. for(int i = 0; i < values.Length; ++i) {
  184. keylist.MoveNext();
  185. values[i] = this[keylist.Current];
  186. Debug.Assert(null != values[i], "null value " + keylist.Current);
  187. }
  188. return new System.Data.Common.ReadOnlyCollection<object>(values);
  189. }
  190. }
  191. internal virtual string ConvertValueToString(object value) {
  192. return (value == null) ? (string)null : Convert.ToString(value, CultureInfo.InvariantCulture);
  193. }
  194. void System.Collections.IDictionary.Add(object keyword, object value) {
  195. Add(ObjectToString(keyword), value);
  196. }
  197. public void Add(string keyword, object value) {
  198. this[keyword] = value;
  199. }
  200. public static void AppendKeyValuePair(StringBuilder builder, string keyword, string value) {
  201. DbConnectionOptions.AppendKeyValuePairBuilder(builder, keyword, value, false);
  202. }
  203. public static void AppendKeyValuePair(StringBuilder builder, string keyword, string value, bool useOdbcRules) {
  204. DbConnectionOptions.AppendKeyValuePairBuilder(builder, keyword, value, useOdbcRules);
  205. }
  206. public virtual void Clear() {
  207. Bid.Trace("<comm.DbConnectionStringBuilder.Clear|API>\n");
  208. _connectionString = "";
  209. _propertyDescriptors = null;
  210. CurrentValues.Clear();
  211. }
  212. protected internal void ClearPropertyDescriptors() {
  213. _propertyDescriptors = null;
  214. }
  215. // does the keyword exist as a strongly typed keyword or as a stored value
  216. bool System.Collections.IDictionary.Contains(object keyword) {
  217. return ContainsKey(ObjectToString(keyword));
  218. }
  219. public virtual bool ContainsKey(string keyword) {
  220. ADP.CheckArgumentNull(keyword, "keyword");
  221. return CurrentValues.ContainsKey(keyword);
  222. }
  223. void ICollection.CopyTo(Array array, int index) {
  224. Bid.Trace("<comm.DbConnectionStringBuilder.ICollection.CopyTo|API> %d#\n", ObjectID);
  225. Collection.CopyTo(array, index);
  226. }
  227. public virtual bool EquivalentTo(DbConnectionStringBuilder connectionStringBuilder) {
  228. ADP.CheckArgumentNull(connectionStringBuilder, "connectionStringBuilder");
  229. Bid.Trace("<comm.DbConnectionStringBuilder.EquivalentTo|API> %d#, connectionStringBuilder=%d#\n", ObjectID, connectionStringBuilder.ObjectID);
  230. if ((GetType() != connectionStringBuilder.GetType()) || (CurrentValues.Count != connectionStringBuilder.CurrentValues.Count)) {
  231. return false;
  232. }
  233. object value;
  234. foreach(KeyValuePair<string, object> entry in CurrentValues) {
  235. if (!connectionStringBuilder.CurrentValues.TryGetValue(entry.Key, out value) || !entry.Value.Equals(value)) {
  236. return false;
  237. }
  238. }
  239. return true;
  240. }
  241. IEnumerator System.Collections.IEnumerable.GetEnumerator() {
  242. Bid.Trace("<comm.DbConnectionStringBuilder.IEnumerable.GetEnumerator|API> %d#\n", ObjectID);
  243. return Collection.GetEnumerator();
  244. }
  245. IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() {
  246. Bid.Trace("<comm.DbConnectionStringBuilder.IDictionary.GetEnumerator|API> %d#\n", ObjectID);
  247. return Dictionary.GetEnumerator();
  248. }
  249. [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "See Dev11 bug 875012")]
  250. private string ObjectToString(object keyword) {
  251. try {
  252. return (string)keyword;
  253. }
  254. catch(InvalidCastException) {
  255. //
  256. throw new ArgumentException("keyword", "not a string");
  257. }
  258. }
  259. void System.Collections.IDictionary.Remove(object keyword) {
  260. Remove(ObjectToString(keyword));
  261. }
  262. public virtual bool Remove(string keyword) {
  263. Bid.Trace("<comm.DbConnectionStringBuilder.Remove|API> %d#, keyword='%ls'\n", ObjectID, keyword);
  264. ADP.CheckArgumentNull(keyword, "keyword");
  265. if (CurrentValues.Remove(keyword)) {
  266. _connectionString = null;
  267. _propertyDescriptors = null;
  268. return true;
  269. }
  270. return false;
  271. }
  272. // does the keyword exist as a stored value or something that should always be persisted
  273. public virtual bool ShouldSerialize(string keyword) {
  274. ADP.CheckArgumentNull(keyword, "keyword");
  275. return CurrentValues.ContainsKey(keyword);
  276. }
  277. public override string ToString() {
  278. return ConnectionString;
  279. }
  280. public virtual bool TryGetValue(string keyword, out object value) {
  281. ADP.CheckArgumentNull(keyword, "keyword");
  282. return CurrentValues.TryGetValue(keyword, out value);
  283. }
  284. internal Attribute[] GetAttributesFromCollection(AttributeCollection collection) {
  285. Attribute[] attributes = new Attribute[collection.Count];
  286. collection.CopyTo(attributes, 0);
  287. return attributes;
  288. }
  289. private PropertyDescriptorCollection GetProperties() {
  290. PropertyDescriptorCollection propertyDescriptors = _propertyDescriptors;
  291. if (null == propertyDescriptors) {
  292. IntPtr hscp;
  293. Bid.ScopeEnter(out hscp, "<comm.DbConnectionStringBuilder.GetProperties|INFO> %d#", ObjectID);
  294. try {
  295. Hashtable descriptors = new Hashtable(StringComparer.OrdinalIgnoreCase);
  296. GetProperties(descriptors);
  297. PropertyDescriptor[] properties = new PropertyDescriptor[descriptors.Count];
  298. descriptors.Values.CopyTo(properties, 0);
  299. propertyDescriptors = new PropertyDescriptorCollection(properties);
  300. _propertyDescriptors = propertyDescriptors;
  301. }
  302. finally {
  303. Bid.ScopeLeave(ref hscp);
  304. }
  305. }
  306. return propertyDescriptors;
  307. }
  308. protected virtual void GetProperties(Hashtable propertyDescriptors) {
  309. IntPtr hscp;
  310. Bid.ScopeEnter(out hscp, "<comm.DbConnectionStringBuilder.GetProperties|API> %d#", ObjectID);
  311. try {
  312. // show all strongly typed properties (not already added)
  313. // except ConnectionString iff BrowsableConnectionString
  314. Attribute[] attributes;
  315. foreach(PropertyDescriptor reflected in TypeDescriptor.GetProperties(this, true)) {
  316. if (ADP.ConnectionString != reflected.Name) {
  317. string displayName = reflected.DisplayName;
  318. if (!propertyDescriptors.ContainsKey(displayName)) {
  319. attributes = GetAttributesFromCollection(reflected.Attributes);
  320. PropertyDescriptor descriptor = new DbConnectionStringBuilderDescriptor(reflected.Name,
  321. reflected.ComponentType, reflected.PropertyType, reflected.IsReadOnly, attributes);
  322. propertyDescriptors[displayName] = descriptor;
  323. }
  324. // else added by derived class first
  325. }
  326. else if (BrowsableConnectionString) {
  327. propertyDescriptors[ADP.ConnectionString] = reflected;
  328. }
  329. else {
  330. propertyDescriptors.Remove(ADP.ConnectionString);
  331. }
  332. }
  333. // all keywords in Keys list that do not have strongly typed property, ODBC case
  334. // ignore 'Workaround Oracle Bug 914652' via IsFixedSize
  335. if (!IsFixedSize) {
  336. attributes = null;
  337. foreach(string keyword in Keys) {
  338. if (!propertyDescriptors.ContainsKey(keyword)) {
  339. object value = this[keyword];
  340. Type vtype;
  341. if (null != value) {
  342. vtype = value.GetType();
  343. if (typeof(string) == vtype) {
  344. int tmp1;
  345. if (Int32.TryParse((string)value, out tmp1)) {
  346. vtype = typeof(Int32);
  347. }
  348. else {
  349. bool tmp2;
  350. if (Boolean.TryParse((string)value, out tmp2)) {
  351. vtype = typeof(Boolean);
  352. }
  353. }
  354. }
  355. }
  356. else {
  357. vtype = typeof(string);
  358. }
  359. Attribute[] useAttributes = attributes;
  360. if (StringComparer.OrdinalIgnoreCase.Equals(DbConnectionStringKeywords.Password, keyword) ||
  361. StringComparer.OrdinalIgnoreCase.Equals(DbConnectionStringSynonyms.Pwd, keyword)) {
  362. useAttributes = new Attribute[] {
  363. BrowsableAttribute.Yes,
  364. PasswordPropertyTextAttribute.Yes,
  365. new ResCategoryAttribute(Res.DataCategory_Security),
  366. RefreshPropertiesAttribute.All,
  367. };
  368. }
  369. else if (null == attributes) {
  370. attributes = new Attribute[] {
  371. BrowsableAttribute.Yes,
  372. RefreshPropertiesAttribute.All,
  373. };
  374. useAttributes = attributes;
  375. }
  376. PropertyDescriptor descriptor = new DbConnectionStringBuilderDescriptor(keyword,
  377. this.GetType(), vtype, false, useAttributes);
  378. propertyDescriptors[keyword] = descriptor;
  379. }
  380. }
  381. }
  382. }
  383. finally {
  384. Bid.ScopeLeave(ref hscp);
  385. }
  386. }
  387. private PropertyDescriptorCollection GetProperties(Attribute[] attributes) {
  388. PropertyDescriptorCollection propertyDescriptors = GetProperties();
  389. if ((null == attributes) || (0 == attributes.Length)) {
  390. // Basic case has no filtering
  391. return propertyDescriptors;
  392. }
  393. // Create an array that is guaranteed to hold all attributes
  394. PropertyDescriptor[] propertiesArray = new PropertyDescriptor[propertyDescriptors.Count];
  395. // Create an index to reference into this array
  396. int index = 0;
  397. // Iterate over each property
  398. foreach (PropertyDescriptor property in propertyDescriptors) {
  399. // Identify if this property's attributes match the specification
  400. bool match = true;
  401. foreach (Attribute attribute in attributes) {
  402. Attribute attr = property.Attributes[attribute.GetType()];
  403. if ((attr == null && !attribute.IsDefaultAttribute()) || !attr.Match(attribute)) {
  404. match = false;
  405. break;
  406. }
  407. }
  408. // If this property matches, add it to the array
  409. if (match) {
  410. propertiesArray[index] = property;
  411. index++;
  412. }
  413. }
  414. // Create a new array that only contains the filtered properties
  415. PropertyDescriptor[] filteredPropertiesArray = new PropertyDescriptor[index];
  416. Array.Copy(propertiesArray, filteredPropertiesArray, index);
  417. return new PropertyDescriptorCollection(filteredPropertiesArray);
  418. }
  419. string ICustomTypeDescriptor.GetClassName() {
  420. return TypeDescriptor.GetClassName(this, true);
  421. }
  422. string ICustomTypeDescriptor.GetComponentName() {
  423. return TypeDescriptor.GetComponentName(this, true);
  424. }
  425. AttributeCollection ICustomTypeDescriptor.GetAttributes() {
  426. return TypeDescriptor.GetAttributes(this, true);
  427. }
  428. object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
  429. return TypeDescriptor.GetEditor(this, editorBaseType, true);
  430. }
  431. TypeConverter ICustomTypeDescriptor.GetConverter() {
  432. return TypeDescriptor.GetConverter(this, true);
  433. }
  434. PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
  435. return TypeDescriptor.GetDefaultProperty(this, true);
  436. }
  437. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
  438. return GetProperties();
  439. }
  440. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
  441. return GetProperties(attributes);
  442. }
  443. EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
  444. return TypeDescriptor.GetDefaultEvent(this, true);
  445. }
  446. EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
  447. return TypeDescriptor.GetEvents(this, true);
  448. }
  449. EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
  450. return TypeDescriptor.GetEvents(this, attributes, true);
  451. }
  452. object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
  453. return this;
  454. }
  455. }
  456. }