2 // WebHttpDispatchOperationSelectorTest.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.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.
31 using System.Globalization;
32 using System.Runtime.Serialization;
33 using System.ServiceModel;
34 using System.ServiceModel.Channels;
35 using System.ServiceModel.Description;
36 using System.ServiceModel.Dispatcher;
37 using System.ServiceModel.Web;
40 using NUnit.Framework;
42 using MonoTests.Helpers;
44 namespace MonoTests.System.ServiceModel.Dispatcher
47 public class WebHttpDispatchOperationSelectorTest
50 [ExpectedException (typeof (ArgumentNullException))]
51 public void ConstructorNullEndpoint ()
53 new WebHttpDispatchOperationSelector (null);
57 [ExpectedException (typeof (InvalidOperationException))]
58 public void ConstructorEndpointNullAddress ()
60 ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
61 new WebHttpDispatchOperationSelector (se);
64 #region SelectOperation
67 public void SelectOperation ()
69 SelectOperationCore (Create ());
73 public void SelectOperation2 ()
75 SelectOperationCore (Create2 ());
79 public void SelectOperation3 ()
81 ContractDescription cd = ContractDescription.GetContract (typeof (MyService2));
82 Assert.IsNotNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#1");
84 cd = ContractDescription.GetContract (typeof (MyService));
85 Assert.IsNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#2");
88 void SelectOperationCore (MySelector d)
91 var msg = Message.CreateMessage (MessageVersion.Soap12, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
92 Assert.IsNull (msg.Headers.To, "#1-0");
93 Assert.IsFalse (d.SelectOperation (ref msg, out name), "#1");
94 Assert.AreEqual ("", name, "#1-2");
95 Assert.IsNull (msg.Headers.To, "#1-3"); // no overwrite
96 Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#1-4");
98 msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo");
99 Assert.IsFalse (d.SelectOperation (ref msg, out name), "#2");
100 Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#2-2");
102 msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
103 Assert.IsFalse (d.SelectOperation (ref msg, out name), "#3");
104 Assert.AreEqual ("", name, "#3-2");
105 Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#3-3");
107 // version and action do not matter
108 msg = Message.CreateMessage (MessageVersion.Soap12, "http://nonexistent.org/");
109 var http = new HttpRequestMessageProperty ();
110 // this mismatch is allowed. Lack of this value is OK.
111 // http.Method = "POST";
112 // this mismatch is allowed. Lack of this value is OK.
113 // http.QueryString = "foo=bar";
114 // this mismatch is allowed. Lack of this value is OK.
115 // http.Headers.Add ("Content-Type", "application/json");
116 // so, the http property can be empty, but is required.
117 msg.Properties.Add (HttpRequestMessageProperty.Name, http);
118 msg.Headers.To = new Uri ("http://localhost:8080/Echo?input=hoge");
119 Assert.IsTrue (d.SelectOperation (ref msg, out name), "#4");
120 // FIXME: hmm... isn'y "Echo" expected?
121 // Assert.AreEqual ("", name, "#4-2");
125 [Category ("NotWorking")]
126 public void SelectOperationOnlyMessage ()
128 // This test shows strange result ... it adds UriMatched property while it does not really match the URI.
131 var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
132 Assert.AreEqual ("", d.SelectOperation (ref msg), "#1");
133 Assert.IsTrue (msg.Properties.ContainsKey ("UriMatched"), "#1-2");
135 msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
136 Assert.AreEqual ("", d.SelectOperation (ref msg), "#2");
137 Assert.IsNotNull (msg.Properties ["UriMatched"], "#2-2");
141 [ExpectedException (typeof (ArgumentException))]
142 public void SelectOperationCheckExistingProperty ()
145 var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // heh, I mistyped it and turned to prove that Action does not matter.
146 msg.Headers.To = new Uri ("http://localhost:8080/Echo");
148 // LAMESPEC: .NET does returns String.Empty, while we return the name of the operation (as IOperationSelector.SelectOperation is expected to do!)
149 // Assert.AreEqual (String.Empty, d.SelectOperation (ref msg), "#1");
150 d.SelectOperation (ref msg);
152 // The second invocation should raise the expected exception
153 d.SelectOperation (ref msg);
158 class MySelector : WebHttpDispatchOperationSelector
160 public MySelector (ServiceEndpoint se)
165 public bool SelectOperation (ref Message msg, out string name)
168 name = SelectOperation (ref msg, out ret);
173 class MyBehavior : WebHttpBehavior
175 public WebHttpDispatchOperationSelector GetPublicOperationSelector (ServiceEndpoint se)
177 return GetOperationSelector (se);
180 protected override WebHttpDispatchOperationSelector GetOperationSelector (ServiceEndpoint se)
182 return new MySelector (se);
187 public interface MyService
190 // [WebGet (UriTemplate = "MyService/Echo?input={input}")]
191 // [WebGet] // UriTemplate = "Echo?input={input}"
192 string Echo (string input);
195 [ServiceContract (Name = "MyService")]
196 public interface MyService2
198 [OperationContract (Name = "Echo")]
199 [WebGet] // UriTemplate = "Echo?input={input}"
200 string Echo (string input);
205 ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
206 se.Address = new EndpointAddress ("http://localhost:8080");
207 se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
208 return new MySelector (se);
209 //var b = new MyBehavior ();
210 //se.Behaviors.Add (b);
211 //return (MySelector) b.GetPublicOperationSelector (se);
214 MySelector Create2 ()
216 ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService2)));
217 se.Address = new EndpointAddress ("http://localhost:8080");
218 //se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
219 return new MySelector (se);
224 #region "bug #656020"
230 public string Name { get; set; }
236 [WebGet(UriTemplate = "{name}?age={age}&blah={blah}")]
238 string SayHi (string name, int age, string blah);
240 [WebInvoke(UriTemplate = "blah")]
242 string SayHi2 (User user);
247 public string SayHi (string name, int age, string blah)
249 return string.Format ("Hi {0}: {1}, {2}", name, age, blah == null);
252 public string SayHi2 (User user)
254 return string.Format ("Hi {0}.", user.Name);
259 public void WebMessageFormats ()
261 var host = new WebServiceHost (typeof (Hello));
262 var port = NetworkHelpers.FindFreePort ();
263 host.AddServiceEndpoint (typeof (IHello), new WebHttpBinding (), "http://localhost:" + port + "/");
264 host.Description.Behaviors.Find<ServiceDebugBehavior> ().IncludeExceptionDetailInFaults = true;
268 using (ChannelFactory<IHello> factory = new ChannelFactory<IHello> (new WebHttpBinding (), "http://localhost:" + port + "/"))
270 factory.Endpoint.Behaviors.Add (new WebHttpBehavior ());
271 IHello h = factory.CreateChannel ();
272 //Console.WriteLine(h.SayHi("Joe", 42, null));
273 Assert.AreEqual ("Hi Joe.", h.SayHi2 (new User { Name = "Joe" }), "#1");