1 // 2 // ServiceHostTest.cs 3 // 4 // Author: 5 // Ankit Jain <jankit@novell.com> 6 // Atsushi Enomoto <atsushi@ximian.com> 7 // 8 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com 9 // 10 // Permission is hereby granted, free of charge, to any person obtaining 11 // a copy of this software and associated documentation files (the 12 // "Software"), to deal in the Software without restriction, including 13 // without limitation the rights to use, copy, modify, merge, publish, 14 // distribute, sublicense, and/or sell copies of the Software, and to 15 // permit persons to whom the Software is furnished to do so, subject to 16 // the following conditions: 17 // 18 // The above copyright notice and this permission notice shall be 19 // included in all copies or substantial portions of the Software. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 // 29 #if !MOBILE && !XAMMAC_4_5 30 using System; 31 using System.Collections.Generic; 32 using System.ServiceModel; 33 using System.ServiceModel.Channels; 34 using System.ServiceModel.Description; 35 using System.ServiceModel.Dispatcher; 36 using NUnit.Framework; 37 38 using MonoTests.Helpers; 39 40 namespace MonoTests.System.ServiceModel 41 { 42 [TestFixture] 43 public class ServiceHostTest 44 { 45 class MyHost : ServiceHost 46 { MyHost(Type type, Uri uri)47 public MyHost (Type type, Uri uri) 48 : base (type, uri) 49 { 50 } 51 52 public IDictionary<string,ContractDescription> ExposedContracts { 53 get { return ImplementedContracts; } 54 } 55 } 56 57 [Test] Ctor()58 public void Ctor () 59 { 60 MyHost host = new MyHost (typeof (Foo), new Uri ("http://localhost")); 61 Assert.IsNotNull (host.Description, "#1"); 62 Assert.AreEqual (typeof (Foo), host.Description.ServiceType, "#1-2"); 63 Assert.IsNotNull (host.BaseAddresses, "#2"); 64 Assert.AreEqual (1, host.BaseAddresses.Count, "#3"); 65 66 Assert.IsNotNull (host.ChannelDispatchers, "#4"); 67 Assert.AreEqual (0, host.ChannelDispatchers.Count, "#5"); 68 Assert.IsNotNull (host.Authorization, "#6"); 69 Assert.IsNotNull (host.ExposedContracts, "#7"); 70 // Foo is already in the contracts. 71 Assert.AreEqual (1, host.ExposedContracts.Count, "#8"); 72 // this loop iterates only once. 73 foreach (KeyValuePair<string,ContractDescription> e in host.ExposedContracts) { 74 // hmm... so, seems like the key is just the full name of the contract type. 75 Assert.AreEqual ("MonoTests.System.ServiceModel.ServiceHostTest+Foo", e.Key, "#9"); 76 ContractDescription cd = e.Value; 77 Assert.AreEqual ("Foo", cd.Name, "#10"); 78 Assert.AreEqual ("http://tempuri.org/", cd.Namespace, "#11"); 79 } 80 } 81 82 [Test] 83 [ExpectedException (typeof (ArgumentNullException))] CtorNull()84 public void CtorNull () 85 { 86 new ServiceHost (typeof (Foo), null); 87 } 88 89 [Test] 90 [ExpectedException (typeof (ArgumentException))] CtorServiceTypeNotClass()91 public void CtorServiceTypeNotClass () 92 { 93 new ServiceHost (typeof (IBar), new Uri ("http://localhost")); 94 } 95 96 [Test] 97 [ExpectedException (typeof (ArgumentException))] CtorRelativeBaseAddress()98 public void CtorRelativeBaseAddress () 99 { 100 new ServiceHost (typeof (Foo), new Uri ("test", UriKind.Relative)); 101 } 102 103 [Test] 104 [ExpectedException (typeof (ArgumentException))] CtorMultipleAddressPerScheme()105 public void CtorMultipleAddressPerScheme () 106 { 107 new ServiceHost ( typeof (Foo), 108 new Uri ("http://localhost", UriKind.Absolute), 109 new Uri ("http://someotherhost", UriKind.Absolute)); 110 } 111 112 [Test] AddServiceEndpoint()113 public void AddServiceEndpoint () 114 { 115 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 116 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); 117 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "svc"); 118 119 Assert.IsNotNull (host.Description, "#6"); 120 Assert.IsNotNull (host.Description.Endpoints, "#7"); 121 Assert.AreEqual (host.Description.Endpoints.Count, 2, "#8"); 122 Assert.AreEqual ("http://localhost/echo/rel", host.Description.Endpoints [0].Address.Uri.AbsoluteUri, "#9"); 123 } 124 125 [Test] 126 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint1()127 public void AddServiceEndpoint1 () 128 { 129 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("ftp://localhost/echo")); 130 // ftp does not match BasicHttpBinding 131 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); 132 } 133 134 [Test] 135 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint2()136 public void AddServiceEndpoint2 () 137 { 138 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 139 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); 140 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); // duplicate URI 141 142 host.Open (); 143 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host. 144 } 145 146 [Test] 147 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint2_2()148 public void AddServiceEndpoint2_2 () 149 { 150 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 151 // same as above, but through Endpoints.Add() 152 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel"))); 153 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel"))); 154 155 host.Open (); 156 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host. 157 } 158 159 [Test] 160 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint2_3()161 public void AddServiceEndpoint2_3 () 162 { 163 ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri ("http://localhost/echo")); 164 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IHoge)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo"))); 165 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IFuga)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo"))); 166 167 // Different contracts unlike previous two cases. 168 // If two or more endpoints are bound to the same listen 169 // URI, then they must share the same instance. 170 171 host.Open (); 172 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host. 173 } 174 175 [Test] AddServiceEndpoint2_4()176 public void AddServiceEndpoint2_4 () 177 { 178 var ep = "http://" + NetworkHelpers.LocalEphemeralEndPoint().ToString(); 179 ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri (ep)); 180 var binding = new BasicHttpBinding (); 181 host.AddServiceEndpoint (typeof (IHoge), binding, new Uri (ep)); 182 host.AddServiceEndpoint (typeof (IFuga), binding, new Uri (ep)); 183 184 // Use the same binding, results in one ChannelDispatcher (actually two, for metadata/debug behavior). 185 host.Open (); 186 try { 187 Assert.AreEqual (2, host.ChannelDispatchers.Count, "#1"); 188 foreach (ChannelDispatcher cd in host.ChannelDispatchers) { 189 if (cd.BindingName != binding.Name) 190 continue; // mex 191 Assert.AreEqual (2, cd.Endpoints.Count, "#2"); 192 } 193 } finally { 194 host.Close (); 195 } 196 } 197 198 [Test] 199 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint3()200 public void AddServiceEndpoint3 () 201 { 202 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 203 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); 204 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "http://localhost/echo/rel"); // duplicate URI when resolved 205 206 host.Open (); 207 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host. 208 } 209 210 [Test] Open()211 public void Open () 212 { 213 ServiceHost host = new ServiceHost (typeof (ZeroOperationsImpl)); 214 host.AddServiceEndpoint (typeof (IHaveZeroOperarationsContract), new BasicHttpBinding (), "http://localhost/echo"); 215 216 try { 217 host.Open (); 218 Assert.Fail ("InvalidOperationException expected"); 219 } 220 catch (InvalidOperationException e) { 221 //"ContractDescription 'IHaveZeroOperarationsContract' has zero operations; a contract must have at least one operation." 222 StringAssert.Contains ("IHaveZeroOperarationsContract", e.Message); 223 } 224 finally { 225 if (host.State == CommunicationState.Opened) 226 host.Close (); // It is to make sure to close unexpectedly opened host if the test fail. 227 } 228 } 229 230 [Test] AddServiceEndpoint4()231 public void AddServiceEndpoint4 () 232 { 233 ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo")); 234 host.AddServiceEndpoint ("MonoTests.System.ServiceModel.ServiceHostTest+IBaz", new BasicHttpBinding (), "rel"); 235 } 236 237 [Test] 238 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint5()239 public void AddServiceEndpoint5 () 240 { 241 ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo")); 242 243 // Full type name is expected here (see AddServiceEndpoint4). 244 host.AddServiceEndpoint ("IBaz", new BasicHttpBinding (), "rel"); 245 } 246 247 [Test] 248 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpoint6()249 public void AddServiceEndpoint6 () 250 { 251 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 252 host.AddServiceEndpoint ("ISuchTypeDoesNotExist", new BasicHttpBinding (), "rel"); 253 } 254 255 [Test] AddServiceEndpoint7()256 public void AddServiceEndpoint7 () 257 { 258 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo")); 259 var a = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "a"); 260 Console.WriteLine (a.Address); 261 Assert.AreEqual ("http", a.Address.Uri.Scheme, "#1"); 262 Assert.AreEqual ("http://localhost/echo/a", a.Address.Uri.AbsoluteUri, "#2"); 263 264 var b = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "/b"); 265 Console.WriteLine (b.Address); 266 Assert.AreEqual ("http", b.Address.Uri.Scheme, "#3"); 267 Assert.AreEqual ("http://localhost/echo/b", b.Address.Uri.AbsoluteUri, "#4"); 268 } 269 270 [Test] 271 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpointMexWithNoImpl()272 public void AddServiceEndpointMexWithNoImpl () 273 { 274 var port = NetworkHelpers.FindFreePort (); 275 using (ServiceHost h = new ServiceHost (typeof (Foo), new Uri ("http://localhost:" + port))) { 276 // it expects ServiceMetadataBehavior 277 h.AddServiceEndpoint (ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding (), "mex"); 278 } 279 } 280 281 [Test] AddServiceEndpointMetadataExchange()282 public void AddServiceEndpointMetadataExchange () 283 { 284 var port = NetworkHelpers.FindFreePort (); 285 // MyMetadataExchange implements IMetadataExchange 286 ServiceHost host = new ServiceHost (typeof (MyMetadataExchange)); 287 host.AddServiceEndpoint ("IMetadataExchange", 288 new BasicHttpBinding (), 289 "http://localhost:" + port + "/"); 290 } 291 292 [Test] 293 [ExpectedException (typeof (InvalidOperationException))] AddServiceEndpointMetadataExchangeFullNameFails()294 public void AddServiceEndpointMetadataExchangeFullNameFails () 295 { 296 var port = NetworkHelpers.FindFreePort (); 297 ServiceHost host = new ServiceHost (typeof (MyMetadataExchange)); 298 host.AddServiceEndpoint ("System.ServiceModel.Description.IMetadataExchange", 299 new BasicHttpBinding (), 300 "http://localhost:" + port); 301 } 302 303 [Test] InstanceWithNonSingletonMode()304 public void InstanceWithNonSingletonMode () 305 { 306 var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString(); 307 ServiceHost host = new ServiceHost ( 308 new NonSingletonService ()); 309 Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "premise1"); 310 host.AddServiceEndpoint ( 311 typeof (NonSingletonService), 312 new BasicHttpBinding (), 313 new Uri ("http://" + ep + "/s1")); 314 315 // in case Open() didn't fail, we need to close the host. 316 // And even if Close() caused the expected exception, 317 // the test should still fail. 318 try { 319 host.Open (); 320 try { 321 if (host.State == CommunicationState.Opened) 322 host.Close (); 323 } catch (InvalidOperationException) { 324 } 325 Assert.Fail ("InstanceContextMode was not checked"); 326 } catch (InvalidOperationException) { 327 } 328 } 329 330 331 [Test] InstanceWithSingletonMode()332 public void InstanceWithSingletonMode () 333 { 334 var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString(); 335 SingletonService instance = new SingletonService (); 336 ServiceHost host = new ServiceHost (instance); 337 Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "#1"); 338 host.AddServiceEndpoint ( 339 typeof (SingletonService), 340 new BasicHttpBinding (), 341 new Uri ("http://" + ep + "/s2")); 342 343 // in case Open() didn't fail, we need to close the host. 344 // And even if Close() caused the expected exception, 345 // the test should still fail. 346 try { 347 host.Open (); 348 ChannelDispatcher cd = (ChannelDispatcher) host.ChannelDispatchers [0]; 349 DispatchRuntime dr = cd.Endpoints [0].DispatchRuntime; 350 Assert.IsNotNull (dr.InstanceContextProvider, "#2"); 351 InstanceContext ctx = dr.InstanceContextProvider.GetExistingInstanceContext (null, null); 352 Assert.IsNotNull (ctx, "#3"); 353 Assert.AreEqual (instance, ctx.GetServiceInstance (), "#4"); 354 } finally { 355 if (host.State == CommunicationState.Opened) 356 host.Close (); 357 } 358 } 359 360 [Test] InstanceWithSingletonMode_InheritServiceBehavior()361 public void InstanceWithSingletonMode_InheritServiceBehavior () 362 { 363 // # 37035 364 365 var ep = NetworkHelpers.LocalEphemeralEndPoint ().ToString (); 366 367 ChildSingletonService instance = new ChildSingletonService (); 368 ServiceHost host = new ServiceHost (instance); 369 370 host.AddServiceEndpoint (typeof (SingletonService), 371 new BasicHttpBinding (), 372 new Uri ("http://" + ep + "/s3")); 373 374 try { 375 host.Open (); 376 } catch (InvalidOperationException ex) { 377 Assert.Fail ("InstanceContextMode was not inherited from parent, exception was: {0}", ex); 378 } finally { 379 host.Close (); 380 } 381 } 382 383 [ServiceContract] 384 interface IBar 385 { 386 } 387 388 [ServiceContract] 389 class Foo 390 { 391 [OperationContract] SayWhat()392 public void SayWhat () { } 393 } 394 395 [ServiceContract] 396 interface IBaz 397 { 398 [OperationContract] Echo(string source)399 string Echo (string source); 400 } 401 402 [ServiceContract] 403 interface IHoge 404 { 405 [OperationContract] DoX()406 void DoX (); 407 } 408 409 [ServiceContract] 410 interface IFuga 411 { 412 [OperationContract] DoY()413 void DoY (); 414 } 415 416 [ServiceContract] 417 interface IHaveZeroOperarationsContract 418 { Echo(string source)419 string Echo (string source); 420 } 421 422 class ZeroOperationsImpl : IHaveZeroOperarationsContract 423 { Echo(string source)424 public string Echo(string source) 425 { 426 return null; 427 } 428 } 429 430 class HogeFuga : IHoge, IFuga 431 { DoX()432 public void DoX () {} DoY()433 public void DoY () {} 434 } 435 436 class Baz : IBaz 437 { Echo(string source)438 public string Echo (string source) 439 { 440 return source; 441 } 442 } 443 444 class MyMetadataExchange : IMetadataExchange 445 { Get(Message req)446 public Message Get (Message req) 447 { 448 throw new NotImplementedException (); 449 } 450 BeginGet(Message request, AsyncCallback cb, object state)451 public IAsyncResult BeginGet (Message request, AsyncCallback cb, object state) 452 { 453 throw new NotImplementedException (); 454 } 455 EndGet(IAsyncResult result)456 public Message EndGet (IAsyncResult result) 457 { 458 throw new NotImplementedException (); 459 } 460 } 461 462 [ServiceContract] 463 public class NonSingletonService 464 { 465 [OperationContract] Process(string input)466 public void Process (string input) 467 { 468 } 469 } 470 471 [ServiceContract] 472 [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single)] 473 public class SingletonService 474 { 475 [OperationContract] Process(string input)476 public virtual void Process (string input) 477 { 478 } 479 } 480 481 public class ChildSingletonService : SingletonService 482 { Process(string input)483 public override void Process (string input) 484 { 485 } 486 } 487 } 488 } 489 #endif 490