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