using System; using System.IO; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.ServiceModel.Web; using System.Text; using NUnit.Framework; namespace MonoTests.System.ServiceModel.Description { public class WebHttpBehaviorExt : WebHttpBehavior { public IClientMessageFormatter DoGetReplyClientFormatter (OperationDescription operationDescription, ServiceEndpoint endpoint) { return GetReplyClientFormatter (operationDescription, endpoint); } public IClientMessageFormatter DoGetRequestClientFormatter (OperationDescription operationDescription, ServiceEndpoint endpoint) { return GetRequestClientFormatter (operationDescription, endpoint); } #if !MOBILE public IDispatchMessageFormatter DoGetReplyDispatchFormatter (OperationDescription operationDescription, ServiceEndpoint endpoint) { return GetReplyDispatchFormatter (operationDescription, endpoint); } public IDispatchMessageFormatter DoGetRequestDispatchFormatter (OperationDescription operationDescription, ServiceEndpoint endpoint) { return GetRequestDispatchFormatter (operationDescription, endpoint); } #endif public event Action ApplyClientBehaviorInvoked; public override void ApplyClientBehavior (ServiceEndpoint endpoint, ClientRuntime client) { base.ApplyClientBehavior (endpoint, client); if (ApplyClientBehaviorInvoked != null) ApplyClientBehaviorInvoked (endpoint, client); } } [TestFixture] public class WebHttpBehaviorTest { ServiceEndpoint CreateEndpoint () { return new ServiceEndpoint (ContractDescription.GetContract (typeof (IMyService)), new WebHttpBinding (), new EndpointAddress ("http://localhost:37564")); } [Test] public void DefaultValues () { var b = new WebHttpBehavior (); Assert.AreEqual (WebMessageBodyStyle.Bare, b.DefaultBodyStyle, "#1"); Assert.AreEqual (WebMessageFormat.Xml, b.DefaultOutgoingRequestFormat, "#2"); Assert.AreEqual (WebMessageFormat.Xml, b.DefaultOutgoingResponseFormat, "#3"); Assert.IsFalse (b.AutomaticFormatSelectionEnabled, "#11"); Assert.IsFalse (b.FaultExceptionEnabled, "#12"); Assert.IsFalse (b.HelpEnabled, "#13"); } [Test] public void AddBiningParameters () { var se = CreateEndpoint (); var b = new WebHttpBehavior (); var pl = new BindingParameterCollection (); b.AddBindingParameters (se, pl); Assert.AreEqual (0, pl.Count, "#1"); } #if !MOBILE && !MONOMAC [Test] public void ApplyDispatchBehavior () { var se = CreateEndpoint (); var od = se.Contract.Operations [0]; // in .NET 3.5 it adds "OperationSelectorBehavior" int initCB = ContractDescription.GetContract (typeof (IMyService)).Behaviors.Count; // in .NET 3.5 it adds // - OperationInvokeBehavior, // - OperationBehaviorAttribute, // - DataContractSerializerOperationBehavior and // - DataContractSerializerOperationGenerator int initOB = od.Behaviors.Count; // Assert.AreEqual (1, initCB, "#0-1"); // Assert.AreEqual (4, initOB, "#0-2"); var b = new WebHttpBehavior (); se.Behaviors.Add (b); var ed = new EndpointDispatcher (se.Address, se.Contract.Name, se.Contract.Namespace); IChannelListener l = new WebHttpBinding ().BuildChannelListener (new BindingParameterCollection ()); var cd = new ChannelDispatcher (l); cd.Endpoints.Add (ed); // without it this test results in NRE (it blindly adds IErrorHandler). Assert.AreEqual (0, cd.ErrorHandlers.Count, "#1-1"); Assert.IsNull (ed.DispatchRuntime.OperationSelector, "#1-2"); Assert.AreEqual (1, se.Behaviors.Count, "#1-3-1"); Assert.AreEqual (initCB, se.Contract.Behaviors.Count, "#1-3-2"); Assert.AreEqual (initOB, od.Behaviors.Count, "#1-3-3"); Assert.IsTrue (ed.AddressFilter is EndpointAddressMessageFilter, "#1-4"); b.ApplyDispatchBehavior (se, ed); // FIXME: implement and enable it later //Assert.AreEqual (1, cd.ErrorHandlers.Count, "#2-1"); Assert.AreEqual (typeof (WebHttpDispatchOperationSelector), ed.DispatchRuntime.OperationSelector.GetType (), "#2-2"); Assert.AreEqual (1, se.Behaviors.Count, "#3-1"); Assert.AreEqual (initCB, se.Contract.Behaviors.Count, "#3-2"); Assert.AreEqual (initOB, od.Behaviors.Count, "#3-3"); // ... i.e. nothing is added. Assert.IsTrue (ed.AddressFilter is PrefixEndpointAddressMessageFilter, "#3-4"); Assert.AreEqual (0, ed.DispatchRuntime.Operations.Count, "#4-0"); // hmm... really? } #endif [Test] public void GetMessageFormatters () { var se = CreateEndpoint (); var od = se.Contract.Operations [0]; var b = new WebHttpBehaviorExt (); Assert.IsNotNull (b.DoGetRequestClientFormatter (od, se), "#1"); Assert.IsNotNull (b.DoGetReplyClientFormatter (od, se), "#2"); #if !MOBILE Assert.IsNotNull (b.DoGetRequestDispatchFormatter (od, se), "#3"); Assert.IsNotNull (b.DoGetReplyDispatchFormatter (od, se), "#4"); #endif } [Test] public void RequestClientFormatter () { var se = CreateEndpoint (); var od = se.Contract.Operations [0]; var b = new WebHttpBehaviorExt (); var rcf = b.DoGetRequestClientFormatter (od, se); var msg = rcf.SerializeRequest (MessageVersion.None, new object [] {"foo"}); var hp = msg.Properties [HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; Assert.IsNotNull (hp, "#1"); Assert.IsTrue (msg.IsEmpty, "#2"); Assert.AreEqual (String.Empty, hp.QueryString, "#3"); var mb = msg.CreateBufferedCopy (1000); try { rcf.DeserializeReply (mb.CreateMessage (), new object [0]); Assert.Fail ("It should not support reply deserialization"); } catch (NotSupportedException) { } } #if !MOBILE [Test] public void RequestClientFormatter2 () { var se = CreateEndpoint (); var od = se.Contract.Operations [0]; var b = new WebHttpBehaviorExt (); IClientMessageFormatter rcf = null; b.ApplyClientBehaviorInvoked += delegate (ServiceEndpoint e, ClientRuntime cr) { rcf = cr.Operations [0].Formatter; }; se.Behaviors.Add (b); var ch = new WebChannelFactory (se).CreateChannel (); var msg = rcf.SerializeRequest (MessageVersion.None, new object [] {"foo"}); var hp = msg.Properties [HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; Assert.IsNotNull (hp, "#1"); Assert.IsTrue (msg.IsEmpty, "#2"); Assert.AreEqual (String.Empty, hp.QueryString, "#3"); //var mb = msg.CreateBufferedCopy (1000); // TODO: test DeserializeReply too (it is supported unlike above). } #endif [ServiceContract] public interface IMyService { [OperationContract] [WebGet] string Echo (string input); } public interface IMyServiceClient : IMyService, IClientChannel { } public class MyService: IMyService { #if !MOBILE [OperationBehavior] #endif public string Echo (string input) { return input; } } [Test] public void TestWebGetExists() { ContractDescription cd = ContractDescription.GetContract (typeof(IMyService), typeof (MyService)); OperationDescription od = cd.Operations[0]; Assert.IsTrue (od.Behaviors.Contains (typeof (WebGetAttribute)), "Operation is recognized as WebGet"); } #if !MOBILE [Test] public void MessageFormatterSupportsRaw () { // serializing reply var ms = new MemoryStream (); var bytes = new byte [] {0, 1, 2, 0xFF}; ms.Write (bytes, 0, bytes.Length); ms.Position = 0; var cd = ContractDescription.GetContract (typeof (ITestService)); var od = cd.Operations [0]; var se = new ServiceEndpoint (cd, new WebHttpBinding (), new EndpointAddress ("http://localhost:37564/")); var formatter = new WebHttpBehaviorExt ().DoGetReplyDispatchFormatter (od, se); var msg = formatter.SerializeReply (MessageVersion.None, null, ms); var wp = msg.Properties ["WebBodyFormatMessageProperty"] as WebBodyFormatMessageProperty; Assert.IsNotNull (wp, "#1"); Assert.AreEqual (WebContentFormat.Raw, wp.Format, "#2"); var wmebe = new WebMessageEncodingBindingElement (); var wme = wmebe.CreateMessageEncoderFactory ().Encoder; var ms2 = new MemoryStream (); wme.WriteMessage (msg, ms2); Assert.AreEqual (bytes, ms2.ToArray (), "#3"); } [Test] public void MessageFormatterSupportsRaw2 () { // deserializing request var ms = new MemoryStream (); ms.Write (new byte [] {0, 1, 2, 0xFF}, 0, 4); ms.Position = 0; var cd = ContractDescription.GetContract (typeof (ITestService)); var od = cd.Operations [0]; var se = new ServiceEndpoint (cd, new WebHttpBinding (), new EndpointAddress ("http://localhost:8080/")); var wmebe = new WebMessageEncodingBindingElement (); var wme = wmebe.CreateMessageEncoderFactory ().Encoder; var msg = wme.ReadMessage (ms, 100, null); // "application/xml" causes error. var formatter = new WebHttpBehaviorExt ().DoGetRequestDispatchFormatter (od, se); object [] pars = new object [1]; formatter.DeserializeRequest (msg, pars); Assert.IsTrue (pars [0] is Stream, "ret"); } #endif [ServiceContract] public interface IMultipleParametersGet { [OperationContract] [WebGet (UriTemplate = "get")] void Get (string p1, string p2); } [ServiceContract] public interface IMultipleParameters { [OperationContract] [WebInvoke (UriTemplate = "posturi?p1={p1}&p2={p2}")] string PostUri (string p1, string p2); [OperationContract] [WebInvoke (UriTemplate = "postone?p1={p1}")] string PostOne (string p1, string p2); [OperationContract] [WebInvoke (UriTemplate = "postwrapped", BodyStyle=WebMessageBodyStyle.WrappedRequest)] string PostWrapped (string p1, string p2); [OperationContract] [WebInvoke (UriTemplate = "out?p1={p1}&p2={p2}", BodyStyle=WebMessageBodyStyle.WrappedResponse)] void PostOut (string p1, string p2, out string ret); } [Test] public void MultipleParameters () { var behavior = new WebHttpBehaviorExt (); var cd = ContractDescription.GetContract (typeof (IMultipleParameters)); var se = new ServiceEndpoint (cd, new WebHttpBinding (), new EndpointAddress ("http://localhost:8080/")); behavior.Validate (se); foreach (var od in cd.Operations) behavior.DoGetRequestClientFormatter (od, se); } [Test] [Category ("NotWorking")] public void MultipleParameters2 () { var behavior = new WebHttpBehaviorExt (); var cd = ContractDescription.GetContract (typeof (IMultipleParametersGet)); var se = new ServiceEndpoint (cd, new WebHttpBinding (), new EndpointAddress ("http://localhost:8080/")); behavior.Validate (se); try { foreach (var od in cd.Operations) behavior.DoGetRequestClientFormatter (od, se); Assert.Fail ("Should result in invalid operation"); } catch (InvalidOperationException) { } } } [ServiceContract] public interface ITestService { [OperationContract] Stream Receive (Stream input); } }