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