1 //
2 // CallbackBehaviorAttributeTest.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2009 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 #if !MOBILE && !XAMMAC_4_5
29 using System;
30 using System.Collections.ObjectModel;
31 using System.IO;
32 using System.Linq;
33 using System.Net.Sockets;
34 using System.Reflection;
35 using System.ServiceModel;
36 using System.ServiceModel.Channels;
37 using System.ServiceModel.Description;
38 using System.ServiceModel.Dispatcher;
39 using System.Transactions;
40 using System.Threading;
41 using NUnit.Framework;
42 
43 using MonoTests.Helpers;
44 
45 namespace MonoTests.System.ServiceModel
46 {
47 	[TestFixture]
48 	public class CallbackBehaviorAttributeTest
49 	{
50 		[Test]
DefaultValues()51 		public void DefaultValues ()
52 		{
53 			var c = new CallbackBehaviorAttribute ();
54 			Assert.IsTrue (c.AutomaticSessionShutdown, "#1");
55 			Assert.AreEqual (ConcurrencyMode.Single, c.ConcurrencyMode, "#2");
56 			Assert.IsFalse (c.IgnoreExtensionDataObject, "#3");
57 			Assert.IsFalse (c.IncludeExceptionDetailInFaults, "#4");
58 			Assert.AreEqual (0x10000, c.MaxItemsInObjectGraph, "#5");
59 			Assert.AreEqual (IsolationLevel.Unspecified, c.TransactionIsolationLevel, "#6");
60 			Assert.IsNull (c.TransactionTimeout, "#7");
61 			Assert.IsTrue (c.UseSynchronizationContext, "#8");
62 			Assert.IsTrue (c.ValidateMustUnderstand, "#9");
63 		}
64 
65 		[Test]
AddBindingParameters()66 		public void AddBindingParameters ()
67 		{
68 			IEndpointBehavior eb = new CallbackBehaviorAttribute ();
69 			var cd = ContractDescription.GetContract (typeof (IFoo));
70 			var se = new ServiceEndpoint (cd);
71 			Assert.AreEqual (0, se.Behaviors.Count, "#1");
72 			var pc = new BindingParameterCollection ();
73 			eb.AddBindingParameters (se, pc);
74 			Assert.AreEqual (0, pc.Count, "#2");
75 			Assert.AreEqual (0, se.Behaviors.Count, "#3");
76 		}
77 
78 		[Test]
79 		[ExpectedException (typeof (InvalidOperationException))]
ApplyDispatchBehavior()80 		public void ApplyDispatchBehavior ()
81 		{
82 			// It cannot be applied to service endpoint dispatcher.
83 			IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
84 			var cd = ContractDescription.GetContract (typeof (IFoo));
85 			var se = new ServiceEndpoint (cd);
86 			var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IFoo", "urn:foo");
87 			eb.ApplyDispatchBehavior (se, ed);
88 		}
89 
90 		[Test]
91 		[ExpectedException (typeof (InvalidOperationException))]
ApplyClientBehaviorNonDuplex()92 		public void ApplyClientBehaviorNonDuplex ()
93 		{
94 			// It must be applied to duplex callback runtime
95 			IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
96 			var cd = ContractDescription.GetContract (typeof (IFoo));
97 			var se = new ServiceEndpoint (cd);
98 			var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IFoo", "urn:foo");
99 			var cr = ed.DispatchRuntime.CallbackClientRuntime;
100 			eb.ApplyClientBehavior (se, cr);
101 		}
102 
103 		/* There is no way that I can create ClientRuntime instance ...
104 		[Test]
105 		public void ApplyClientBehavior ()
106 		{
107 			IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
108 			var cd = ContractDescription.GetContract (typeof (IDuplexFoo));
109 			var se = new ServiceEndpoint (cd);
110 			var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IDuplexFoo", "urn:foo");
111 			var cr = ed.DispatchRuntime.CallbackClientRuntime;
112 			eb.ApplyClientBehavior (se, cr);
113 			Assert.IsFalse (cr.ValidateMustUnderstand, "#2.1");
114 			//Assert.IsFalse (cr.CallbackDispatchRuntime.ValidateMustUnderstand, "#2.2");
115 			Assert.AreEqual (1, se.Behaviors.Count, "#3");
116 		}
117 		*/
118 
119 		[ServiceContract]
120 		public interface IFoo
121 		{
122 			[OperationContract]
Join(string s1, string s2)123 			string Join (string s1, string s2);
124 		}
125 
126 		[ServiceContract (CallbackContract = typeof (IFoo))]
127 		public interface IDuplexFoo
128 		{
129 			[OperationContract]
Block(string s)130 			void Block (string s);
131 		}
132 
133 		#region "bug #567672"
134 		[Test]
135 		[Category ("NotWorking")]
CallbackExample1()136 		public void CallbackExample1 ()
137 		{
138 			//Start service and use net.tcp binding
139 			ServiceHost eventServiceHost = new ServiceHost (typeof (GreetingsService));
140 			NetTcpBinding tcpBindingpublish = new NetTcpBinding ();
141 			tcpBindingpublish.Security.Mode = SecurityMode.None;
142 			eventServiceHost.AddServiceEndpoint (typeof (IGreetings), tcpBindingpublish, "net.tcp://localhost:8000/GreetingsService");
143 			var cd = eventServiceHost.Description.Endpoints [0].Contract;
144 			Assert.AreEqual (2, cd.Operations.Count, "Operations.Count");
145 			var send = cd.Operations.FirstOrDefault (od => od.Name == "SendMessage");
146 			var show = cd.Operations.FirstOrDefault (od => od.Name == "ShowMessage");
147 			Assert.IsNotNull (send, "OD:SendMessage");
148 			Assert.IsNotNull (show, "OD:ShowMessage");
149 			foreach (var md in send.Messages) {
150 				if (md.Direction == MessageDirection.Input)
151 					Assert.AreEqual ("http://tempuri.org/IGreetings/SendMessage", md.Action, "MD:SendMessage");
152 				else
153 					Assert.AreEqual ("http://tempuri.org/IGreetings/SendMessageResponse", md.Action, "MD:SendMessage");
154 			}
155 			foreach (var md in show.Messages) {
156 				if (md.Direction == MessageDirection.Output)
157 					Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessage", md.Action, "MD:ShowMessage");
158 				else
159 					Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessageResponse", md.Action, "MD:ShowMessage");
160 			}
161 			eventServiceHost.Open ();
162 
163 			var chd = (ChannelDispatcher) eventServiceHost.ChannelDispatchers [0];
164 			Assert.IsNotNull (chd, "ChannelDispatcher");
165 			Assert.AreEqual (1, chd.Endpoints.Count, "ChannelDispatcher.Endpoints.Count");
166 			var ed = chd.Endpoints [0];
167 			var cr = ed.DispatchRuntime.CallbackClientRuntime;
168 			Assert.IsNotNull (cr, "CR");
169 			Assert.AreEqual (1, cr.Operations.Count, "CR.Operations.Count");
170 			Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessage", cr.Operations [0].Action, "ClientOperation.Action");
171 
172 			//Create client proxy
173 			NetTcpBinding clientBinding = new NetTcpBinding ();
174 			clientBinding.Security.Mode = SecurityMode.None;
175 			EndpointAddress ep = new EndpointAddress ("net.tcp://localhost:8000/GreetingsService");
176 			ClientCallback cb = new ClientCallback ();
177 			IGreetings proxy = DuplexChannelFactory<IGreetings>.CreateChannel (new InstanceContext (cb), clientBinding, ep);
178 
179 			//Call service
180 			proxy.SendMessage ();
181 
182 			//Wait for callback - sort of hack, but better than using wait handle to possibly block tests.
183 			Thread.Sleep (2000);
184 
185 			//Cleanup
186 			eventServiceHost.Close ();
187 
188 			Assert.IsTrue (CallbackSent, "#1");
189 			Assert.IsTrue (CallbackReceived, "#2");
190 		}
191 
192 		[Test]
193 		[Category ("NotWorking")]
CallbackExample2()194 		public void CallbackExample2 ()
195 		{
196 			//Start service and use net.tcp binding
197 			ServiceHost eventServiceHost = new ServiceHost (typeof (GreetingsService2));
198 			NetTcpBinding tcpBindingpublish = new NetTcpBinding ();
199 			tcpBindingpublish.Security.Mode = SecurityMode.None;
200 			eventServiceHost.AddServiceEndpoint (typeof (IGreetings2), tcpBindingpublish, "net.tcp://localhost:8000/GreetingsService2");
201 			eventServiceHost.Open ();
202 
203 			//Create client proxy
204 			NetTcpBinding clientBinding = new NetTcpBinding ();
205 			clientBinding.Security.Mode = SecurityMode.None;
206 			EndpointAddress ep = new EndpointAddress ("net.tcp://localhost:8000/GreetingsService2");
207 			ClientCallback2 cb = new ClientCallback2 ();
208 			IGreetings2 proxy = DuplexChannelFactory<IGreetings2>.CreateChannel (new InstanceContext (cb), clientBinding, ep);
209 
210 			//Call service
211 			proxy.SendMessage ();
212 
213 			//Wait for callback - sort of hack, but better than using wait handle to possibly block tests.
214 			Thread.Sleep (2000);
215 
216 			//Cleanup
217 			eventServiceHost.Close ();
218 
219 			Assert.IsTrue (CallbackSent2, "#1");
220 			Assert.IsTrue (CallbackReceived2, "#2");
221 		}
222 
223 		public static bool CallbackSent, CallbackReceived;
224 
225 		//Service implementation
226 		[ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
227 		public class GreetingsService : IGreetings
228 		{
SendMessage()229 			public void SendMessage ()
230 			{
231 				//Make a callback
232 				IGreetingsCallback clientCallback = OperationContext.Current.GetCallbackChannel<IGreetingsCallback> ();
233 
234 				clientCallback.ShowMessage ("Mono and WCF are GREAT!");
235 				CallbackBehaviorAttributeTest.CallbackSent = true;
236 			}
237 		}
238 
239 		// Client callback interface implementation
240 		[CallbackBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
241 		public class ClientCallback : IGreetingsCallback
242 		{
ShowMessage(string message)243 			public void ShowMessage (string message)
244 			{
245 				CallbackBehaviorAttributeTest.CallbackReceived = true;
246 			}
247 		}
248 
249 		[ServiceContract (CallbackContract = typeof (IGreetingsCallback))]
250 		public interface IGreetings
251 		{
252 			[OperationContract (IsOneWay = true)]
SendMessage()253 			void SendMessage ();
254 		}
255 
256 		[ServiceContract]
257 		public interface IGreetingsCallback
258 		{
259 			[OperationContract (IsOneWay = true)]
ShowMessage(string message)260 			void ShowMessage (string message);
261 		}
262 
263 		public static bool CallbackSent2, CallbackReceived2;
264 
265 		//Service implementation
266 		[ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
267 		public class GreetingsService2 : IGreetings2
268 		{
SendMessage()269 			public void SendMessage ()
270 			{
271 				//Make a callback
272 				IGreetingsCallback2 clientCallback = OperationContext.Current.GetCallbackChannel<IGreetingsCallback2> ();
273 
274 				clientCallback.ShowMessage ("Mono and WCF are GREAT!");
275 				CallbackBehaviorAttributeTest.CallbackSent2 = true;
276 			}
277 		}
278 
279 		// Client callback interface implementation
280 		[CallbackBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
281 		public class ClientCallback2 : IGreetingsCallback2
282 		{
ShowMessage(string message)283 			public void ShowMessage (string message)
284 			{
285 				CallbackBehaviorAttributeTest.CallbackReceived2 = true;
286 			}
287 		}
288 
289 		[ServiceContract (CallbackContract = typeof (IGreetingsCallback2))]
290 		public interface IGreetings2
291 		{
292 			[OperationContract (IsOneWay = false)]
SendMessage()293 			void SendMessage ();
294 		}
295 
296 		[ServiceContract]
297 		public interface IGreetingsCallback2
298 		{
299 			[OperationContract (IsOneWay = false)]
ShowMessage(string message)300 			void ShowMessage (string message);
301 		}
302 		#endregion
303 
304 		#region ConcurrencyMode testing
305 
306 		ManualResetEvent wait_handle = new ManualResetEvent (false);
307 
308 		[Test]
309 		[Category ("NotWorking")]
ConcurrencyModeSingleAndCallbackInsideServiceMethod()310 		public void ConcurrencyModeSingleAndCallbackInsideServiceMethod ()
311 		{
312 			var host = new ServiceHost (typeof (TestService));
313 			var binding = new NetTcpBinding ();
314 			binding.Security.Mode = SecurityMode.None;
315 			host.AddServiceEndpoint (typeof (ITestService), binding, new Uri ("net.tcp://localhost:18080"));
316 			host.Description.Behaviors.Find<ServiceDebugBehavior> ().IncludeExceptionDetailInFaults = true;
317 			host.Open ();
318 
319 			try {
320 				var cf = new DuplexChannelFactory<ITestService> (new TestCallback (), binding, new EndpointAddress ("net.tcp://localhost:18080"));
321 				var ch = cf.CreateChannel ();
322 				ch.DoWork ("test");
323 
324 				wait_handle.WaitOne (10000);
325 				Assert.Fail ("should fail");
326 			} catch (FaultException) {
327 				// expected.
328 			} finally {
329 				Thread.Sleep (1000);
330 			}
331 
332 			host.Close ();
333 		}
334 
335 		[ServiceContract (CallbackContract = typeof (ITestCallback))]
336 		public interface ITestService
337 		{
338 			[OperationContract (IsOneWay = false)] // ConcurrencyMode error as long as IsOneWay == false.
DoWork(string name)339 			void DoWork (string name);
340 		}
341 
342 		public interface ITestCallback
343 		{
344 			[OperationContract (IsOneWay = false)]
Report(string result)345 			void Report (string result);
346 		}
347 
348 		public class TestService : ITestService
349 		{
DoWork(string name)350 			public void DoWork (string name)
351 			{
352 				var cb = OperationContext.Current.GetCallbackChannel<ITestCallback> ();
353 				cb.Report ("OK");
354 				Assert.Fail ("callback should have failed");
355 			}
356 		}
357 
358 		public class TestCallback : ITestCallback
359 		{
Report(string result)360 			public void Report (string result)
361 			{
362 				Assert.Fail ("should not reach here");
363 			}
364 		}
365 
366 		#endregion
367 	}
368 }
369 #endif