/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/MessageProperties.cs

https://github.com/pruiz/mono · C# · 891 lines · 756 code · 120 blank · 15 comment · 217 complexity · a4f56f2198ca39c32746cd943f4e87cf MD5 · raw file

  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Runtime;
  9. using System.ServiceModel.Security;
  10. public sealed class MessageProperties : IDictionary<string, object>, IDisposable
  11. {
  12. Property[] properties;
  13. int propertyCount;
  14. MessageEncoder encoder;
  15. Uri via;
  16. object allowOutputBatching;
  17. SecurityMessageProperty security;
  18. bool disposed;
  19. const int InitialPropertyCount = 2;
  20. const int MaxRecycledArrayLength = 8;
  21. const string ViaKey = "Via";
  22. const string AllowOutputBatchingKey = "AllowOutputBatching";
  23. const string SecurityKey = "Security";
  24. const string EncoderKey = "Encoder";
  25. const int NotFoundIndex = -1;
  26. const int ViaIndex = -2;
  27. const int AllowOutputBatchingIndex = -3;
  28. const int SecurityIndex = -4;
  29. const int EncoderIndex = -5;
  30. static object trueBool = true;
  31. static object falseBool = false;
  32. public MessageProperties()
  33. {
  34. }
  35. public MessageProperties(MessageProperties properties)
  36. {
  37. CopyProperties(properties);
  38. }
  39. internal MessageProperties(KeyValuePair<string, object>[] array)
  40. {
  41. if (array == null)
  42. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array"));
  43. CopyProperties(array);
  44. }
  45. void ThrowDisposed()
  46. {
  47. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(string.Empty, SR.GetString(SR.ObjectDisposed, this.GetType().ToString())));
  48. }
  49. public object this[string name]
  50. {
  51. get
  52. {
  53. if (disposed)
  54. ThrowDisposed();
  55. object value;
  56. if (!TryGetValue(name, out value))
  57. {
  58. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertyNotFound, name)));
  59. }
  60. return value;
  61. }
  62. set
  63. {
  64. if (disposed)
  65. ThrowDisposed();
  66. UpdateProperty(name, value, false);
  67. }
  68. }
  69. internal bool CanRecycle
  70. {
  71. get
  72. {
  73. return properties == null || properties.Length <= MaxRecycledArrayLength;
  74. }
  75. }
  76. public int Count
  77. {
  78. get
  79. {
  80. if (disposed)
  81. ThrowDisposed();
  82. return propertyCount;
  83. }
  84. }
  85. public MessageEncoder Encoder
  86. {
  87. get
  88. {
  89. if (disposed)
  90. ThrowDisposed();
  91. return encoder;
  92. }
  93. set
  94. {
  95. if (disposed)
  96. ThrowDisposed();
  97. AdjustPropertyCount((object)encoder == null, (object)value == null);
  98. encoder = value;
  99. }
  100. }
  101. public bool AllowOutputBatching
  102. {
  103. get
  104. {
  105. if (disposed)
  106. ThrowDisposed();
  107. return (object)allowOutputBatching == trueBool;
  108. }
  109. set
  110. {
  111. if (disposed)
  112. ThrowDisposed();
  113. AdjustPropertyCount((object)allowOutputBatching == null, false);
  114. if (value)
  115. {
  116. allowOutputBatching = trueBool;
  117. }
  118. else
  119. {
  120. allowOutputBatching = falseBool;
  121. }
  122. }
  123. }
  124. public bool IsFixedSize
  125. {
  126. get
  127. {
  128. if (disposed)
  129. ThrowDisposed();
  130. return false;
  131. }
  132. }
  133. public bool IsReadOnly
  134. {
  135. get
  136. {
  137. if (disposed)
  138. ThrowDisposed();
  139. return false;
  140. }
  141. }
  142. public ICollection<string> Keys
  143. {
  144. get
  145. {
  146. if (disposed)
  147. ThrowDisposed();
  148. List<string> keys = new List<string>();
  149. if ((object)via != null)
  150. {
  151. keys.Add(ViaKey);
  152. }
  153. if ((object)allowOutputBatching != null)
  154. {
  155. keys.Add(AllowOutputBatchingKey);
  156. }
  157. if ((object)security != null)
  158. {
  159. keys.Add(SecurityKey);
  160. }
  161. if ((object)encoder != null)
  162. {
  163. keys.Add(EncoderKey);
  164. }
  165. if (properties != null)
  166. {
  167. for (int i = 0; i < properties.Length; i++)
  168. {
  169. string propertyName = properties[i].Name;
  170. if (propertyName == null)
  171. {
  172. break;
  173. }
  174. keys.Add(propertyName);
  175. }
  176. }
  177. return keys;
  178. }
  179. }
  180. public SecurityMessageProperty Security
  181. {
  182. get
  183. {
  184. if (disposed)
  185. ThrowDisposed();
  186. return security;
  187. }
  188. set
  189. {
  190. if (disposed)
  191. ThrowDisposed();
  192. AdjustPropertyCount((object)security == null, (object)value == null);
  193. security = value;
  194. }
  195. }
  196. public ICollection<object> Values
  197. {
  198. get
  199. {
  200. if (disposed)
  201. ThrowDisposed();
  202. List<object> values = new List<object>();
  203. if ((object)via != null)
  204. {
  205. values.Add(via);
  206. }
  207. if ((object)allowOutputBatching != null)
  208. {
  209. values.Add(allowOutputBatching);
  210. }
  211. if ((object)security != null)
  212. {
  213. values.Add(security);
  214. }
  215. if ((object)encoder != null)
  216. {
  217. values.Add(encoder);
  218. }
  219. if (properties != null)
  220. {
  221. for (int i = 0; i < properties.Length; i++)
  222. {
  223. if (properties[i].Name == null)
  224. {
  225. break;
  226. }
  227. values.Add(properties[i].Value);
  228. }
  229. }
  230. return values;
  231. }
  232. }
  233. public Uri Via
  234. {
  235. get
  236. {
  237. if (disposed)
  238. ThrowDisposed();
  239. return via;
  240. }
  241. set
  242. {
  243. if (disposed)
  244. ThrowDisposed();
  245. AdjustPropertyCount((object)via == null, (object)value == null);
  246. via = value;
  247. }
  248. }
  249. public void Add(string name, object property)
  250. {
  251. if (disposed)
  252. ThrowDisposed();
  253. if (property == null)
  254. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("property"));
  255. UpdateProperty(name, property, true);
  256. }
  257. void AdjustPropertyCount(bool oldValueIsNull, bool newValueIsNull)
  258. {
  259. if (newValueIsNull)
  260. {
  261. if (!oldValueIsNull)
  262. {
  263. propertyCount--;
  264. }
  265. }
  266. else
  267. {
  268. if (oldValueIsNull)
  269. {
  270. propertyCount++;
  271. }
  272. }
  273. }
  274. public void Clear()
  275. {
  276. if (disposed)
  277. ThrowDisposed();
  278. if (properties != null)
  279. {
  280. for (int i = 0; i < properties.Length; i++)
  281. {
  282. if (properties[i].Name == null)
  283. {
  284. break;
  285. }
  286. properties[i] = new Property();
  287. }
  288. }
  289. via = null;
  290. allowOutputBatching = null;
  291. security = null;
  292. encoder = null;
  293. propertyCount = 0;
  294. }
  295. public void CopyProperties(MessageProperties properties)
  296. {
  297. // CopyProperties behavior should be equivalent to the behavior
  298. // of MergeProperties except that Merge supports property values that
  299. // implement the IMergeEnabledMessageProperty. Any changes to CopyProperties
  300. // should be reflected in MergeProperties as well.
  301. if (properties == null)
  302. {
  303. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
  304. }
  305. if (disposed)
  306. {
  307. ThrowDisposed();
  308. }
  309. if (properties.properties != null)
  310. {
  311. for (int i = 0; i < properties.properties.Length; i++)
  312. {
  313. if (properties.properties[i].Name == null)
  314. {
  315. break;
  316. }
  317. Property property = properties.properties[i];
  318. // this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
  319. this[property.Name] = property.Value;
  320. }
  321. }
  322. this.Via = properties.Via;
  323. this.AllowOutputBatching = properties.AllowOutputBatching;
  324. this.Security = (properties.Security != null) ? (SecurityMessageProperty)properties.Security.CreateCopy() : null;
  325. this.Encoder = properties.Encoder;
  326. }
  327. internal void MergeProperties(MessageProperties properties)
  328. {
  329. // MergeProperties behavior should be equivalent to the behavior
  330. // of CopyProperties except that Merge supports property values that
  331. // implement the IMergeEnabledMessageProperty. Any changes to CopyProperties
  332. // should be reflected in MergeProperties as well.
  333. if (properties == null)
  334. {
  335. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
  336. }
  337. if (disposed)
  338. {
  339. ThrowDisposed();
  340. }
  341. if (properties.properties != null)
  342. {
  343. for (int i = 0; i < properties.properties.Length; i++)
  344. {
  345. if (properties.properties[i].Name == null)
  346. {
  347. break;
  348. }
  349. Property property = properties.properties[i];
  350. IMergeEnabledMessageProperty currentValue;
  351. if (!this.TryGetValue<IMergeEnabledMessageProperty>(property.Name, out currentValue) ||
  352. !currentValue.TryMergeWithProperty(property.Value))
  353. {
  354. // Merge wasn't possible so copy
  355. // this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
  356. this[property.Name] = property.Value;
  357. }
  358. }
  359. }
  360. this.Via = properties.Via;
  361. this.AllowOutputBatching = properties.AllowOutputBatching;
  362. this.Security = (properties.Security != null) ? (SecurityMessageProperty)properties.Security.CreateCopy() : null;
  363. this.Encoder = properties.Encoder;
  364. }
  365. internal void CopyProperties(KeyValuePair<string, object>[] array)
  366. {
  367. if (disposed)
  368. {
  369. ThrowDisposed();
  370. }
  371. for (int i = 0; i < array.Length; i++)
  372. {
  373. KeyValuePair<string, object> property = array[i];
  374. // this[string] will call CreateCopyOfPropertyValue, so we don't need to repeat that here
  375. this[property.Key] = property.Value;
  376. }
  377. }
  378. public bool ContainsKey(string name)
  379. {
  380. if (disposed)
  381. ThrowDisposed();
  382. if (name == null)
  383. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
  384. int index = FindProperty(name);
  385. switch (index)
  386. {
  387. case ViaIndex:
  388. return (object)via != null;
  389. case AllowOutputBatchingIndex:
  390. return (object)allowOutputBatching != null;
  391. case SecurityIndex:
  392. return (object)security != null;
  393. case EncoderIndex:
  394. return (object)encoder != null;
  395. case NotFoundIndex:
  396. return false;
  397. default:
  398. return true;
  399. }
  400. }
  401. object CreateCopyOfPropertyValue(object propertyValue)
  402. {
  403. IMessageProperty messageProperty = propertyValue as IMessageProperty;
  404. if (messageProperty == null)
  405. return propertyValue;
  406. object copy = messageProperty.CreateCopy();
  407. if (copy == null)
  408. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertyReturnedNullCopy)));
  409. return copy;
  410. }
  411. public void Dispose()
  412. {
  413. if (disposed)
  414. return;
  415. disposed = true;
  416. if (properties != null)
  417. {
  418. for (int i = 0; i < properties.Length; i++)
  419. {
  420. if (properties[i].Name == null)
  421. {
  422. break;
  423. }
  424. properties[i].Dispose();
  425. }
  426. }
  427. if (this.security != null)
  428. {
  429. this.security.Dispose();
  430. }
  431. }
  432. int FindProperty(string name)
  433. {
  434. if (name == ViaKey)
  435. return ViaIndex;
  436. else if (name == AllowOutputBatchingKey)
  437. return AllowOutputBatchingIndex;
  438. else if (name == EncoderKey)
  439. return EncoderIndex;
  440. else if (name == SecurityKey)
  441. return SecurityIndex;
  442. if (properties != null)
  443. {
  444. for (int i = 0; i < properties.Length; i++)
  445. {
  446. string propertyName = properties[i].Name;
  447. if (propertyName == null)
  448. {
  449. break;
  450. }
  451. if (propertyName == name)
  452. {
  453. return i;
  454. }
  455. }
  456. }
  457. return NotFoundIndex;
  458. }
  459. internal void Recycle()
  460. {
  461. disposed = false;
  462. Clear();
  463. }
  464. public bool Remove(string name)
  465. {
  466. if (disposed)
  467. ThrowDisposed();
  468. int originalPropertyCount = propertyCount;
  469. UpdateProperty(name, null, false);
  470. return originalPropertyCount != propertyCount;
  471. }
  472. public bool TryGetValue(string name, out object value)
  473. {
  474. if (disposed)
  475. ThrowDisposed();
  476. if (name == null)
  477. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
  478. int index = FindProperty(name);
  479. switch (index)
  480. {
  481. case ViaIndex:
  482. value = via;
  483. break;
  484. case AllowOutputBatchingIndex:
  485. value = allowOutputBatching;
  486. break;
  487. case SecurityIndex:
  488. value = security;
  489. break;
  490. case EncoderIndex:
  491. value = encoder;
  492. break;
  493. case NotFoundIndex:
  494. value = null;
  495. break;
  496. default:
  497. value = properties[index].Value;
  498. break;
  499. }
  500. return value != null;
  501. }
  502. internal bool TryGetValue<TProperty>(string name, out TProperty property)
  503. {
  504. object o;
  505. if (this.TryGetValue(name, out o))
  506. {
  507. property = (TProperty)o;
  508. return true;
  509. }
  510. else
  511. {
  512. property = default(TProperty);
  513. return false;
  514. }
  515. }
  516. internal TProperty GetValue<TProperty>(string name) where TProperty : class
  517. {
  518. return this.GetValue<TProperty>(name, false);
  519. }
  520. internal TProperty GetValue<TProperty>(string name, bool ensureTypeMatch) where TProperty : class
  521. {
  522. object obj;
  523. if (!this.TryGetValue(name, out obj))
  524. {
  525. return null;
  526. }
  527. return ensureTypeMatch ? (TProperty)obj : obj as TProperty;
  528. }
  529. void UpdateProperty(string name, object value, bool mustNotExist)
  530. {
  531. if (name == null)
  532. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
  533. int index = FindProperty(name);
  534. if (index != NotFoundIndex)
  535. {
  536. if (mustNotExist)
  537. {
  538. bool exists;
  539. switch (index)
  540. {
  541. case ViaIndex:
  542. exists = (object)via != null;
  543. break;
  544. case AllowOutputBatchingIndex:
  545. exists = (object)allowOutputBatching != null;
  546. break;
  547. case SecurityIndex:
  548. exists = (object)security != null;
  549. break;
  550. case EncoderIndex:
  551. exists = (object)encoder != null;
  552. break;
  553. default:
  554. exists = true;
  555. break;
  556. }
  557. if (exists)
  558. {
  559. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.DuplicateMessageProperty, name)));
  560. }
  561. }
  562. if (index >= 0)
  563. {
  564. if (value == null)
  565. {
  566. properties[index].Dispose();
  567. int shiftIndex;
  568. for (shiftIndex = index + 1; shiftIndex < properties.Length; shiftIndex++)
  569. {
  570. if (properties[shiftIndex].Name == null)
  571. {
  572. break;
  573. }
  574. properties[shiftIndex - 1] = properties[shiftIndex];
  575. }
  576. properties[shiftIndex - 1] = new Property();
  577. propertyCount--;
  578. }
  579. else
  580. {
  581. properties[index].Value = CreateCopyOfPropertyValue(value);
  582. }
  583. }
  584. else
  585. {
  586. switch (index)
  587. {
  588. case ViaIndex:
  589. Via = (Uri)value;
  590. break;
  591. case AllowOutputBatchingIndex:
  592. AllowOutputBatching = (bool)value;
  593. break;
  594. case SecurityIndex:
  595. if (Security != null)
  596. Security.Dispose();
  597. Security = (SecurityMessageProperty)CreateCopyOfPropertyValue(value);
  598. break;
  599. case EncoderIndex:
  600. Encoder = (MessageEncoder)value;
  601. break;
  602. default:
  603. Fx.Assert("");
  604. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
  605. }
  606. }
  607. }
  608. else if (value != null)
  609. {
  610. int newIndex;
  611. if (properties == null)
  612. {
  613. properties = new Property[InitialPropertyCount];
  614. newIndex = 0;
  615. }
  616. else
  617. {
  618. for (newIndex = 0; newIndex < properties.Length; newIndex++)
  619. {
  620. if (properties[newIndex].Name == null)
  621. {
  622. break;
  623. }
  624. }
  625. if (newIndex == properties.Length)
  626. {
  627. Property[] newProperties = new Property[properties.Length * 2];
  628. Array.Copy(properties, newProperties, properties.Length);
  629. properties = newProperties;
  630. }
  631. }
  632. object newValue = CreateCopyOfPropertyValue(value);
  633. properties[newIndex] = new Property(name, newValue);
  634. propertyCount++;
  635. }
  636. }
  637. void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int index)
  638. {
  639. if (disposed)
  640. ThrowDisposed();
  641. if (array == null)
  642. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array"));
  643. if (array.Length < propertyCount)
  644. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessagePropertiesArraySize0)));
  645. if (index < 0 || index > array.Length - propertyCount)
  646. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index", index,
  647. SR.GetString(SR.ValueMustBeInRange, 0, array.Length - propertyCount)));
  648. if (this.via != null)
  649. array[index++] = new KeyValuePair<string, object>(ViaKey, via);
  650. if (this.allowOutputBatching != null)
  651. array[index++] = new KeyValuePair<string, object>(AllowOutputBatchingKey, allowOutputBatching);
  652. if (this.security != null)
  653. array[index++] = new KeyValuePair<string, object>(SecurityKey, this.security.CreateCopy());
  654. if (this.encoder != null)
  655. array[index++] = new KeyValuePair<string, object>(EncoderKey, encoder);
  656. if (properties != null)
  657. {
  658. for (int i = 0; i < properties.Length; i++)
  659. {
  660. string propertyName = properties[i].Name;
  661. if (propertyName == null)
  662. {
  663. break;
  664. }
  665. array[index++] = new KeyValuePair<string, object>(propertyName, CreateCopyOfPropertyValue(properties[i].Value));
  666. }
  667. }
  668. }
  669. void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> pair)
  670. {
  671. if (disposed)
  672. ThrowDisposed();
  673. if (pair.Value == null)
  674. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
  675. UpdateProperty(pair.Key, pair.Value, true);
  676. }
  677. bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> pair)
  678. {
  679. if (disposed)
  680. ThrowDisposed();
  681. if (pair.Value == null)
  682. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
  683. if (pair.Key == null)
  684. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Key"));
  685. object value;
  686. if (!TryGetValue(pair.Key, out value))
  687. {
  688. return false;
  689. }
  690. return value.Equals(pair.Value);
  691. }
  692. IEnumerator IEnumerable.GetEnumerator()
  693. {
  694. if (disposed)
  695. ThrowDisposed();
  696. return ((IEnumerable<KeyValuePair<string, object>>)this).GetEnumerator();
  697. }
  698. IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
  699. {
  700. if (disposed)
  701. ThrowDisposed();
  702. List<KeyValuePair<string, object>> pairs = new List<KeyValuePair<string, object>>(propertyCount);
  703. if (this.via != null)
  704. pairs.Add(new KeyValuePair<string, object>(ViaKey, via));
  705. if (this.allowOutputBatching != null)
  706. pairs.Add(new KeyValuePair<string, object>(AllowOutputBatchingKey, allowOutputBatching));
  707. if (this.security != null)
  708. pairs.Add(new KeyValuePair<string, object>(SecurityKey, security));
  709. if (this.encoder != null)
  710. pairs.Add(new KeyValuePair<string, object>(EncoderKey, encoder));
  711. if (properties != null)
  712. {
  713. for (int i = 0; i < properties.Length; i++)
  714. {
  715. string propertyName = properties[i].Name;
  716. if (propertyName == null)
  717. {
  718. break;
  719. }
  720. pairs.Add(new KeyValuePair<string, object>(propertyName, properties[i].Value));
  721. }
  722. }
  723. return pairs.GetEnumerator();
  724. }
  725. bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> pair)
  726. {
  727. if (disposed)
  728. ThrowDisposed();
  729. if (pair.Value == null)
  730. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Value"));
  731. if (pair.Key == null)
  732. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pair.Key"));
  733. object value;
  734. if (!TryGetValue(pair.Key, out value))
  735. {
  736. return false;
  737. }
  738. if (!value.Equals(pair.Value))
  739. {
  740. return false;
  741. }
  742. Remove(pair.Key);
  743. return true;
  744. }
  745. struct Property : IDisposable
  746. {
  747. string name;
  748. object value;
  749. public Property(string name, object value)
  750. {
  751. this.name = name;
  752. this.value = value;
  753. }
  754. public string Name
  755. {
  756. get { return name; }
  757. }
  758. public object Value
  759. {
  760. get { return value; }
  761. set { this.value = value; }
  762. }
  763. public void Dispose()
  764. {
  765. IDisposable disposable = value as IDisposable;
  766. if (disposable != null)
  767. disposable.Dispose();
  768. }
  769. }
  770. }
  771. }