5 // Ankit Jain <jankit@novell.com>
6 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections.Generic;
31 using System.ServiceModel;
32 using System.ServiceModel.Channels;
33 using System.ServiceModel.Description;
34 using System.ServiceModel.Dispatcher;
35 using NUnit.Framework;
37 using MonoTests.Helpers;
39 namespace MonoTests.System.ServiceModel
42 public class ServiceHostTest
44 class MyHost : ServiceHost
46 public MyHost (Type type, Uri uri)
51 public IDictionary<string,ContractDescription> ExposedContracts {
52 get { return ImplementedContracts; }
59 MyHost host = new MyHost (typeof (Foo), new Uri ("http://localhost"));
60 Assert.IsNotNull (host.Description, "#1");
61 Assert.AreEqual (typeof (Foo), host.Description.ServiceType, "#1-2");
62 Assert.IsNotNull (host.BaseAddresses, "#2");
63 Assert.AreEqual (1, host.BaseAddresses.Count, "#3");
65 Assert.IsNotNull (host.ChannelDispatchers, "#4");
66 Assert.AreEqual (0, host.ChannelDispatchers.Count, "#5");
67 Assert.IsNotNull (host.Authorization, "#6");
68 Assert.IsNotNull (host.ExposedContracts, "#7");
69 // Foo is already in the contracts.
70 Assert.AreEqual (1, host.ExposedContracts.Count, "#8");
71 // this loop iterates only once.
72 foreach (KeyValuePair<string,ContractDescription> e in host.ExposedContracts) {
73 // hmm... so, seems like the key is just the full name of the contract type.
74 Assert.AreEqual ("MonoTests.System.ServiceModel.ServiceHostTest+Foo", e.Key, "#9");
75 ContractDescription cd = e.Value;
76 Assert.AreEqual ("Foo", cd.Name, "#10");
77 Assert.AreEqual ("http://tempuri.org/", cd.Namespace, "#11");
82 [ExpectedException (typeof (ArgumentNullException))]
83 public void CtorNull ()
85 new ServiceHost (typeof (Foo), null);
89 [ExpectedException (typeof (ArgumentException))]
90 public void CtorServiceTypeNotClass ()
92 new ServiceHost (typeof (IBar), new Uri ("http://localhost"));
96 [ExpectedException (typeof (ArgumentException))]
97 public void CtorRelativeBaseAddress ()
99 new ServiceHost (typeof (Foo), new Uri ("test", UriKind.Relative));
103 [ExpectedException (typeof (ArgumentException))]
104 public void CtorMultipleAddressPerScheme ()
106 new ServiceHost ( typeof (Foo),
107 new Uri ("http://localhost", UriKind.Absolute),
108 new Uri ("http://someotherhost", UriKind.Absolute));
112 public void AddServiceEndpoint ()
114 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
115 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
116 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "svc");
118 Assert.IsNotNull (host.Description, "#6");
119 Assert.IsNotNull (host.Description.Endpoints, "#7");
120 Assert.AreEqual (host.Description.Endpoints.Count, 2, "#8");
121 Assert.AreEqual ("http://localhost/echo/rel", host.Description.Endpoints [0].Address.Uri.AbsoluteUri, "#9");
125 [ExpectedException (typeof (InvalidOperationException))]
126 public void AddServiceEndpoint1 ()
128 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("ftp://localhost/echo"));
129 // ftp does not match BasicHttpBinding
130 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
134 [ExpectedException (typeof (InvalidOperationException))]
135 public void AddServiceEndpoint2 ()
137 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
138 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
139 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); // duplicate URI
142 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
146 [ExpectedException (typeof (InvalidOperationException))]
147 public void AddServiceEndpoint2_2 ()
149 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
150 // same as above, but through Endpoints.Add()
151 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
152 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
155 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
159 [ExpectedException (typeof (InvalidOperationException))]
160 public void AddServiceEndpoint2_3 ()
162 ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri ("http://localhost/echo"));
163 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IHoge)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
164 host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IFuga)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
166 // Different contracts unlike previous two cases.
167 // If two or more endpoints are bound to the same listen
168 // URI, then they must share the same instance.
171 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
175 public void AddServiceEndpoint2_4 ()
177 var ep = "http://" + NetworkHelpers.LocalEphemeralEndPoint().ToString();
178 ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri (ep));
179 var binding = new BasicHttpBinding ();
180 host.AddServiceEndpoint (typeof (IHoge), binding, new Uri (ep));
181 host.AddServiceEndpoint (typeof (IFuga), binding, new Uri (ep));
183 // Use the same binding, results in one ChannelDispatcher (actually two, for metadata/debug behavior).
186 Assert.AreEqual (2, host.ChannelDispatchers.Count, "#1");
187 foreach (ChannelDispatcher cd in host.ChannelDispatchers) {
188 if (cd.BindingName != binding.Name)
190 Assert.AreEqual (2, cd.Endpoints.Count, "#2");
198 [ExpectedException (typeof (InvalidOperationException))]
199 public void AddServiceEndpoint3 ()
201 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
202 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
203 host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "http://localhost/echo/rel"); // duplicate URI when resolved
206 host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
212 ServiceHost host = new ServiceHost (typeof (ZeroOperationsImpl));
213 host.AddServiceEndpoint (typeof (IHaveZeroOperarationsContract), new BasicHttpBinding (), "http://localhost/echo");
217 Assert.Fail ("InvalidOperationException expected");
219 catch (InvalidOperationException e) {
220 //"ContractDescription 'IHaveZeroOperarationsContract' has zero operations; a contract must have at least one operation."
221 StringAssert.Contains ("IHaveZeroOperarationsContract", e.Message);
224 if (host.State == CommunicationState.Opened)
225 host.Close (); // It is to make sure to close unexpectedly opened host if the test fail.
230 public void AddServiceEndpoint4 ()
232 ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo"));
233 host.AddServiceEndpoint ("MonoTests.System.ServiceModel.ServiceHostTest+IBaz", new BasicHttpBinding (), "rel");
237 [ExpectedException (typeof (InvalidOperationException))]
238 public void AddServiceEndpoint5 ()
240 ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo"));
242 // Full type name is expected here (see AddServiceEndpoint4).
243 host.AddServiceEndpoint ("IBaz", new BasicHttpBinding (), "rel");
247 [ExpectedException (typeof (InvalidOperationException))]
248 public void AddServiceEndpoint6 ()
250 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
251 host.AddServiceEndpoint ("ISuchTypeDoesNotExist", new BasicHttpBinding (), "rel");
255 public void AddServiceEndpoint7 ()
257 ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
258 var a = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "a");
259 Console.WriteLine (a.Address);
260 Assert.AreEqual ("http", a.Address.Uri.Scheme, "#1");
261 Assert.AreEqual ("http://localhost/echo/a", a.Address.Uri.AbsoluteUri, "#2");
263 var b = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "/b");
264 Console.WriteLine (b.Address);
265 Assert.AreEqual ("http", b.Address.Uri.Scheme, "#3");
266 Assert.AreEqual ("http://localhost/echo/b", b.Address.Uri.AbsoluteUri, "#4");
270 [ExpectedException (typeof (InvalidOperationException))]
271 public void AddServiceEndpointMexWithNoImpl ()
273 using (ServiceHost h = new ServiceHost (typeof (Foo), new Uri ("http://localhost:8080"))) {
274 // it expects ServiceMetadataBehavior
275 h.AddServiceEndpoint (ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding (), "mex");
280 public void AddServiceEndpointMetadataExchange ()
282 // MyMetadataExchange implements IMetadataExchange
283 ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
284 host.AddServiceEndpoint ("IMetadataExchange",
285 new BasicHttpBinding (),
286 "http://localhost:8080/");
290 [ExpectedException (typeof (InvalidOperationException))]
291 public void AddServiceEndpointMetadataExchangeFullNameFails ()
293 ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
294 host.AddServiceEndpoint ("System.ServiceModel.Description.IMetadataExchange",
295 new BasicHttpBinding (),
296 "http://localhost:8080");
300 public void InstanceWithNonSingletonMode ()
302 var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
303 ServiceHost host = new ServiceHost (
304 new NonSingletonService ());
305 Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "premise1");
306 host.AddServiceEndpoint (
307 typeof (NonSingletonService),
308 new BasicHttpBinding (),
309 new Uri ("http://" + ep + "/s1"));
311 // in case Open() didn't fail, we need to close the host.
312 // And even if Close() caused the expected exception,
313 // the test should still fail.
317 if (host.State == CommunicationState.Opened)
319 } catch (InvalidOperationException) {
321 Assert.Fail ("InstanceContextMode was not checked");
322 } catch (InvalidOperationException) {
328 public void InstanceWithSingletonMode ()
330 var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
331 SingletonService instance = new SingletonService ();
332 ServiceHost host = new ServiceHost (instance);
333 Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "#1");
334 host.AddServiceEndpoint (
335 typeof (SingletonService),
336 new BasicHttpBinding (),
337 new Uri ("http://" + ep + "/s2"));
339 // in case Open() didn't fail, we need to close the host.
340 // And even if Close() caused the expected exception,
341 // the test should still fail.
344 ChannelDispatcher cd = (ChannelDispatcher) host.ChannelDispatchers [0];
345 DispatchRuntime dr = cd.Endpoints [0].DispatchRuntime;
346 Assert.IsNotNull (dr.InstanceContextProvider, "#2");
347 InstanceContext ctx = dr.InstanceContextProvider.GetExistingInstanceContext (null, null);
348 Assert.IsNotNull (ctx, "#3");
349 Assert.AreEqual (instance, ctx.GetServiceInstance (), "#4");
351 if (host.State == CommunicationState.Opened)
357 public void InstanceWithSingletonMode_InheritServiceBehavior ()
361 var ep = NetworkHelpers.LocalEphemeralEndPoint ().ToString ();
363 ChildSingletonService instance = new ChildSingletonService ();
364 ServiceHost host = new ServiceHost (instance);
366 host.AddServiceEndpoint (typeof (SingletonService),
367 new BasicHttpBinding (),
368 new Uri ("http://" + ep + "/s3"));
372 } catch (InvalidOperationException ex) {
373 Assert.Fail ("InstanceContextMode was not inherited from parent, exception was: {0}", ex);
388 public void SayWhat () { }
395 string Echo (string source);
413 interface IHaveZeroOperarationsContract
415 string Echo (string source);
418 class ZeroOperationsImpl : IHaveZeroOperarationsContract
420 public string Echo(string source)
426 class HogeFuga : IHoge, IFuga
428 public void DoX () {}
429 public void DoY () {}
434 public string Echo (string source)
440 class MyMetadataExchange : IMetadataExchange
442 public Message Get (Message req)
444 throw new NotImplementedException ();
447 public IAsyncResult BeginGet (Message request, AsyncCallback cb, object state)
449 throw new NotImplementedException ();
452 public Message EndGet (IAsyncResult result)
454 throw new NotImplementedException ();
459 public class NonSingletonService
462 public void Process (string input)
468 [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single)]
469 public class SingletonService
472 public virtual void Process (string input)
477 public class ChildSingletonService : SingletonService
479 public override void Process (string input)