MessageHeaderT.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel
  5. {
  6. using System.Collections.Generic;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Runtime;
  9. using System.ServiceModel.Channels;
  10. using System.Threading;
  11. public class MessageHeader<T>
  12. {
  13. string actor;
  14. bool mustUnderstand;
  15. bool relay;
  16. T content;
  17. public MessageHeader()
  18. {
  19. }
  20. public MessageHeader(T content)
  21. : this(content, false, "", false)
  22. {
  23. }
  24. public MessageHeader(T content, bool mustUnderstand, string actor, bool relay)
  25. {
  26. this.content = content;
  27. this.mustUnderstand = mustUnderstand;
  28. this.actor = actor;
  29. this.relay = relay;
  30. }
  31. public string Actor
  32. {
  33. get { return this.actor; }
  34. set { this.actor = value; }
  35. }
  36. public T Content
  37. {
  38. get { return this.content; }
  39. set { this.content = value; }
  40. }
  41. public bool MustUnderstand
  42. {
  43. get { return this.mustUnderstand; }
  44. set { this.mustUnderstand = value; }
  45. }
  46. public bool Relay
  47. {
  48. get { return this.relay; }
  49. set { this.relay = value; }
  50. }
  51. internal Type GetGenericArgument()
  52. {
  53. return typeof(T);
  54. }
  55. public MessageHeader GetUntypedHeader(string name, string ns)
  56. {
  57. return MessageHeader.CreateHeader(name, ns, this.content, this.mustUnderstand, this.actor, this.relay);
  58. }
  59. }
  60. // problem: creating / getting content / settings content on a MessageHeader<T> given the type at runtime
  61. // require reflection.
  62. // solution: This class creates a cache of adapters that provide an untyped wrapper over a particular
  63. // MessageHeader<T> instantiation.
  64. // better solution: implement something like "IUntypedTypedHeader" that has a "object Content" property,
  65. // privately implement this on TypedHeader, and then just use that iface to operation on the header (actually
  66. // you'd still have the creation problem...). the issue with that is you now have a new public interface
  67. internal abstract class TypedHeaderManager
  68. {
  69. static Dictionary<Type, TypedHeaderManager> cache = new Dictionary<Type, TypedHeaderManager>();
  70. static ReaderWriterLock cacheLock = new ReaderWriterLock();
  71. static Type GenericAdapterType = typeof(GenericAdapter<>);
  72. internal static object Create(Type t, object content, bool mustUnderstand, bool relay, string actor)
  73. {
  74. return GetTypedHeaderManager(t).Create(content, mustUnderstand, relay, actor);
  75. }
  76. internal static object GetContent(Type t, object typedHeaderInstance, out bool mustUnderstand, out bool relay, out string actor)
  77. {
  78. return GetTypedHeaderManager(t).GetContent(typedHeaderInstance, out mustUnderstand, out relay, out actor);
  79. }
  80. internal static Type GetMessageHeaderType(Type contentType)
  81. {
  82. return GetTypedHeaderManager(contentType).GetMessageHeaderType();
  83. }
  84. internal static Type GetHeaderType(Type headerParameterType)
  85. {
  86. if (headerParameterType.IsGenericType && headerParameterType.GetGenericTypeDefinition() == typeof(MessageHeader<>))
  87. return headerParameterType.GetGenericArguments()[0];
  88. return headerParameterType;
  89. }
  90. [SuppressMessage(FxCop.Category.Usage, "CA2301:EmbeddableTypesInContainersRule", MessageId = "cache", Justification = "No need to support type equivalence here.")]
  91. static TypedHeaderManager GetTypedHeaderManager(Type t)
  92. {
  93. TypedHeaderManager result = null;
  94. bool lockHeld = false;
  95. try
  96. {
  97. try { }
  98. finally
  99. {
  100. cacheLock.AcquireReaderLock(int.MaxValue);
  101. lockHeld = true;
  102. }
  103. if (!cache.TryGetValue(t, out result))
  104. {
  105. cacheLock.UpgradeToWriterLock(int.MaxValue);
  106. if (!cache.TryGetValue(t, out result))
  107. {
  108. result = (TypedHeaderManager)Activator.CreateInstance(GenericAdapterType.MakeGenericType(t));
  109. cache.Add(t, result);
  110. }
  111. }
  112. }
  113. finally
  114. {
  115. if (lockHeld)
  116. {
  117. cacheLock.ReleaseLock();
  118. }
  119. }
  120. return result;
  121. }
  122. protected abstract object Create(object content, bool mustUnderstand, bool relay, string actor);
  123. protected abstract object GetContent(object typedHeaderInstance, out bool mustUnderstand, out bool relay, out string actor);
  124. protected abstract Type GetMessageHeaderType();
  125. class GenericAdapter<T> : TypedHeaderManager
  126. {
  127. protected override object Create(object content, bool mustUnderstand, bool relay, string actor)
  128. {
  129. MessageHeader<T> header = new MessageHeader<T>();
  130. header.Content = (T)content;
  131. header.MustUnderstand = mustUnderstand;
  132. header.Relay = relay;
  133. header.Actor = actor;
  134. return header;
  135. }
  136. protected override object GetContent(object typedHeaderInstance, out bool mustUnderstand, out bool relay, out string actor)
  137. {
  138. mustUnderstand = false;
  139. relay = false;
  140. actor = null;
  141. if (typedHeaderInstance == null)
  142. return null;
  143. MessageHeader<T> header = typedHeaderInstance as MessageHeader<T>;
  144. if (header == null)
  145. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException("typedHeaderInstance"));
  146. mustUnderstand = header.MustUnderstand;
  147. relay = header.Relay;
  148. actor = header.Actor;
  149. return header.Content;
  150. }
  151. protected override Type GetMessageHeaderType()
  152. {
  153. return typeof(MessageHeader<T>);
  154. }
  155. }
  156. }
  157. }