2 // CallbackBehaviorAttributeTest.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2009 Novell, Inc. http://www.novell.com
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Collections.ObjectModel;
32 using System.Net.Sockets;
33 using System.Reflection;
34 using System.ServiceModel;
35 using System.ServiceModel.Channels;
36 using System.ServiceModel.Description;
37 using System.ServiceModel.Dispatcher;
38 using System.Transactions;
39 using System.Threading;
40 using NUnit.Framework;
42 using MonoTests.Helpers;
44 namespace MonoTests.System.ServiceModel
47 public class CallbackBehaviorAttributeTest
50 public void DefaultValues ()
52 var c = new CallbackBehaviorAttribute ();
53 Assert.IsTrue (c.AutomaticSessionShutdown, "#1");
54 Assert.AreEqual (ConcurrencyMode.Single, c.ConcurrencyMode, "#2");
55 Assert.IsFalse (c.IgnoreExtensionDataObject, "#3");
56 Assert.IsFalse (c.IncludeExceptionDetailInFaults, "#4");
57 Assert.AreEqual (0x10000, c.MaxItemsInObjectGraph, "#5");
58 Assert.AreEqual (IsolationLevel.Unspecified, c.TransactionIsolationLevel, "#6");
59 Assert.IsNull (c.TransactionTimeout, "#7");
60 Assert.IsTrue (c.UseSynchronizationContext, "#8");
61 Assert.IsTrue (c.ValidateMustUnderstand, "#9");
65 public void AddBindingParameters ()
67 IEndpointBehavior eb = new CallbackBehaviorAttribute ();
68 var cd = ContractDescription.GetContract (typeof (IFoo));
69 var se = new ServiceEndpoint (cd);
70 Assert.AreEqual (0, se.Behaviors.Count, "#1");
71 var pc = new BindingParameterCollection ();
72 eb.AddBindingParameters (se, pc);
73 Assert.AreEqual (0, pc.Count, "#2");
74 Assert.AreEqual (0, se.Behaviors.Count, "#3");
78 [ExpectedException (typeof (InvalidOperationException))]
79 public void ApplyDispatchBehavior ()
81 // It cannot be applied to service endpoint dispatcher.
82 IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
83 var cd = ContractDescription.GetContract (typeof (IFoo));
84 var se = new ServiceEndpoint (cd);
85 var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IFoo", "urn:foo");
86 eb.ApplyDispatchBehavior (se, ed);
90 [ExpectedException (typeof (InvalidOperationException))]
91 public void ApplyClientBehaviorNonDuplex ()
93 // It must be applied to duplex callback runtime
94 IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
95 var cd = ContractDescription.GetContract (typeof (IFoo));
96 var se = new ServiceEndpoint (cd);
97 var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IFoo", "urn:foo");
98 var cr = ed.DispatchRuntime.CallbackClientRuntime;
99 eb.ApplyClientBehavior (se, cr);
102 /* There is no way that I can create ClientRuntime instance ...
104 public void ApplyClientBehavior ()
106 IEndpointBehavior eb = new CallbackBehaviorAttribute () { ConcurrencyMode = ConcurrencyMode.Multiple, ValidateMustUnderstand = false };
107 var cd = ContractDescription.GetContract (typeof (IDuplexFoo));
108 var se = new ServiceEndpoint (cd);
109 var ed = new EndpointDispatcher (new EndpointAddress ("http://localhost:" + NetworkHelpers.FindFreePort ()), "IDuplexFoo", "urn:foo");
110 var cr = ed.DispatchRuntime.CallbackClientRuntime;
111 eb.ApplyClientBehavior (se, cr);
112 Assert.IsFalse (cr.ValidateMustUnderstand, "#2.1");
113 //Assert.IsFalse (cr.CallbackDispatchRuntime.ValidateMustUnderstand, "#2.2");
114 Assert.AreEqual (1, se.Behaviors.Count, "#3");
119 public interface IFoo
122 string Join (string s1, string s2);
125 [ServiceContract (CallbackContract = typeof (IFoo))]
126 public interface IDuplexFoo
129 void Block (string s);
132 #region "bug #567672"
134 [Category ("NotWorking")]
135 public void CallbackExample1 ()
137 //Start service and use net.tcp binding
138 ServiceHost eventServiceHost = new ServiceHost (typeof (GreetingsService));
139 NetTcpBinding tcpBindingpublish = new NetTcpBinding ();
140 tcpBindingpublish.Security.Mode = SecurityMode.None;
141 eventServiceHost.AddServiceEndpoint (typeof (IGreetings), tcpBindingpublish, "net.tcp://localhost:8000/GreetingsService");
142 var cd = eventServiceHost.Description.Endpoints [0].Contract;
143 Assert.AreEqual (2, cd.Operations.Count, "Operations.Count");
144 var send = cd.Operations.FirstOrDefault (od => od.Name == "SendMessage");
145 var show = cd.Operations.FirstOrDefault (od => od.Name == "ShowMessage");
146 Assert.IsNotNull (send, "OD:SendMessage");
147 Assert.IsNotNull (show, "OD:ShowMessage");
148 foreach (var md in send.Messages) {
149 if (md.Direction == MessageDirection.Input)
150 Assert.AreEqual ("http://tempuri.org/IGreetings/SendMessage", md.Action, "MD:SendMessage");
152 Assert.AreEqual ("http://tempuri.org/IGreetings/SendMessageResponse", md.Action, "MD:SendMessage");
154 foreach (var md in show.Messages) {
155 if (md.Direction == MessageDirection.Output)
156 Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessage", md.Action, "MD:ShowMessage");
158 Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessageResponse", md.Action, "MD:ShowMessage");
160 eventServiceHost.Open ();
162 var chd = (ChannelDispatcher) eventServiceHost.ChannelDispatchers [0];
163 Assert.IsNotNull (chd, "ChannelDispatcher");
164 Assert.AreEqual (1, chd.Endpoints.Count, "ChannelDispatcher.Endpoints.Count");
165 var ed = chd.Endpoints [0];
166 var cr = ed.DispatchRuntime.CallbackClientRuntime;
167 Assert.IsNotNull (cr, "CR");
168 Assert.AreEqual (1, cr.Operations.Count, "CR.Operations.Count");
169 Assert.AreEqual ("http://tempuri.org/IGreetings/ShowMessage", cr.Operations [0].Action, "ClientOperation.Action");
171 //Create client proxy
172 NetTcpBinding clientBinding = new NetTcpBinding ();
173 clientBinding.Security.Mode = SecurityMode.None;
174 EndpointAddress ep = new EndpointAddress ("net.tcp://localhost:8000/GreetingsService");
175 ClientCallback cb = new ClientCallback ();
176 IGreetings proxy = DuplexChannelFactory<IGreetings>.CreateChannel (new InstanceContext (cb), clientBinding, ep);
179 proxy.SendMessage ();
181 //Wait for callback - sort of hack, but better than using wait handle to possibly block tests.
185 eventServiceHost.Close ();
187 Assert.IsTrue (CallbackSent, "#1");
188 Assert.IsTrue (CallbackReceived, "#2");
192 [Category ("NotWorking")]
193 public void CallbackExample2 ()
195 //Start service and use net.tcp binding
196 ServiceHost eventServiceHost = new ServiceHost (typeof (GreetingsService2));
197 NetTcpBinding tcpBindingpublish = new NetTcpBinding ();
198 tcpBindingpublish.Security.Mode = SecurityMode.None;
199 eventServiceHost.AddServiceEndpoint (typeof (IGreetings2), tcpBindingpublish, "net.tcp://localhost:8000/GreetingsService2");
200 eventServiceHost.Open ();
202 //Create client proxy
203 NetTcpBinding clientBinding = new NetTcpBinding ();
204 clientBinding.Security.Mode = SecurityMode.None;
205 EndpointAddress ep = new EndpointAddress ("net.tcp://localhost:8000/GreetingsService2");
206 ClientCallback2 cb = new ClientCallback2 ();
207 IGreetings2 proxy = DuplexChannelFactory<IGreetings2>.CreateChannel (new InstanceContext (cb), clientBinding, ep);
210 proxy.SendMessage ();
212 //Wait for callback - sort of hack, but better than using wait handle to possibly block tests.
216 eventServiceHost.Close ();
218 Assert.IsTrue (CallbackSent2, "#1");
219 Assert.IsTrue (CallbackReceived2, "#2");
222 public static bool CallbackSent, CallbackReceived;
224 //Service implementation
225 [ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
226 public class GreetingsService : IGreetings
228 public void SendMessage ()
231 IGreetingsCallback clientCallback = OperationContext.Current.GetCallbackChannel<IGreetingsCallback> ();
233 clientCallback.ShowMessage ("Mono and WCF are GREAT!");
234 CallbackBehaviorAttributeTest.CallbackSent = true;
238 // Client callback interface implementation
239 [CallbackBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
240 public class ClientCallback : IGreetingsCallback
242 public void ShowMessage (string message)
244 CallbackBehaviorAttributeTest.CallbackReceived = true;
248 [ServiceContract (CallbackContract = typeof (IGreetingsCallback))]
249 public interface IGreetings
251 [OperationContract (IsOneWay = true)]
256 public interface IGreetingsCallback
258 [OperationContract (IsOneWay = true)]
259 void ShowMessage (string message);
262 public static bool CallbackSent2, CallbackReceived2;
264 //Service implementation
265 [ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
266 public class GreetingsService2 : IGreetings2
268 public void SendMessage ()
271 IGreetingsCallback2 clientCallback = OperationContext.Current.GetCallbackChannel<IGreetingsCallback2> ();
273 clientCallback.ShowMessage ("Mono and WCF are GREAT!");
274 CallbackBehaviorAttributeTest.CallbackSent2 = true;
278 // Client callback interface implementation
279 [CallbackBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
280 public class ClientCallback2 : IGreetingsCallback2
282 public void ShowMessage (string message)
284 CallbackBehaviorAttributeTest.CallbackReceived2 = true;
288 [ServiceContract (CallbackContract = typeof (IGreetingsCallback2))]
289 public interface IGreetings2
291 [OperationContract (IsOneWay = false)]
296 public interface IGreetingsCallback2
298 [OperationContract (IsOneWay = false)]
299 void ShowMessage (string message);
303 #region ConcurrencyMode testing
305 ManualResetEvent wait_handle = new ManualResetEvent (false);
308 [Category ("NotWorking")]
309 public void ConcurrencyModeSingleAndCallbackInsideServiceMethod ()
311 var host = new ServiceHost (typeof (TestService));
312 var binding = new NetTcpBinding ();
313 binding.Security.Mode = SecurityMode.None;
314 host.AddServiceEndpoint (typeof (ITestService), binding, new Uri ("net.tcp://localhost:18080"));
315 host.Description.Behaviors.Find<ServiceDebugBehavior> ().IncludeExceptionDetailInFaults = true;
319 var cf = new DuplexChannelFactory<ITestService> (new TestCallback (), binding, new EndpointAddress ("net.tcp://localhost:18080"));
320 var ch = cf.CreateChannel ();
323 wait_handle.WaitOne (10000);
324 Assert.Fail ("should fail");
325 } catch (FaultException) {
334 [ServiceContract (CallbackContract = typeof (ITestCallback))]
335 public interface ITestService
337 [OperationContract (IsOneWay = false)] // ConcurrencyMode error as long as IsOneWay == false.
338 void DoWork (string name);
341 public interface ITestCallback
343 [OperationContract (IsOneWay = false)]
344 void Report (string result);
347 public class TestService : ITestService
349 public void DoWork (string name)
351 var cb = OperationContext.Current.GetCallbackChannel<ITestCallback> ();
353 Assert.Fail ("callback should have failed");
357 public class TestCallback : ITestCallback
359 public void Report (string result)
361 Assert.Fail ("should not reach here");