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