2 // ContractDescriptionTest.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 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;
30 using System.Net.Security;
31 using System.Reflection;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
35 using NUnit.Framework;
37 namespace MonoTests.System.ServiceModel
40 public class ContractDescriptionTest
43 [ExpectedException (typeof (InvalidOperationException))]
44 public void GetNonContract ()
46 ContractDescription cd = ContractDescription.GetContract (
51 public void GetContract ()
53 InternalTestGetContract (
54 ContractDescription.GetContract (typeof (IFoo)));
58 public void GetContractParamRenamed ()
60 ContractDescription cd = ContractDescription.GetContract (typeof (IFooMsgParams));
62 Assert.AreEqual (1, cd.Operations.Count, "Operation count");
65 OperationDescription od = cd.Operations [0];
67 ServiceAssert.AssertOperationDescription (
69 typeof (IFooMsgParams).GetMethod ("Foo"),
73 // Operation #1 -> Message #1
74 MessageDescription md = od.Messages [0];
76 ServiceAssert.AssertMessageAndBodyDescription (
77 "http://tempuri.org/IFooMsgParams/MyFoo",
78 MessageDirection.Input,
79 null, "MyFoo", "http://tempuri.org/", false,
82 ServiceAssert.AssertMessagePartDescription (
83 "MyParam", "http://tempuri.org/", 0, false,
84 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "MyFoo.msg");
88 ServiceAssert.AssertMessageAndBodyDescription (
89 "http://tempuri.org/IFooMsgParams/MyFooResponse",
90 MessageDirection.Output,
91 null, "MyFooResponse",
92 "http://tempuri.org/", true,
95 ServiceAssert.AssertMessagePartDescription (
96 "MyResult", "http://tempuri.org/", 0, false,
97 ProtectionLevel.None, typeof (string), md.Body.ReturnValue, "MyResult ReturnValue");
101 public void GetContractConfigName ()
103 ContractDescription cd = ContractDescription.GetContract (typeof (ICtorUseCase2));
104 Assert.AreEqual("CtorUseCase2", cd.ConfigurationName);
105 Assert.AreEqual("ICtorUseCase2", cd.Name);
106 cd = ContractDescription.GetContract (typeof (ICtorUseCase1));
107 Assert.AreEqual("MonoTests.System.ServiceModel.ICtorUseCase1", cd.ConfigurationName);
108 Assert.AreEqual("ICtorUseCase1", cd.Name);
112 public void GetContract2 ()
114 InternalTestGetContract (
115 ContractDescription.GetContract (typeof (Foo)));
118 public void InternalTestGetContract (ContractDescription cd)
120 ServiceAssert.AssertContractDescription (
121 "IFoo", "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null,
124 Assert.AreEqual (2, cd.Operations.Count, "Operation count");
127 OperationDescription od = cd.Operations [0];
129 ServiceAssert.AssertOperationDescription (
130 "HeyDude", null, null,
131 typeof (IFoo).GetMethod ("HeyDude"),
135 // Operation #1 -> Message #1
136 MessageDescription md = od.Messages [0];
138 ServiceAssert.AssertMessageAndBodyDescription (
139 "http://tempuri.org/IFoo/HeyDude",
140 MessageDirection.Input,
141 null, "HeyDude", "http://tempuri.org/", false,
144 ServiceAssert.AssertMessagePartDescription (
145 "msg", "http://tempuri.org/", 0, false,
146 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyDude.msg");
147 ServiceAssert.AssertMessagePartDescription (
148 "msg2", "http://tempuri.org/", 1, false,
149 ProtectionLevel.None, typeof (string), md.Body.Parts [1], "HeyDude.msg");
151 // Operation #1 -> Message #2
152 md = od.Messages [1];
154 ServiceAssert.AssertMessageAndBodyDescription (
155 "http://tempuri.org/IFoo/HeyDudeResponse",
156 MessageDirection.Output,
157 null, "HeyDudeResponse",
158 "http://tempuri.org/", true,
161 ServiceAssert.AssertMessagePartDescription (
162 "HeyDudeResult", "http://tempuri.org/", 0, false,
163 ProtectionLevel.None, typeof (string), md.Body.ReturnValue, "HeyDudeResponse ReturnValue");
166 od = cd.Operations [1];
168 ServiceAssert.AssertOperationDescription (
169 "HeyHey", null, null,
170 typeof (IFoo).GetMethod ("HeyHey"),
174 // Operation #2 -> Message #1
175 md = od.Messages [0];
177 ServiceAssert.AssertMessageAndBodyDescription (
178 "http://tempuri.org/IFoo/HeyHey",
179 MessageDirection.Input,
180 null, "HeyHey", "http://tempuri.org/", false,
183 ServiceAssert.AssertMessagePartDescription (
184 "ref1", "http://tempuri.org/", 0, false,
185 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyHey.ref1");
187 // Operation #2 -> Message #2
188 md = od.Messages [1];
190 ServiceAssert.AssertMessageAndBodyDescription (
191 "http://tempuri.org/IFoo/HeyHeyResponse",
192 MessageDirection.Output,
193 null, "HeyHeyResponse",
194 "http://tempuri.org/", true,
197 ServiceAssert.AssertMessagePartDescription (
198 "HeyHeyResult", "http://tempuri.org/", 0, false,
199 ProtectionLevel.None, typeof (void), md.Body.ReturnValue, "HeyHeyResponse ReturnValue");
201 ServiceAssert.AssertMessagePartDescription (
202 "out1", "http://tempuri.org/", 0, false,
203 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyHey.out1");
204 ServiceAssert.AssertMessagePartDescription (
205 "ref1", "http://tempuri.org/", 1, false,
206 ProtectionLevel.None, typeof (string), md.Body.Parts [1], "HeyHey.ref1");
210 public void GetContractInherit ()
212 ContractDescription.GetContract (typeof (Foo));
216 [ExpectedException (typeof (InvalidOperationException))]
217 public void GetMultipleServiceContract ()
219 ContractDescription.GetContract (typeof (FooBar));
223 // [ExpectedException (typeof (InvalidOperationException))]
224 public void GetContractNoOperation ()
226 ContractDescription.GetContract (typeof (INoOperation));
230 [Category ("NotWorking")]
231 public void GetContractMessageParameter ()
233 ContractDescription cd = ContractDescription.GetContract (typeof (IMessageParameter));
235 ServiceAssert.AssertContractDescription (
236 "IMessageParameter", "http://tempuri.org/",
237 SessionMode.Allowed, typeof (IMessageParameter), null,
240 OperationDescription od = cd.Operations [0];
242 ServiceAssert.AssertOperationDescription (
243 "ReturnMessage", null, null,
244 typeof (IMessageParameter).GetMethod ("ReturnMessage"),
248 MessageDescription md = od.Messages [0];
250 ServiceAssert.AssertMessageAndBodyDescription (
251 "http://tempuri.org/IMessageParameter/ReturnMessage",
252 MessageDirection.Input,
253 // Body.WrapperName is null
254 null, null, null, false,
255 md, "ReturnMessage");
257 ServiceAssert.AssertMessagePartDescription (
258 "arg", "http://tempuri.org/", 0, false,
259 ProtectionLevel.None, typeof (Message), md.Body.Parts [0], "ReturnMessage input");
263 [ExpectedException (typeof (InvalidOperationException))]
264 public void GetContractInvalidAsync ()
266 ContractDescription.GetContract (typeof (IInvalidAsync));
270 // IMetadataExchange contains async patterns.
271 public void GetContractIMetadataExchange ()
273 ContractDescription cd = ContractDescription.GetContract (typeof (IMetadataExchange));
274 OperationDescription od = cd.Operations [0];
275 Assert.AreEqual (2, od.Messages.Count, "premise: message count");
276 foreach (MessageDescription md in od.Messages) {
277 if (md.Direction == MessageDirection.Input) {
278 Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get", md.Action, "#1-1");
279 Assert.AreEqual (1, md.Body.Parts.Count, "#1-2");
280 Assert.IsNull (md.Body.ReturnValue, "#1-3");
281 Assert.AreEqual (typeof (Message), md.Body.Parts [0].Type, "#1-4");
283 Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse", md.Action, "#2-1");
284 Assert.AreEqual (0, md.Body.Parts.Count, "#2-2");
285 Assert.IsNotNull (md.Body.ReturnValue, "#2-3");
286 Assert.AreEqual (typeof (Message), md.Body.ReturnValue.Type, "#2-4");
292 // enable it if we want to become a compatibility kid. It has
293 // no ServiceContract, thus it should not be accepted. But
294 // there is an abuse of ChannelFactory<IRequestChannel> in
295 // MSDN documentations and probably examples.
296 [Category ("NotWorking")]
297 public void GetContractIRequestChannel ()
299 ContractDescription cd = ContractDescription.GetContract (typeof (IRequestChannel));
300 Assert.AreEqual (typeof (IRequestChannel), cd.ContractType, "#_1");
301 Assert.AreEqual ("IRequestChannel", cd.Name, "#_2");
302 Assert.AreEqual ("http://schemas.microsoft.com/2005/07/ServiceModel", cd.Namespace, "#_3");
303 Assert.AreEqual (false, cd.HasProtectionLevel, "#_4");
304 Assert.AreEqual (SessionMode.NotAllowed, cd.SessionMode, "#_5");
305 Assert.AreEqual (0, cd.Behaviors.Count, "#_6");
306 Assert.AreEqual (1, cd.Operations.Count, "#_7");
307 OperationDescription od = cd.Operations [0];
308 Assert.IsNull (od.SyncMethod, "#_8");
309 Assert.IsNull (od.BeginMethod, "#_9");
310 Assert.IsNull (od.EndMethod, "#_10");
311 Assert.AreEqual (false, od.IsOneWay, "#_11");
312 Assert.AreEqual (false, od.HasProtectionLevel, "#_12");
313 Assert.AreEqual ("Request", od.Name, "#_13");
314 Assert.AreEqual (true, od.IsInitiating, "#_14");
315 Assert.AreEqual (0, od.Behaviors.Count, "#_15");
316 Assert.AreEqual (2, od.Messages.Count, "#_16");
317 foreach (MessageDescription md in od.Messages) {
318 if (md.Direction == MessageDirection.Output) {
319 Assert.AreEqual ("*", md.Action, "#_17");
320 Assert.AreEqual (false, md.HasProtectionLevel, "#_18");
321 Assert.AreEqual (0, md.Headers.Count, "#_19");
322 Assert.AreEqual (0, md.Properties.Count, "#_20");
323 Assert.IsNull (md.MessageType, "#_21");
324 MessageBodyDescription mb = md.Body;
325 Assert.AreEqual (null, mb.WrapperName, "#_22");
326 Assert.AreEqual (null, mb.WrapperNamespace, "#_23");
327 Assert.IsNull (mb.ReturnValue, "#_24");
328 Assert.AreEqual (0, mb.Parts.Count, "#_25");
330 Assert.AreEqual ("*", md.Action, "#_17_");
331 Assert.AreEqual (false, md.HasProtectionLevel, "#_18_");
332 Assert.AreEqual (0, md.Headers.Count, "#_19_");
333 Assert.AreEqual (0, md.Properties.Count, "#_20_");
334 Assert.IsNull (md.MessageType, "#_21_");
335 MessageBodyDescription mb = md.Body;
336 Assert.AreEqual (null, mb.WrapperName, "#_22_");
337 Assert.AreEqual (null, mb.WrapperNamespace, "#_23_");
338 Assert.IsNull (mb.ReturnValue, "#_24_");
339 Assert.AreEqual (0, mb.Parts.Count, "#_25_");
345 [ExpectedException (typeof (InvalidOperationException))]
346 public void WrongAsyncEndContract ()
348 ContractDescription.GetContract (typeof (IWrongAsyncEndContract));
352 public void AsyncContract1 ()
354 ContractDescription cd =
355 ContractDescription.GetContract (typeof (IAsyncContract1));
356 Assert.AreEqual (1, cd.Operations.Count);
357 OperationDescription od = cd.Operations [0];
358 Assert.AreEqual ("Sum", od.Name, "#1");
359 Assert.IsNotNull (od.BeginMethod, "#2");
360 Assert.IsNotNull (od.EndMethod, "#3");
364 [ExpectedException (typeof (InvalidOperationException))]
365 public void DuplicateOperationNames ()
367 ContractDescription.GetContract (typeof (IDuplicateOperationNames));
371 [ExpectedException (typeof (InvalidOperationException))]
372 public void AsyncMethodNameDoesNotStartWithBegin ()
374 ContractDescription.GetContract (typeof (IAsyncMethodNameDoesNotStartWithBegin));
378 [ExpectedException (typeof (InvalidOperationException))]
379 public void AsyncNameDoesNotStartWithBeginButExplicitName ()
381 // it is still invalid ...
382 ContractDescription.GetContract (typeof (IAsyncNameDoesNotStartWithBeginButExplicitName));
386 public void MessageBodyMemberIsNotInferred ()
388 ContractDescription cd = ContractDescription.GetContract (typeof (MessageBodyMemberIsNotInferredService));
389 OperationDescription od = cd.Operations [0];
390 MessageDescription md = od.Messages [0];
391 Assert.AreEqual (0, md.Body.Parts.Count);
395 public void TestContractFromObject () {
396 ContractDescription cd = ContractDescription.GetContract (typeof (Foo));
397 ServiceAssert.AssertContractDescription (typeof (IFoo).Name, "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null, cd, "#1");
398 Assert.AreEqual (cd.Operations.Count, 2);
399 OperationBehaviorAttribute op = cd.Operations.Find ("HeyHey").Behaviors.Find<OperationBehaviorAttribute> ();
400 Assert.IsNotNull (op);
402 op.ReleaseInstanceMode,
403 ReleaseInstanceMode.None, "#2");
405 cd = ContractDescription.GetContract (typeof (IFoo), typeof (Foo));
406 ServiceAssert.AssertContractDescription (typeof (IFoo).Name, "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null, cd, "#3");
407 Assert.AreEqual (cd.Operations.Count, 2, "#4");
409 cd.Operations.Find ("HeyHey").Behaviors.Find<OperationBehaviorAttribute> ().ReleaseInstanceMode,
410 ReleaseInstanceMode.AfterCall, "#5");
413 // It is for testing attribute search in interfaces.
414 public class Foo : IFoo
416 public string HeyDude (string msg, string msg2)
421 [OperationBehavior (ReleaseInstanceMode = ReleaseInstanceMode.AfterCall)]
422 public void HeyHey (out string out1, ref string ref1)
428 // It inherits both IFoo and IBar, thus cannot be a contract.
429 public class FooBar : IFoo, IBar
431 public string HeyDude (string msg, string msg2)
436 public void HeyHey (out string out1, ref string ref1)
441 public void OpenBar () {}
445 public interface IFoo
448 string HeyDude (string msg, string msg2);
451 void HeyHey (out string out1, ref string ref1);
455 public interface IFoo2
457 // FIXME: it does not pass yet
459 OregoMessage Nanoda (OregoMessage msg);
461 // FIXME: it does not pass yet
463 OregoMessage Nanoda2 (OregoMessage msg1, OregoMessage msg2);
465 // FIXME: it does not pass yet
467 Mona NewMona (Mona source);
471 public interface IBar
478 public class OregoMessage
481 public string Neutral;
484 [MessageBodyMember] // it should be ignored ...
485 public string Setter { set { } }
486 public string NonMember;
491 public string OmaeMona;
492 public string OreMona;
496 public interface INoOperation
501 public interface IMessageParameter
504 Message ReturnMessage (Message arg);
508 public interface IInvalidAsync
511 Message ReturnMessage (Message arg);
513 [OperationContract (AsyncPattern = true)]
514 IAsyncResult BeginReturnMessage (Message arg, AsyncCallback callback, object state);
516 // and no EndReturnMessage().
520 public interface IWrongAsyncEndContract
523 int Sum (int a, int b);
525 [OperationContract (AsyncPattern = true)]
526 IAsyncResult BeginSum (int a, int b, AsyncCallback cb, object state);
528 // this OperationContractAttribute is not allowed.
529 [OperationContract (AsyncPattern = true)]
530 int EndSum (IAsyncResult result);
534 public interface IAsyncContract1
537 int Sum (int a, int b);
539 [OperationContract (AsyncPattern = true)]
540 IAsyncResult BeginSum (int a, int b, AsyncCallback cb, object state);
542 int EndSum (IAsyncResult result);
546 public interface IAsyncMethodNameDoesNotStartWithBegin
549 int Sum (int a, int b);
551 [OperationContract (AsyncPattern = true)]
552 IAsyncResult StartSum (int a, int b, AsyncCallback cb, object state);
554 int EndSum (IAsyncResult result);
558 public interface IAsyncNameDoesNotStartWithBeginButExplicitName
561 int Sum (int a, int b);
563 [OperationContract (Name = "Sum", AsyncPattern = true)]
564 IAsyncResult StartSum (int a, int b, AsyncCallback cb, object state);
566 int EndSum (IAsyncResult result);
570 public interface IDuplicateOperationNames
573 string Echo (string s);
576 string Echo (string s1, string s2);
580 public interface IFooMsgParams
582 [OperationContract (Name = "MyFoo")]
583 [return: MessageParameter (Name = "MyResult")]
584 string Foo ([MessageParameter (Name = "MyParam")] string param);
588 public class MessageBodyMemberIsNotInferredService
591 public void Echo (MessageBodyMemberIsNotInferredContract msg)
597 public class MessageBodyMemberIsNotInferredContract