1 using System;
2 using System.Globalization;
3 using System.Runtime.InteropServices;
4 using System.Runtime.Remoting.Activation;
5 using System.Runtime.Remoting.Contexts;
6 using System.Runtime.Remoting.Messaging;
7 using System.Runtime.Serialization;
8 using System.Security.Permissions;
9 using System.ServiceModel;
10 using System.Transactions;
11 using Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF;
12
13 namespace StyduAttribute
14 {
15 public interface ITestAspect
16 {
17 void AddMessageSink(IMessageSink messageSink);
18 }
19
20 [AttributeUsage(AttributeTargets.Method)]
21 public sealed class ExpectedExceptionMessageAttribute : Attribute
22 {
23 private string _exceptionMessage;
24 private Type _exceptionType;
25
26 public ExpectedExceptionMessageAttribute(Type exceptionType, string exceptionMessage)
27 {
28 this._exceptionType = exceptionType;
29 this._exceptionMessage = exceptionMessage;
30 }
31
32 public string ExceptionMessage
33 {
34 get { return this._exceptionMessage; }
35 }
36
37 public Type ExceptionType
38 {
39 get { return this._exceptionType; }
40 }
41 }
42
43 public class ExpectedExceptionMessageAspect : TestAspect<ExpectedExceptionMessageAttribute>, IMessageSink, ITestAspect
44 {
45 private IMessageSink _nextSink;
46
47 public void AddMessageSink(IMessageSink messageSink)
48 {
49 this._nextSink = messageSink;
50 }
51
52 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
53 public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
54 {
55 throw new InvalidOperationException();
56 }
57
58 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
59 public IMessage SyncProcessMessage(IMessage msg)
60 {
61 if (msg == null)
62 {
63 throw new ArgumentNullException("msg");
64 }
65 ExpectedExceptionMessageAttribute attribute = base.GetAttribute(msg);
66 if (attribute != null)
67 {
68 IMessage message = this._nextSink.SyncProcessMessage(msg);
69
70 string expectedAssemblyQualifiedName = attribute.ExceptionType.AssemblyQualifiedName;
71
72 ReturnMessage returnMessage = message as ReturnMessage;
73
74 if (returnMessage == null)
75 {
76 throw new TestException(string.Format(CultureInfo.CurrentCulture, "The type of expected exception ('{0}') was not thrown.", new object[] { expectedAssemblyQualifiedName }));
77 }
78 string assemblyQualifiedName = returnMessage.Exception.GetType().AssemblyQualifiedName;
79
80 if (assemblyQualifiedName != expectedAssemblyQualifiedName)
81 {
82 throw new TestException(string.Format(CultureInfo.CurrentCulture, "The type of exception thrown ('{0}') did not match the type expected ('{1}').", new object[] { assemblyQualifiedName, expectedAssemblyQualifiedName }));
83 }
84 if (assemblyQualifiedName.Contains("Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.ValidationFault"))
85 {
86 var faults = returnMessage.Exception as FaultException<ValidationFault>;
87
88 string validationMessage = string.Empty;
89
90 foreach (ValidationDetail item in faults.Detail.Details)
91 {
92 validationMessage += item.Message;
93 }
94 if (!validationMessage.Contains(attribute.ExceptionMessage))
95 {
96 throw new TestException(string.Format(CultureInfo.CurrentCulture, "The exception message thrown ('{0}') did not match the message expected ('{1}').", new object[] { validationMessage, attribute.ExceptionMessage }));
97 }
98
99 }
100 else if (!returnMessage.Exception.Message.Contains(attribute.ExceptionMessage))
101 {
102 throw new TestException(string.Format(CultureInfo.CurrentCulture, "The exception message thrown ('{0}') did not match the message expected ('{1}').", new object[] { returnMessage.Exception.Message, attribute.ExceptionMessage }));
103 }
104 return base.FakeTargetResponse(msg);
105 }
106 return this._nextSink.SyncProcessMessage(msg);
107 }
108
109 public IMessageSink NextSink
110 {
111 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
112 get { return this._nextSink; }
113 }
114 }
115
116 [Serializable]
117 public class TestException : Exception
118 {
119 private const string _defaultExceptionMessage = "There has been an exception but no information was provided. Please view the stack trace for more information.";
120
121 public TestException()
122 : this("There has been an exception but no information was provided. Please view the stack trace for more information.")
123 {
124 }
125
126 public TestException(string message)
127 : base(message)
128 {
129 }
130
131 protected TestException(SerializationInfo info, StreamingContext context)
132 : base(info, context)
133 {
134 }
135
136 public TestException(string message, Exception innerException)
137 : base(message, innerException)
138 {
139
140 }
141 }
142
143 [AttributeUsage(AttributeTargets.Class)]
144 public sealed class TestAttribute : ContextAttribute
145 {
146 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
147 public TestAttribute()
148 : base("HiiPTest")
149 {
150 }
151
152 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
153 public override void GetPropertiesForNewContext(IConstructionCallMessage msg)
154 {
155 if (msg == null)
156 {
157 throw new ArgumentNullException("msg");
158 }
159 msg.ContextProperties.Add(new TestProperty<RollBackAspect>());
160 msg.ContextProperties.Add(new TestProperty<ExpectedExceptionMessageAspect>());
161 }
162 }
163
164 public abstract class TestAspect<TAttribute> where TAttribute : Attribute
165 {
166 protected TestAspect()
167 {
168 }
169
170 protected IMessage FakeTargetResponse(IMessage message)
171 {
172 return new MethodResponse(new Header[0], new MethodCall(message));
173 }
174
175 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
176 protected TAttribute GetAttribute(IMessage message)
177 {
178
179 string typeName = (string)message.Properties["__TypeName"];
180 string name = (string)message.Properties["__MethodName"];
181 object[] customAttributes = Type.GetType(typeName).GetMethod(name).GetCustomAttributes(typeof(TAttribute), true);
182 TAttribute local = default(TAttribute);
183 if (customAttributes.Length > 0)
184 {
185 local = customAttributes[0] as TAttribute;
186 }
187 return local;
188 }
189
190 [StructLayout(LayoutKind.Sequential, Size = 1)]
191 private struct MessageKeys
192 {
193 public const string TypeName = "__TypeName";
194 public const string MethodName = "__MethodName";
195 }
196
197 public void My() { }
198 }
199
200 public class TestProperty<T> : IContextProperty, IContributeObjectSink where T : IMessageSink, ITestAspect, new()
201 {
202 private readonly string _name;
203
204 public TestProperty()
205 {
206 this._name = typeof(T).AssemblyQualifiedName;
207 }
208
209 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
210 public void Freeze(Context newContext)
211 {
212 }
213
214 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
215 public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
216 {
217 T local = (default(T) == null) ? Activator.CreateInstance<T>() : default(T);
218 local.AddMessageSink(nextSink);
219 return local;
220 }
221
222 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
223 public bool IsNewContextOK(Context newCtx)
224 {
225 return true;
226 }
227
228 public string Name
229 {
230 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
231 get { return this._name; }
232 }
233 }
234
235 [AttributeUsage(AttributeTargets.Method)]
236 public sealed class RollBackAttribute : Attribute
237 {
238 private readonly bool _commit;
239 private readonly TransactionOptions _transactionOptions;
240 private readonly TransactionScopeOption _transactionScopeOption;
241
242 public RollBackAttribute()
243 : this(false, TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, Timeout = new TimeSpan(0, 5, 0) })
244 {
245 }
246
247 public RollBackAttribute(bool commit)
248 : this(commit, TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, Timeout = new TimeSpan(0, 5, 0) })
249 {
250 }
251
252 public RollBackAttribute(bool commit, TransactionScopeOption transactionScopeOption, TransactionOptions transactionOptions)
253 {
254 this._commit = commit;
255 this._transactionScopeOption = transactionScopeOption;
256 this._transactionOptions = transactionOptions;
257 }
258
259 public bool Commit
260 {
261 get { return this._commit; }
262 }
263
264 public TransactionOptions TransactionOptions
265 {
266 get { return this._transactionOptions; }
267 }
268
269 public TransactionScopeOption TransactionScopeOption
270 {
271 get { return this._transactionScopeOption; }
272 }
273 }
274
275 public class RollBackAspect : TestAspect<RollBackAttribute>, IMessageSink, ITestAspect
276 {
277 private IMessageSink _nextSink;
278
279 public void AddMessageSink(IMessageSink messageSink)
280 {
281 this._nextSink = messageSink;
282 }
283
284 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
285 public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
286 {
287 throw new InvalidOperationException();
288 }
289
290 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
291 public IMessage SyncProcessMessage(IMessage msg)
292 {
293 if (msg == null)
294 {
295 throw new ArgumentNullException("msg");
296 }
297 RollBackAttribute attribute = base.GetAttribute(msg);
298 if (attribute != null)
299 {
300 using (TransactionScope scope = new TransactionScope(attribute.TransactionScopeOption, attribute.TransactionOptions))
301 {
302 IMessage message = this._nextSink.SyncProcessMessage(msg);
303 if (attribute.Commit)
304 {
305 Console.WriteLine("Commiting Transaction in Test Method.");
306 scope.Complete();
307 }
308 return message;
309 }
310 }
311 return this._nextSink.SyncProcessMessage(msg);
312 }
313
314 public IMessageSink NextSink
315 {
316 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
317 get { return this._nextSink; }
318 }
319 }
320
321 [Test]
322 public class TestFixture : ContextBoundObject
323 {
324 }
325 }