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