DbConnectionStringBuilder.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DbConnectionStringBuilder.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</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 = (null != value) ? Convert.ToString(value, CultureInfo.InvariantCulture) : (string)null;
  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. void System.Collections.IDictionary.Add(object keyword, object value) {
  192. Add(ObjectToString(keyword), value);
  193. }
  194. public void Add(string keyword, object value) {
  195. this[keyword] = value;
  196. }
  197. public static void AppendKeyValuePair(StringBuilder builder, string keyword, string value) {
  198. DbConnectionOptions.AppendKeyValuePairBuilder(builder, keyword, value, false);
  199. }
  200. public static void AppendKeyValuePair(StringBuilder builder, string keyword, string value, bool useOdbcRules) {
  201. DbConnectionOptions.AppendKeyValuePairBuilder(builder, keyword, value, useOdbcRules);
  202. }
  203. public virtual void Clear() {
  204. Bid.Trace("<comm.DbConnectionStringBuilder.Clear|API>\n");
  205. _connectionString = "";
  206. _propertyDescriptors = null;
  207. CurrentValues.Clear();
  208. }
  209. protected internal void ClearPropertyDescriptors() {
  210. _propertyDescriptors = null;
  211. }
  212. // does the keyword exist as a strongly typed keyword or as a stored value
  213. bool System.Collections.IDictionary.Contains(object keyword) {
  214. return ContainsKey(ObjectToString(keyword));
  215. }
  216. public virtual bool ContainsKey(string keyword) {
  217. ADP.CheckArgumentNull(keyword, "keyword");
  218. return CurrentValues.ContainsKey(keyword);
  219. }
  220. void ICollection.CopyTo(Array array, int index) {
  221. Bid.Trace("<comm.DbConnectionStringBuilder.ICollection.CopyTo|API> %d#\n", ObjectID);
  222. Collection.CopyTo(array, index);
  223. }
  224. public virtual bool EquivalentTo(DbConnectionStringBuilder connectionStringBuilder) {
  225. ADP.CheckArgumentNull(connectionStringBuilder, "connectionStringBuilder");
  226. Bid.Trace("<comm.DbConnectionStringBuilder.EquivalentTo|API> %d#, connectionStringBuilder=%d#\n", ObjectID, connectionStringBuilder.ObjectID);
  227. if ((GetType() != connectionStringBuilder.GetType()) || (CurrentValues.Count != connectionStringBuilder.CurrentValues.Count)) {
  228. return false;
  229. }
  230. object value;
  231. foreach(KeyValuePair<string, object> entry in CurrentValues) {
  232. if (!connectionStringBuilder.CurrentValues.TryGetValue(entry.Key, out value) || !entry.Value.Equals(value)) {
  233. return false;
  234. }
  235. }
  236. return true;
  237. }
  238. IEnumerator System.Collections.IEnumerable.GetEnumerator() {
  239. Bid.Trace("<comm.DbConnectionStringBuilder.IEnumerable.GetEnumerator|API> %d#\n", ObjectID);
  240. return Collection.GetEnumerator();
  241. }
  242. IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() {
  243. Bid.Trace("<comm.DbConnectionStringBuilder.IDictionary.GetEnumerator|API> %d#\n", ObjectID);
  244. return Dictionary.GetEnumerator();
  245. }
  246. [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "See Dev11 bug 875012")]
  247. private string ObjectToString(object keyword) {
  248. try {
  249. return (string)keyword;
  250. }
  251. catch(InvalidCastException) {
  252. //
  253. throw new ArgumentException("keyword", "not a string");
  254. }
  255. }
  256. void System.Collections.IDictionary.Remove(object keyword) {
  257. Remove(ObjectToString(keyword));
  258. }
  259. public virtual bool Remove(string keyword) {
  260. Bid.Trace("<comm.DbConnectionStringBuilder.Remove|API> %d#, keyword='%ls'\n", ObjectID, keyword);
  261. ADP.CheckArgumentNull(keyword, "keyword");
  262. if (CurrentValues.Remove(keyword)) {
  263. _connectionString = null;
  264. _propertyDescriptors = null;
  265. return true;
  266. }
  267. return false;
  268. }
  269. // does the keyword exist as a stored value or something that should always be persisted
  270. public virtual bool ShouldSerialize(string keyword) {
  271. ADP.CheckArgumentNull(keyword, "keyword");
  272. return CurrentValues.ContainsKey(keyword);
  273. }
  274. public override string ToString() {
  275. return ConnectionString;
  276. }
  277. public virtual bool TryGetValue(string keyword, out object value) {
  278. ADP.CheckArgumentNull(keyword, "keyword");
  279. return CurrentValues.TryGetValue(keyword, out value);
  280. }
  281. internal Attribute[] GetAttributesFromCollection(AttributeCollection collection) {
  282. Attribute[] attributes = new Attribute[collection.Count];
  283. collection.CopyTo(attributes, 0);
  284. return attributes;
  285. }
  286. private PropertyDescriptorCollection GetProperties() {
  287. PropertyDescriptorCollection propertyDescriptors = _propertyDescriptors;
  288. if (null == propertyDescriptors) {
  289. IntPtr hscp;
  290. Bid.ScopeEnter(out hscp, "<comm.DbConnectionStringBuilder.GetProperties|INFO> %d#", ObjectID);
  291. try {
  292. Hashtable descriptors = new Hashtable(StringComparer.OrdinalIgnoreCase);
  293. GetProperties(descriptors);
  294. PropertyDescriptor[] properties = new PropertyDescriptor[descriptors.Count];
  295. descriptors.Values.CopyTo(properties, 0);
  296. propertyDescriptors = new PropertyDescriptorCollection(properties);
  297. _propertyDescriptors = propertyDescriptors;
  298. }
  299. finally {
  300. Bid.ScopeLeave(ref hscp);
  301. }
  302. }
  303. return propertyDescriptors;
  304. }
  305. protected virtual void GetProperties(Hashtable propertyDescriptors) {
  306. IntPtr hscp;
  307. Bid.ScopeEnter(out hscp, "<comm.DbConnectionStringBuilder.GetProperties|API> %d#", ObjectID);
  308. try {
  309. // show all strongly typed properties (not already added)
  310. // except ConnectionString iff BrowsableConnectionString
  311. Attribute[] attributes;
  312. foreach(PropertyDescriptor reflected in TypeDescriptor.GetProperties(this, true)) {
  313. if (ADP.ConnectionString != reflected.Name) {
  314. string displayName = reflected.DisplayName;
  315. if (!propertyDescriptors.ContainsKey(displayName)) {
  316. attributes = GetAttributesFromCollection(reflected.Attributes);
  317. PropertyDescriptor descriptor = new DbConnectionStringBuilderDescriptor(reflected.Name,
  318. reflected.ComponentType, reflected.PropertyType, reflected.IsReadOnly, attributes);
  319. propertyDescriptors[displayName] = descriptor;
  320. }
  321. // else added by derived class first
  322. }
  323. else if (BrowsableConnectionString) {
  324. propertyDescriptors[ADP.ConnectionString] = reflected;
  325. }
  326. else {
  327. propertyDescriptors.Remove(ADP.ConnectionString);
  328. }
  329. }
  330. // all keywords in Keys list that do not have strongly typed property, ODBC case
  331. // ignore 'Workaround Oracle Bug 914652' via IsFixedSize
  332. if (!IsFixedSize) {
  333. attributes = null;
  334. foreach(string keyword in Keys) {
  335. if (!propertyDescriptors.ContainsKey(keyword)) {
  336. object value = this[keyword];
  337. Type vtype;
  338. if (null != value) {
  339. vtype = value.GetType();
  340. if (typeof(string) == vtype) {
  341. int tmp1;
  342. if (Int32.TryParse((string)value, out tmp1)) {
  343. vtype = typeof(Int32);
  344. }
  345. else {
  346. bool tmp2;
  347. if (Boolean.TryParse((string)value, out tmp2)) {
  348. vtype = typeof(Boolean);
  349. }
  350. }
  351. }
  352. }
  353. else {
  354. vtype = typeof(string);
  355. }
  356. Attribute[] useAttributes = attributes;
  357. if (StringComparer.OrdinalIgnoreCase.Equals(DbConnectionStringKeywords.Password, keyword) ||
  358. StringComparer.OrdinalIgnoreCase.Equals(DbConnectionStringSynonyms.Pwd, keyword)) {
  359. useAttributes = new Attribute[] {
  360. BrowsableAttribute.Yes,
  361. PasswordPropertyTextAttribute.Yes,
  362. new ResCategoryAttribute(Res.DataCategory_Security),
  363. RefreshPropertiesAttribute.All,
  364. };
  365. }
  366. else if (null == attributes) {
  367. attributes = new Attribute[] {
  368. BrowsableAttribute.Yes,
  369. RefreshPropertiesAttribute.All,
  370. };
  371. useAttributes = attributes;
  372. }
  373. PropertyDescriptor descriptor = new DbConnectionStringBuilderDescriptor(keyword,
  374. this.GetType(), vtype, false, useAttributes);
  375. propertyDescriptors[keyword] = descriptor;
  376. }
  377. }
  378. }
  379. }
  380. finally {
  381. Bid.ScopeLeave(ref hscp);
  382. }
  383. }
  384. private PropertyDescriptorCollection GetProperties(Attribute[] attributes) {
  385. PropertyDescriptorCollection propertyDescriptors = GetProperties();
  386. if ((null == attributes) || (0 == attributes.Length)) {
  387. // Basic case has no filtering
  388. return propertyDescriptors;
  389. }
  390. // Create an array that is guaranteed to hold all attributes
  391. PropertyDescriptor[] propertiesArray = new PropertyDescriptor[propertyDescriptors.Count];
  392. // Create an index to reference into this array
  393. int index = 0;
  394. // Iterate over each property
  395. foreach (PropertyDescriptor property in propertyDescriptors) {
  396. // Identify if this property's attributes match the specification
  397. bool match = true;
  398. foreach (Attribute attribute in attributes) {
  399. Attribute attr = property.Attributes[attribute.GetType()];
  400. if ((attr == null && !attribute.IsDefaultAttribute()) || !attr.Match(attribute)) {
  401. match = false;
  402. break;
  403. }
  404. }
  405. // If this property matches, add it to the array
  406. if (match) {
  407. propertiesArray[index] = property;
  408. index++;
  409. }
  410. }
  411. // Create a new array that only contains the filtered properties
  412. PropertyDescriptor[] filteredPropertiesArray = new PropertyDescriptor[index];
  413. Array.Copy(propertiesArray, filteredPropertiesArray, index);
  414. return new PropertyDescriptorCollection(filteredPropertiesArray);
  415. }
  416. string ICustomTypeDescriptor.GetClassName() {
  417. return TypeDescriptor.GetClassName(this, true);
  418. }
  419. string ICustomTypeDescriptor.GetComponentName() {
  420. return TypeDescriptor.GetComponentName(this, true);
  421. }
  422. AttributeCollection ICustomTypeDescriptor.GetAttributes() {
  423. return TypeDescriptor.GetAttributes(this, true);
  424. }
  425. object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
  426. return TypeDescriptor.GetEditor(this, editorBaseType, true);
  427. }
  428. TypeConverter ICustomTypeDescriptor.GetConverter() {
  429. return TypeDescriptor.GetConverter(this, true);
  430. }
  431. PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
  432. return TypeDescriptor.GetDefaultProperty(this, true);
  433. }
  434. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
  435. return GetProperties();
  436. }
  437. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
  438. return GetProperties(attributes);
  439. }
  440. EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
  441. return TypeDescriptor.GetDefaultEvent(this, true);
  442. }
  443. EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
  444. return TypeDescriptor.GetEvents(this, true);
  445. }
  446. EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
  447. return TypeDescriptor.GetEvents(this, attributes, true);
  448. }
  449. object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
  450. return this;
  451. }
  452. }
  453. }