public static void BasicAuthentication_RoundTrips_Echo() { BasicHttpBinding basicHttpBinding = null; EndpointAddress endpointAddress = null; ChannelFactory <IWcfCustomUserNameService> factory = null; string username = null; string password = null; IWcfCustomUserNameService serviceProxy = null; string testString = null; string result = null; try { // *** SETUP *** \\ basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; endpointAddress = new EndpointAddress(Endpoints.Https_BasicAuth_Address); factory = new ChannelFactory <IWcfCustomUserNameService>(basicHttpBinding, endpointAddress); username = Guid.NewGuid().ToString("n").Substring(0, 8); password = Guid.NewGuid().ToString("n").Substring(0, 16); factory.Credentials.UserName.UserName = username; factory.Credentials.UserName.Password = password; serviceProxy = factory.CreateChannel(); testString = "I am a test"; // *** EXECUTE *** \\ using (var scope = new OperationContextScope((IContextChannel)serviceProxy)) { HttpRequestMessageProperty requestMessageProperty; if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name)) { requestMessageProperty = new HttpRequestMessageProperty(); OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessageProperty; } else { requestMessageProperty = (HttpRequestMessageProperty)OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]; } requestMessageProperty.Headers[BasicUsernameHeaderName] = username; requestMessageProperty.Headers[BasicPasswordHeaderName] = password; result = serviceProxy.Echo(testString); } // *** VALIDATE *** \\ Assert.True(String.Equals(result, testString), String.Format("Basic echo test.\nTest variation:...\n{0}\nUsing address: '{1}'\nError: expected response from service: '{2}' Actual was: '{3}'", "BasicAuthentication_RoundTrips_Echo", Endpoints.Https_BasicAuth_Address, testString, result)); // *** CLEANUP *** \\ factory.Close(); ((ICommunicationObject)serviceProxy).Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void NegotiateStream_Http_With_ExplicitUserNameAndPassword_With_Upn() { #if FULLXUNIT_NOTSUPPORTED bool windows_Authentication_Available = Windows_Authentication_Available(); bool root_Certificate_Installed = Root_Certificate_Installed(); bool explicit_Credentials_Available = Explicit_Credentials_Available(); bool domain_Available = Domain_Available(); bool upn_Available = UPN_Available(); if (!windows_Authentication_Available || !root_Certificate_Installed || !explicit_Credentials_Available || !domain_Available || !upn_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Windows_Authentication_Available evaluated as {0}", windows_Authentication_Available); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Explicit_Credentials_Available evaluated as {0}", explicit_Credentials_Available); Console.WriteLine("Domain_Available evaluated as {0}", domain_Available); Console.WriteLine("UPN_Available evaluated as {0}", upn_Available); return; } #endif string testString = "Hello"; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; factory = new ChannelFactory <IWcfService>( binding, new EndpointAddress( new Uri(Endpoints.Https_WindowsAuth_Address), new UpnEndpointIdentity(GetUPN()) )); factory.Credentials.Windows.ClientCredential.Domain = GetDomain(); factory.Credentials.Windows.ClientCredential.UserName = GetExplicitUserName(); factory.Credentials.Windows.ClientCredential.Password = GetExplicitPassword(); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo(testString); // *** VALIDATE *** \\ Assert.Equal(testString, result); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
private static void RunVariation(string serviceAddress, bool isMultiNs = false) { BasicHttpBinding binding = null; EndpointAddress endpointAddress = null; ChannelFactory <ICalculator> factory1 = null; ChannelFactory <IHelloWorld> factory2 = null; ICalculator serviceProxy1 = null; IHelloWorld serviceProxy2 = null; // *** SETUP *** \\ binding = new BasicHttpBinding(); endpointAddress = new EndpointAddress(serviceAddress); factory1 = new ChannelFactory <ICalculator>(binding, endpointAddress); serviceProxy1 = factory1.CreateChannel(); if (isMultiNs) { factory2 = new ChannelFactory <IHelloWorld>(binding, endpointAddress); serviceProxy2 = factory2.CreateChannel(); } // *** EXECUTE Variation *** \\ try { var dateTime = DateTime.Now; string testStr = "test string"; var intParams = new IntParams() { P1 = 5, P2 = 10 }; var floatParams = new FloatParams() { P1 = 5.0f, P2 = 10.0f }; var byteParams = new ByteParams() { P1 = 5, P2 = 10 }; Assert.Equal(3, serviceProxy1.Sum2(1, 2)); Assert.Equal(intParams.P1 + intParams.P2, serviceProxy1.Sum(intParams)); Assert.Equal(string.Format("{0}{1}", intParams.P1, intParams.P2), serviceProxy1.Concatenate(intParams)); Assert.Equal((float)(floatParams.P1 / floatParams.P2), serviceProxy1.Divide(floatParams)); Assert.Equal((new byte[] { byteParams.P1, byteParams.P2 }), serviceProxy1.CreateSet(byteParams)); Assert.Equal(dateTime, serviceProxy1.ReturnInputDateTime(dateTime)); Guid guid = Guid.NewGuid(); serviceProxy1.AddIntParams(guid, intParams); IntParams outputIntParams = serviceProxy1.GetAndRemoveIntParams(guid); Assert.NotNull(outputIntParams); Assert.Equal(intParams.P1, outputIntParams.P1); Assert.Equal(intParams.P2, outputIntParams.P2); if (isMultiNs) { Guid guid2 = Guid.NewGuid(); serviceProxy2.AddString(guid2, testStr); Assert.Equal(testStr, serviceProxy2.GetAndRemoveString(guid2)); } } catch (Exception ex) { Assert.True(false, ex.Message); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy1); if (isMultiNs) { ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy2); } } }
public static void WebSocket_Https_Duplex_TextBuffered_KeepAlive() { TextMessageEncodingBindingElement textMessageEncodingBindingElement = null; HttpsTransportBindingElement httpsTransportBindingElement = null; CustomBinding binding = null; ClientReceiver clientReceiver = null; InstanceContext context = null; DuplexChannelFactory <IWSDuplexService> channelFactory = null; IWSDuplexService client = null; try { // *** SETUP *** \\ textMessageEncodingBindingElement = new TextMessageEncodingBindingElement(); httpsTransportBindingElement = new HttpsTransportBindingElement() { MaxReceivedMessageSize = ScenarioTestHelpers.SixtyFourMB, MaxBufferSize = ScenarioTestHelpers.SixtyFourMB }; httpsTransportBindingElement.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; httpsTransportBindingElement.WebSocketSettings.KeepAliveInterval = TimeSpan.FromSeconds(2); binding = new CustomBinding(textMessageEncodingBindingElement, httpsTransportBindingElement); clientReceiver = new ClientReceiver(); context = new InstanceContext(clientReceiver); channelFactory = new DuplexChannelFactory <IWSDuplexService>(context, binding, new EndpointAddress(Endpoints.WebSocketHttpsDuplexTextBuffered_Address)); client = channelFactory.CreateChannel(); // *** EXECUTE *** \\ // Invoking UploadData client.UploadData(ScenarioTestHelpers.CreateInterestingString(123)); // Invoking StartPushingData client.StartPushingData(); Assert.True(clientReceiver.ReceiveDataInvoked.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the buffered response from the Service. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveDataInvoked.Reset(); // Invoking StopPushingData client.StopPushingData(); Assert.True(clientReceiver.ReceiveDataCompleted.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the buffered response from the Service to be completed. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveDataCompleted.Reset(); // Getting results from server via callback. client.GetLog(); Assert.True(clientReceiver.LogReceived.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the Logging from the Service to be received. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); // *** VALIDATE *** \\ Assert.True(clientReceiver.ServerLog.Count > 0, "The logging done by the Server was not returned via the Callback."); // *** CLEANUP *** \\ ((ICommunicationObject)client).Close(); channelFactory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)client, channelFactory); } }
public static void WebSocket_Https_Duplex_Streamed(NetHttpMessageEncoding messageEncoding) { string endpointAddress; NetHttpsBinding binding = null; ClientReceiver clientReceiver = null; InstanceContext context = null; DuplexChannelFactory <IWSDuplexService> channelFactory = null; IWSDuplexService client = null; FlowControlledStream uploadStream = null; try { // *** SETUP *** \\ binding = new NetHttpsBinding() { MaxReceivedMessageSize = ScenarioTestHelpers.SixtyFourMB, MaxBufferSize = ScenarioTestHelpers.SixtyFourMB, }; binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; binding.TransferMode = TransferMode.Streamed; binding.MessageEncoding = messageEncoding; clientReceiver = new ClientReceiver(); context = new InstanceContext(clientReceiver); endpointAddress = Endpoints.WebSocketHttpsDuplexStreamed_Address + Enum.GetName(typeof(NetHttpMessageEncoding), messageEncoding); channelFactory = new DuplexChannelFactory <IWSDuplexService>(context, binding, endpointAddress); client = channelFactory.CreateChannel(); // *** EXECUTE *** \\ using (Stream stream = client.DownloadStream()) { int readResult; // Read from the stream, 1000 bytes at a time. byte[] buffer = new byte[1000]; do { readResult = stream.Read(buffer, 0, buffer.Length); }while (readResult != 0); } uploadStream = new FlowControlledStream(); uploadStream.ReadThrottle = TimeSpan.FromMilliseconds(500); uploadStream.StreamDuration = TimeSpan.FromSeconds(1); client.UploadStream(uploadStream); client.StartPushingStream(); // Wait for the callback to get invoked before telling the service to stop streaming. // This ensures we can read from the stream on the callback while the NCL layer at the service // is still writing the bytes from the stream to the wire. // This will deadlock if the transfer mode is buffered because the callback will wait for the // stream, and the NCL layer will continue to buffer the stream until it reaches the end. Assert.True(clientReceiver.ReceiveStreamInvoked.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the stream response from the Service. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveStreamInvoked.Reset(); // Upload the stream while we are downloading a different stream uploadStream = new FlowControlledStream(); uploadStream.ReadThrottle = TimeSpan.FromMilliseconds(500); uploadStream.StreamDuration = TimeSpan.FromSeconds(1); client.UploadStream(uploadStream); client.StopPushingStream(); // Waiting on ReceiveStreamCompleted from the ClientReceiver. Assert.True(clientReceiver.ReceiveStreamCompleted.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the stream response from the Service to be completed. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveStreamCompleted.Reset(); // Getting results from server via callback. client.GetLog(); Assert.True(clientReceiver.LogReceived.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the Logging from the Service to be received. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); // *** VALIDATE *** \\ Assert.True(clientReceiver.ServerLog.Count > 0, "The logging done by the Server was not returned via the Callback."); // *** CLEANUP *** \\ ((ICommunicationObject)client).Close(); channelFactory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)client, channelFactory); clientReceiver.Dispose(); } }
public static void NetTcp_TransportSecurity_Streamed_MultipleReads() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool windows_Authentication_Available = Windows_Authentication_Available(); bool ambient_Credentials_Available = Ambient_Credentials_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !windows_Authentication_Available || !ambient_Credentials_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("Windows_Authentication_Available evaluated as {0}", windows_Authentication_Available); Console.WriteLine("Ambient_Credentials_Available evaluated as {0}", ambient_Credentials_Available); return; } #endif string testString = ScenarioTestHelpers.CreateInterestingString(20001); NetTcpBinding binding = null; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; Stream stream = null; try { // *** SETUP *** \\ binding = new NetTcpBinding(SecurityMode.Transport); binding.TransferMode = TransferMode.Streamed; factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.Tcp_Transport_Security_Streamed_Address)); serviceProxy = factory.CreateChannel(); stream = StringToStream(testString); // *** EXECUTE *** \\ var returnStream = serviceProxy.EchoStream(stream); var ms = new MemoryStream((int)stream.Length); var buffer = new byte[10]; int bytesRead = 0; while ((bytesRead = returnStream.ReadAsync(buffer, 0, buffer.Length).Result) != 0) { ms.Write(buffer, 0, bytesRead); } ms.Position = 0; var result = StreamToString(ms); // *** VALIDATE *** \\ Assert.Equal(testString, result); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void ClientBaseOfT_Async_Open_Close_TimeSpan_Factory_And_Proxy_CommunicationState() { MyClientBase client = null; IWcfServiceGenerated serviceProxy = null; ChannelFactory <IWcfServiceGenerated> factory = null; TimeSpan timeout = ScenarioTestHelpers.TestTimeout; try { // *** SETUP *** \\ CustomBinding customBinding = new CustomBinding(); customBinding.Elements.Add(new TextMessageEncodingBindingElement()); customBinding.Elements.Add(new HttpTransportBindingElement()); string endpoint = Endpoints.HttpSoap12_Address; client = new MyClientBase(customBinding, new EndpointAddress(endpoint)); factory = client.ChannelFactory; // *** VALIDATE *** \\ Assert.True(CommunicationState.Created == client.State, String.Format("Expected client state to be Created but actual was '{0}'", client.State)); Assert.True(CommunicationState.Created == factory.State, String.Format("Expected channel factory state to be Created but actual was '{0}'", factory.State)); // Note: both the full framework and this NET Core version open the channel factory // when asking for the internal channel. Attempting to Open the ClientBase // after obtaining the internal channel with throw InvalidOperationException attempting // to reopen the channel factory. Customers don't encounter this situation in normal use // because access to the internal channel is protected and cannot be acquired. So we // defer asking for the internal channel in this test to allow the Open() to follow the // same code path as customer code. // *** EXECUTE *** \\ // Explicitly async open the ClientBase to follow general WCF guidelines IAsyncResult ar = ((ICommunicationObject)client).BeginOpen(timeout, null, null); ((ICommunicationObject)client).EndOpen(ar); // Use the internal proxy generated by ClientBase to most resemble how svcutil-generated code works. // This test defers asking for it until the ClientBase is open to avoid the issue described above. serviceProxy = client.Proxy; Assert.True(CommunicationState.Opened == client.State, String.Format("Expected client state to be Opened but actual was '{0}'", client.State)); Assert.True(CommunicationState.Opened == factory.State, String.Format("Expected channel factory state to be Opened but actual was '{0}'", factory.State)); Assert.True(CommunicationState.Opened == ((ICommunicationObject)serviceProxy).State, String.Format("Expected proxy state to be Opened but actual was '{0}'", ((ICommunicationObject)serviceProxy).State)); // *** EXECUTE *** \\ // Explicitly close the ClientBase to follow general WCF guidelines ar = ((ICommunicationObject)client).BeginClose(timeout, null, null); ((ICommunicationObject)client).EndClose(ar); // *** VALIDATE *** \\ // Closing the ClientBase closes the internal channel and factory Assert.True(CommunicationState.Closed == client.State, String.Format("Expected client state to be Closed but actual was '{0}'", client.State)); // Closing the ClientBase also closes the internal channel Assert.True(CommunicationState.Closed == ((ICommunicationObject)serviceProxy).State, String.Format("Expected proxy state to be Closed but actual was '{0}'", ((ICommunicationObject)serviceProxy).State)); // Closing the ClientBase also closes the channel factory Assert.True(CommunicationState.Closed == factory.State, String.Format("Expected channel factory state to be Closed but actual was '{0}'", factory.State)); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, client, factory); } }
// Asking for PeerTrust alone should throw SecurityNegotiationException // if the certificate is not in the TrustedPeople store. For this test // we use a valid chain-trusted certificate that we know is not in the // TrustedPeople store. public static void NetTcp_SecModeTrans_CertValMode_PeerTrust_Fails_Not_In_TrustedPeople() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool peer_Certificate_Installed = Peer_Certificate_Installed(); bool ssl_Available = SSL_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !peer_Certificate_Installed || !ssl_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("Peer_Certificate_Installed evaluated as {0}", peer_Certificate_Installed); Console.WriteLine("SSL_Available evaluated as {0}", ssl_Available); return; } #endif EndpointAddress endpointAddress = null; string testString = "Hello"; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; CommunicationException communicationException = null; try { // *** SETUP *** \\ NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport); binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None; endpointAddress = new EndpointAddress(new Uri( Endpoints.Tcp_CustomBinding_SslStreamSecurity_Address)); factory = new ChannelFactory <IWcfService>(binding, endpointAddress); factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerTrust; serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ try { serviceProxy.Echo(testString); } catch (CommunicationException ce) { communicationException = ce; } // *** VALIDATE *** \\ Assert.True(communicationException != null, "Expected CommunicationException but no exception was thrown."); Assert.True(communicationException.GetType().Name == "SecurityNegotiationException", String.Format("Expected SecurityNegotiationException but received {0}", communicationException.ToString())); // *** CLEANUP *** \\ // objects are in faulted state and will throw, so only use finally style cleanup } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void WebSocketHttpDuplexBinaryStreamed() { NetHttpBinding binding = null; ClientReceiver clientReceiver = null; InstanceContext context = null; DuplexChannelFactory <IWSDuplexService> channelFactory = null; IWSDuplexService client = null; FlowControlledStream uploadStream = null; try { // *** SETUP *** \\ binding = new NetHttpBinding(); binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; binding.MaxReceivedMessageSize = ScenarioTestHelpers.DefaultMaxReceivedMessageSize; binding.MaxBufferSize = ScenarioTestHelpers.DefaultMaxReceivedMessageSize; binding.TransferMode = TransferMode.Streamed; binding.MessageEncoding = NetHttpMessageEncoding.Binary; clientReceiver = new ClientReceiver(); context = new InstanceContext(clientReceiver); channelFactory = new DuplexChannelFactory <IWSDuplexService>(context, binding, Endpoints.WebSocketHttpDuplexBinaryStreamed_Address); client = channelFactory.CreateChannel(); // *** EXECUTE *** \\ using (Stream stream = client.DownloadStream()) { int readResult; // Read from the stream, 1000 bytes at a time. byte[] buffer = new byte[1000]; do { readResult = stream.Read(buffer, 0, buffer.Length); }while (readResult != 0); } uploadStream = new FlowControlledStream(); uploadStream.ReadThrottle = TimeSpan.FromMilliseconds(500); uploadStream.StreamDuration = TimeSpan.FromSeconds(1); client.UploadStream(uploadStream); client.StartPushingStream(); // Wait for the callback to get invoked before telling the service to stop streaming. // This ensures we can read from the stream on the callback while the NCL layer at the service // is still writing the bytes from the stream to the wire. // This will deadlock if the transfer mode is buffered because the callback will wait for the // stream, and the NCL layer will continue to buffer the stream until it reaches the end. clientReceiver.ReceiveStreamInvoked.WaitOne(); clientReceiver.ReceiveStreamInvoked.Reset(); // Upload the stream while we are downloading a different stream uploadStream = new FlowControlledStream(); uploadStream.ReadThrottle = TimeSpan.FromMilliseconds(500); uploadStream.StreamDuration = TimeSpan.FromSeconds(1); client.UploadStream(uploadStream); client.StopPushingStream(); // Waiting on ReceiveStreamCompleted from the ClientReceiver. clientReceiver.ReceiveStreamCompleted.WaitOne(); clientReceiver.ReceiveStreamCompleted.Reset(); // *** VALIDATE *** \\ // Validation is based on no exceptions being thrown. // *** CLEANUP *** \\ ((ICommunicationObject)client).Close(); channelFactory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)client, channelFactory); clientReceiver.Dispose(); } }
public static void ClientCertificate_EchoString() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool server_Accepts_Certificates = Server_Accepts_Certificates(); bool ssl_Available = SSL_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !server_Accepts_Certificates || !ssl_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("Server_Accepts_Certificates evaluated as {0}", server_Accepts_Certificates); Console.WriteLine("SSL_Available evaluated as {0}", ssl_Available); return; } #endif string clientCertThumb = null; EndpointAddress endpointAddress = null; string testString = "Hello"; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ BasicHttpsBinding basicHttpsBinding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport); basicHttpsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; endpointAddress = new EndpointAddress(new Uri(Endpoints.Https_ClientCertificateAuth_Address)); clientCertThumb = ServiceUtilHelper.ClientCertificate.Thumbprint; factory = new ChannelFactory <IWcfService>(basicHttpsBinding, endpointAddress); factory.Credentials.ClientCertificate.SetCertificate( StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, clientCertThumb); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo(testString); // *** VALIDATE *** \\ Assert.Equal(testString, result); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
// Asking for ChainTrust only should succeed if the certificate is // chain-trusted. public static void NetTcp_SecModeTrans_Duplex_Callback_Succeeds() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool ssl_Available = SSL_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !ssl_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("SSL_Available evaluated as {0}", ssl_Available); return; } #endif string clientCertThumb = null; EndpointAddress endpointAddress = null; DuplexChannelFactory <IWcfDuplexService> factory = null; IWcfDuplexService serviceProxy = null; Guid guid = Guid.NewGuid(); try { // *** SETUP *** \\ NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport); binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate; endpointAddress = new EndpointAddress(new Uri( Endpoints.Tcp_Certificate_Duplex_Address)); clientCertThumb = ServiceUtilHelper.ClientCertificate.Thumbprint; WcfDuplexServiceCallback callbackService = new WcfDuplexServiceCallback(); InstanceContext context = new InstanceContext(callbackService); factory = new DuplexChannelFactory <IWcfDuplexService>(context, binding, endpointAddress); factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust; factory.Credentials.ClientCertificate.SetCertificate( StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, clientCertThumb); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ // Ping on another thread. Task.Run(() => serviceProxy.Ping(guid)); Guid returnedGuid = callbackService.CallbackGuid; // *** VALIDATE *** \\ Assert.True(guid == returnedGuid, string.Format("The sent GUID does not match the returned GUID. Sent '{0}', Received: '{1}'", guid, returnedGuid)); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); ((ICommunicationObject)factory).Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void BasicHttp_Streamed_Async_Delayed_And_Aborted_Request_Throws_TimeoutException() { // This test is a regression test that verifies an issue discovered where exceeding the timeout // and aborting the channel before the client's Task completed led to incorrect error handling. BasicHttpBinding binding = null; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; Stream stream = null; int sendTimeoutMs = 3000; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.TransferMode = TransferMode.Streamed; binding.SendTimeout = TimeSpan.FromMilliseconds(sendTimeoutMs); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); serviceProxy = factory.CreateChannel(); // Create a read stream that will both timeout and then abort the proxy channel when the // async read is called. We also intercept the synchronous read because that path can also // be executed during an async read. stream = new TestMockStream() { CopyToAsyncFunc = (Stream destination, int bufferSize, CancellationToken ct) => { // Abort to force the internal HttpClientChannelAsyncRequest.Cleanup() // to clear its data structures before the client's Task completes. Task.Delay(sendTimeoutMs * 2).Wait(); ((ICommunicationObject)serviceProxy).Abort(); return(null); }, ReadFunc = (byte[] buffer, int offset, int count) => { // Abort to force the internal HttpClientChannelAsyncRequest.Cleanup() // to clear its data structures before the client's Task completes. Task.Delay(sendTimeoutMs * 2).Wait(); ((ICommunicationObject)serviceProxy).Abort(); return(-1); } }; // *** EXECUTE *** \\ Assert.Throws <TimeoutException>(() => { var unused = serviceProxy.EchoStreamAsync(stream).GetAwaiter().GetResult(); }); // *** VALIDATE *** \\ // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void ChannelShape_TypedProxy_InvokeIRequestChannelAsync() { CustomBinding customBinding = null; ChannelFactory <IRequestChannel> factory = null; EndpointAddress endpointAddress = null; IRequestChannel channel = null; Message requestMessage = null; Message replyMessage = null; string replyMessageAction = null; string actualResponse = null; try { // *** SETUP *** \\ customBinding = new CustomBinding(new BindingElement[] { new TextMessageEncodingBindingElement(MessageVersion.Default, Encoding.UTF8), new HttpTransportBindingElement() }); endpointAddress = new EndpointAddress(Endpoints.DefaultCustomHttp_Address); // Create the channel factory for the request-reply message exchange pattern. factory = new ChannelFactory <IRequestChannel>(customBinding, endpointAddress); // Create the channel. channel = factory.CreateChannel(); channel.Open(); // Create the Message object to send to the service. requestMessage = Message.CreateMessage( customBinding.MessageVersion, action, new CustomBodyWriter(clientMessage)); string expectedResponse = "[client] This is my request.[service] Request received, this is my Reply."; // *** EXECUTE *** \\ // Send the Message and receive the Response. IAsyncResult ar = channel.BeginRequest(requestMessage, null, null); replyMessage = channel.EndRequest(ar); replyMessageAction = replyMessage.Headers.Action; // *** VALIDATE *** \\ Assert.True(String.Equals(replyMessageAction, action + "Response"), String.Format("A response was received from the Service but it was not the expected Action, expected: {0} actual: {1}", action + "Response", replyMessageAction)); // *** EXECUTE *** \\ var replyReader = replyMessage.GetReaderAtBodyContents(); actualResponse = replyReader.ReadElementContentAsString(); // *** VALIDATE *** \\ Assert.True(String.Equals(actualResponse, expectedResponse), String.Format("Actual MessageBodyContent from service did not match the expected MessageBodyContent, expected: {0} actual: {1}", expectedResponse, actualResponse)); // *** CLEANUP *** \\ replyMessage.Close(); channel.Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ replyMessage.Close(); ScenarioTestHelpers.CloseCommunicationObjects(channel, factory); } }
public static void MustUnderstand_False_TrueNegative_TruePositive() { // When a Message arrives it travels through the WCF stack at the end of which it is passed to the ServiceModel layer. // The MustUnderstand property for every header in the Message is either true or false. // At the end of the stack a check is done, every header with MustUnderstand set to "true" must be found in the... // UnderstoodHeaders collection. // This test makes three calls to a service opration. // The service operation creates a MessageHeader using data passed to it in the call. // Each call validates a scenario variation. UnderstoodHeadersInspector inspector = null; ChannelFactory <IUnderstoodHeaders> factory = null; BasicHttpBinding binding = null; IUnderstoodHeaders proxy = null; // *** SETUP *** \\ binding = new BasicHttpBinding(); factory = new ChannelFactory <IUnderstoodHeaders>(binding, new EndpointAddress(Endpoints.UnderstoodHeaders)); inspector = new UnderstoodHeadersInspector(); factory.Endpoint.EndpointBehaviors.Add(inspector); proxy = factory.CreateChannel(); // *** EXECUTE 1st Variation *** \\ // Custom header with MustUnderstand set to "false", this should just work. try { proxy.CreateMessageHeader(customHeaderMustUnderstand_False.Name, customHeaderMustUnderstand_False.Namespace, customHeaderMustUnderstand_False.MustUnderstand); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)proxy); } // *** EXECUTE 2nd Variation *** \\ // Custom header with MustUnderstand set to "true" this should result in an exception since nothing... // on the client side stack is adding this header to UnderstoodHeaders. Assert.Throws <ProtocolException>(() => { try { proxy = factory.CreateChannel(); proxy.CreateMessageHeader(customHeaderMustUnderstand_True.Name, customHeaderMustUnderstand_True.Namespace, customHeaderMustUnderstand_True.MustUnderstand); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)proxy); } }); // *** EXECUTE 3d Variation *** \\ // Custom header with MustUnderstand set to "True", this should pass because... // we are using a Message Inspector to add the header to UnderstoodHeaders. // This mimics the scenario where the client was expecting this header, did what it needed to do... // and then added it to the UnderstoodHeaders collection as confirmation that it was handled. try { proxy = factory.CreateChannel(); inspector.DoNothing = false; proxy.CreateMessageHeader(customHeaderMustUnderstand_True.Name, customHeaderMustUnderstand_True.Namespace, customHeaderMustUnderstand_True.MustUnderstand); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)proxy, factory); } }
public static void BasicAuthenticationInvalidPwd_throw_MessageSecurityException() { BasicHttpBinding basicHttpBinding = null; ChannelFactory <IWcfCustomUserNameService> factory = null; EndpointAddress endpointAddress = null; string username = null; string password = null; IWcfCustomUserNameService serviceProxy = null; string testString = null; // Will need to use localized string once it is available // On Native retail, the message is stripped to 'HttpAuthorizationForbidden, Basic' // On Debug or .Net Core, the entire message is "The HTTP request was forbidden with client authentication scheme 'Basic'." // Thus we will only check message contains "forbidden" string message = "forbidden"; // *** VALIDATE *** \\ MessageSecurityException exception = Assert.Throws <MessageSecurityException>(() => { // *** SETUP *** \\ basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; endpointAddress = new EndpointAddress(Endpoints.Https_BasicAuth_Address); factory = new ChannelFactory <IWcfCustomUserNameService>(basicHttpBinding, endpointAddress); username = Guid.NewGuid().ToString("n").Substring(0, 8); password = Guid.NewGuid().ToString("n").Substring(0, 16); factory.Credentials.UserName.UserName = username; factory.Credentials.UserName.Password = password + "Invalid"; serviceProxy = factory.CreateChannel(); testString = "I am a test"; // *** EXECUTE *** \\ using (var scope = new OperationContextScope((IContextChannel)serviceProxy)) { HttpRequestMessageProperty requestMessageProperty; if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name)) { requestMessageProperty = new HttpRequestMessageProperty(); OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessageProperty; } else { requestMessageProperty = (HttpRequestMessageProperty)OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]; } requestMessageProperty.Headers[BasicUsernameHeaderName] = username; requestMessageProperty.Headers[BasicPasswordHeaderName] = password; try { string result = serviceProxy.Echo(testString); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } } }); // *** ADDITIONAL VALIDATION *** \\ Assert.True(exception.Message.ToLower().Contains(message), string.Format("Expected exception message to contain: '{0}', actual message is: '{1}'", message, exception.Message)); }
public static void Certificate_With_CanonicalName_Fqdn_Address_EchoString() { bool shouldCallSucceed = false; var domainNameEndpointUri = new Uri(Endpoints.Tcp_ClientCredentialType_Certificate_With_CanonicalName_DomainName_Address); // Get just the hostname part of the domainName Uri var domainNameHost = domainNameEndpointUri.Host.Split('.')[0]; var fqdnEndpointUri = new Uri(Endpoints.Tcp_ClientCredentialType_Certificate_With_CanonicalName_Fqdn_Address); var endpointAddress = new EndpointAddress(fqdnEndpointUri); // If the WCF service's reported FQDN is the same as the services's reported hostname, // it means that there the WCF service is set up on a network where FQDNs aren't used, only hostnames. // Since our pass/fail detection logic on whether or not this is an FQDN depends on whether the host name has a '.', we don't test this case if (string.Compare(domainNameHost, fqdnEndpointUri.Host, StringComparison.OrdinalIgnoreCase) != 0) { shouldCallSucceed = fqdnEndpointUri.Host.IndexOf('.') > -1; } string testString = "Hello"; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport); binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None; factory = new ChannelFactory <IWcfService>(binding, endpointAddress); factory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck; factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust; serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo(testString); // *** VALIDATE *** \\ Assert.Equal(testString, result); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); var errorBuilder = new StringBuilder(); errorBuilder.AppendFormat("The call to '{0}' should have failed but succeeded. ", fqdnEndpointUri.Host); errorBuilder.AppendFormat("This means that the certificate validation passed when it should have failed. "); errorBuilder.AppendFormat("Check the certificate returned by the endpoint at '{0}' ", fqdnEndpointUri); errorBuilder.AppendFormat("to see that it is correct; if it is, there is likely an issue with the identity checking logic."); Assert.True(shouldCallSucceed, errorBuilder.ToString()); } catch (MessageSecurityException exception) { // If there's a MessageSecurityException, we assume that the cert validation failed. Unfortunately checking for the // message is really brittle and we can't account for loc and how .NET Native will display the exceptions // The exception message should look like: // // System.ServiceModel.Security.MessageSecurityException : Identity check failed for outgoing message. The expected // DNS identity of the remote endpoint was 'localhost' but the remote endpoint provided DNS claim 'example.com'.If this // is a legitimate remote endpoint, you can fix the problem by explicitly specifying DNS identity 'example.com' as // the Identity property of EndpointAddress when creating channel proxy. var errorBuilder = new StringBuilder(); errorBuilder.AppendFormat("The call to '{0}' should have been successful but failed with a MessageSecurityException. ", fqdnEndpointUri.Host); errorBuilder.AppendFormat("This usually means that the certificate validation failed when it should have passed. "); errorBuilder.AppendFormat("When connecting to host '{0}', the expectation is that the DNSClaim will be for the same hostname. ", fqdnEndpointUri.Host); errorBuilder.AppendFormat("Exception message: {0}{1}", Environment.NewLine, exception.Message); Assert.True(!shouldCallSucceed, errorBuilder.ToString()); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void ServiceRestart_Throws_CommunicationException() { // This test validates that if the Service were to shut-down, re-start or otherwise die in the // middle of an operation the client will not just hang. It should instead receive a CommunicationException. string restartServiceAddress = ""; ChannelFactory <IWcfService> setupHostFactory = null; IWcfService setupHostServiceProxy = null; ChannelFactory <IWcfRestartService> factory = null; IWcfRestartService serviceProxy = null; BasicHttpBinding binding = new BasicHttpBinding(); // *** Step 1 *** \\ // We need the Service to create and open a ServiceHost and then give us the endpoint address for it. try { setupHostFactory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); setupHostServiceProxy = setupHostFactory.CreateChannel(); restartServiceAddress = setupHostServiceProxy.GetRestartServiceEndpoint(); // *** CLEANUP *** \\ ((ICommunicationObject)setupHostServiceProxy).Close(); setupHostFactory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)setupHostServiceProxy, setupHostFactory); } // *** Additional Setup *** \\ // The restartServiceAddress we got from the Service used localhost as the host name. // We need the actual host name for the client call to work. // To make it easier to parse, localhost was replaced with '[HOST]'. // Use Endpoints.HttpBaseAddress_Basic only for the purpose of extracting the Service host name. // Then update 'restartServiceAddress' with it. string hostName = new Uri(Endpoints.HttpBaseAddress_Basic).Host; restartServiceAddress = restartServiceAddress.Replace("[HOST]", hostName); // Get the last portion of the restart service url which is a Guid and convert it back to a Guid // This is needed by the RestartService operation as a Dictionary key to get the ServiceHost string uniqueIdentifier = restartServiceAddress.Substring(restartServiceAddress.LastIndexOf("/") + 1); Guid guid = new Guid(uniqueIdentifier); // *** Step 2 *** \\ // Simple echo call to make sure the newly created endpoint is working. try { factory = new ChannelFactory <IWcfRestartService>(binding, new EndpointAddress(restartServiceAddress)); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.NonRestartService(guid); Assert.True(result == "Success!", string.Format("Test Case failed, expected the returned string to be: {0}, instead it was: {1}", "Success!", result)); } catch (Exception ex) { string exceptionMessage = ex.Message; string innerExceptionMessage = ex.InnerException?.Message; string testExceptionMessage = $"The ping to validate the newly created endpoint failed.\nThe endpoint pinged was: {restartServiceAddress}\nThe GUID used to extract the ServiceHost from the server side dictionary was: {guid}"; string fullExceptionMessage = $"testExceptionMessage: {testExceptionMessage}\nexceptionMessage: {exceptionMessage}\ninnerExceptionMessage: {innerExceptionMessage}"; Assert.True(false, fullExceptionMessage); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } // *** Step 3 *** \\ // The actual part of the test where the host is killed in the middle of the operation. // We expect the test should not hang and should receive a CommunicationException. CommunicationException exception = Assert.Throws <CommunicationException>(() => { factory = new ChannelFactory <IWcfRestartService>(binding, new EndpointAddress(restartServiceAddress)); serviceProxy = factory.CreateChannel(); try { // *** EXECUTE *** \\ serviceProxy.RestartService(guid); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }); }
public static void Certificate_With_CanonicalName_Localhost_Address_EchoString() { var localhostEndpointUri = new Uri(Endpoints.Tcp_ClientCredentialType_Certificate_With_CanonicalName_Localhost_Address); var endpointAddress = new EndpointAddress(localhostEndpointUri); bool shouldCallSucceed = string.Compare(localhostEndpointUri.Host, "localhost", StringComparison.OrdinalIgnoreCase) == 0; string testString = "Hello"; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport); binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None; factory = new ChannelFactory <IWcfService>(binding, endpointAddress); factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust; serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo(testString); // *** VALIDATE *** \\ Assert.Equal(testString, result); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); var errorBuilder = new StringBuilder(); errorBuilder.AppendFormat("The call to '{0}' should have failed but succeeded. ", localhostEndpointUri.Host); errorBuilder.AppendFormat("This means that the certificate validation passed when it should have failed. "); errorBuilder.AppendFormat("Check the certificate returned by the endpoint at '{0}' ", localhostEndpointUri); errorBuilder.AppendFormat("to see that it is correct; if it is, there is likely an issue with the identity checking logic."); Assert.True(shouldCallSucceed, errorBuilder.ToString()); } catch (Exception exception) when(exception is CommunicationException || exception is MessageSecurityException) { if ((exception is MessageSecurityException) || (exception is CommunicationException) && !string.Equals(exception.InnerException.GetType().ToString(), "System.ServiceModel.Security.MessageSecurityException")) { // If there's a MessageSecurityException, we assume that the cert validation failed. Unfortunately checking for the // message is really brittle and we can't account for loc and how .NET Native will display the exceptions // The exception message should look like: // // System.ServiceModel.Security.MessageSecurityException : Identity check failed for outgoing message. The expected // DNS identity of the remote endpoint was 'localhost' but the remote endpoint provided DNS claim 'example.com'.If this // is a legitimate remote endpoint, you can fix the problem by explicitly specifying DNS identity 'example.com' as // the Identity property of EndpointAddress when creating channel proxy. var errorBuilder = new StringBuilder(); errorBuilder.AppendFormat("The call to '{0}' should have been successful but failed with a MessageSecurityException. ", localhostEndpointUri.Host); errorBuilder.AppendFormat("This usually means that the certificate validation failed when it should have passed. "); errorBuilder.AppendFormat("When connecting to host '{0}', the expectation is that the DNSClaim will be for the same hostname. ", localhostEndpointUri.Host); errorBuilder.AppendFormat("Exception message: {0}{1}", Environment.NewLine, exception.Message); Assert.True(!shouldCallSucceed, errorBuilder.ToString()); } } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void NetTcp_TransportSecurity_Streamed_TimeOut_Long_Running_Operation() { #if FULLXUNIT_NOTSUPPORTED bool root_Certificate_Installed = Root_Certificate_Installed(); bool client_Certificate_Installed = Client_Certificate_Installed(); bool windows_Authentication_Available = Windows_Authentication_Available(); bool ambient_Credentials_Available = Ambient_Credentials_Available(); if (!root_Certificate_Installed || !client_Certificate_Installed || !windows_Authentication_Available || !ambient_Credentials_Available) { Console.WriteLine("---- Test SKIPPED --------------"); Console.WriteLine("Attempting to run the test in ToF, a ConditionalFact evaluated as FALSE."); Console.WriteLine("Root_Certificate_Installed evaluated as {0}", root_Certificate_Installed); Console.WriteLine("Client_Certificate_Installed evaluated as {0}", client_Certificate_Installed); Console.WriteLine("Windows_Authentication_Available evaluated as {0}", windows_Authentication_Available); Console.WriteLine("Ambient_Credentials_Available evaluated as {0}", ambient_Credentials_Available); return; } #endif string testString = "Hello"; NetTcpBinding binding = null; TimeSpan serviceOperationTimeout = TimeSpan.FromMilliseconds(10000); ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; try { // *** SETUP *** \\ binding = new NetTcpBinding(SecurityMode.Transport); binding.TransferMode = TransferMode.Streamed; binding.SendTimeout = TimeSpan.FromMilliseconds(5000); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.Tcp_Transport_Security_Streamed_Address)); serviceProxy = factory.CreateChannel(); Stopwatch watch = new Stopwatch(); watch.Start(); // *** EXECUTE *** \\ try { Assert.Throws <TimeoutException>(() => { string returnString = serviceProxy.EchoWithTimeout(testString, serviceOperationTimeout); }); } finally { watch.Stop(); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } // *** VALIDATE *** \\ // want to assert that this completed in > 5 s as an upper bound since the SendTimeout is 5 sec // (usual case is around 5001-5005 ms) Assert.True(watch.ElapsedMilliseconds >= 4985 && watch.ElapsedMilliseconds < 6000, String.Format("Expected timeout was {0}ms but actual was {1}ms", serviceOperationTimeout.TotalMilliseconds, watch.ElapsedMilliseconds)); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static async Task RetryCountApplied(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; NetHttpBinding binding = null; try { // *** SETUP *** \\ binding = new NetHttpBinding(BasicHttpSecurityMode.None, true); binding.ReliableSession.Ordered = ordered; var customBinding = new CustomBinding(binding); var reliableSessionBindingElement = customBinding.Elements.Find <ReliableSessionBindingElement>(); reliableSessionBindingElement.MaxRetryCount = 2; reliableSessionBindingElement.ReliableMessagingVersion = rmVersion; factory = new ChannelFactory <IWcfReliableService>(customBinding, new EndpointAddress(Endpoints.ReliableSession_NetHttp + endpointSuffix)); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); bool delayNextCall = false; int httpRequestCount = 0; Stopwatch sw = null; TaskCompletionSource <object> tcs1 = null, tcs2 = new TaskCompletionSource <object>(); handlerFactoryBehavior.OnSendingAsync = async(request, token) => { Interlocked.Increment(ref httpRequestCount); // Once the delayNextCall latch is set, all subsequent calls will be on hold until tcs1 is completed. if (delayNextCall) { if (tcs1 == null) // First delayed call { sw = Stopwatch.StartNew(); tcs1 = new TaskCompletionSource <object>(); } else if (sw.IsRunning) { sw.Stop(); // Get time between initial call and 1st retry tcs2.TrySetResult(null); // Signal main test code that stopwatch measurement taken } // All calls will wait on the same TCS as trying to trigger retry; await tcs1.Task; } return(null); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ ((IClientChannel)serviceProxy).Open(); // This will establish a reliable session delayNextCall = true; // Reset request count as it would have incremented in the session open handshake httpRequestCount = 0; var resultTask = serviceProxy.GetNextNumberAsync(); await tcs2.Task; // Wait for Stopwatch to be stopped // *** VALIDATE *** \\ // There should only be a single retry at this point Assert.Equal(2, httpRequestCount); // ReliableSessions doubles the wait time between each retry. We know the first retry time. The second retry // will be 2X this, then the request will fail after another wait of 4X this delay. We need to wait at LEAST 6X // this initial delay for the channel to fault. 10X should be sufficient await Task.Delay((int)sw.ElapsedMilliseconds * 10); // There should now be the second retry (3 attempts to send the request) as well as the SequenceTerminated fault // making a total of 4 requests Assert.Equal(4, httpRequestCount); // Release the paused Http requests tcs1.TrySetResult(null); await Assert.ThrowsAsync <CommunicationException>(() => resultTask); Assert.Equal(CommunicationState.Faulted, ((ICommunicationObject)serviceProxy).State); ((ICommunicationObject)serviceProxy).Abort(); // Remove from factory so factory doesn't throw when closed. // *** CLEANUP *** \\ factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void CustomTextMessageEncoder_Http_RequestReply_Streamed() { // 84K, larger than any buffers, but won't allocate in LOH int streamKBytes = 84; int streamLength = 1024 * streamKBytes; int lowestPrintable = ' '; int printableRange = '~' - lowestPrintable; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; Stream stream = null; try { // *** SETUP *** \\ CustomBinding binding = new CustomBinding(new CustomTextMessageBindingElement(Encoding.UTF8.WebName), new HttpTransportBindingElement { MaxReceivedMessageSize = ScenarioTestHelpers.SixtyFourMB, MaxBufferSize = ScenarioTestHelpers.SixtyFourMB, TransferMode = TransferMode.Streamed }); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.CustomTextEncoderStreamed_Address)); serviceProxy = factory.CreateChannel(); byte[] requestBytes = new byte[streamLength]; RandomNumberGenerator rnd = RandomNumberGenerator.Create(); int pos = 0; for (int i = 0; i < streamKBytes; i++) { byte[] tempBuffer = new byte[1024]; rnd.GetBytes(tempBuffer); for (int j = 0; j < 1024; j++) { byte val = tempBuffer[j]; if (val < ' ' || val > '~') { // Force the value to be between ' ' and '~' int temp1 = val % printableRange; val = (byte)(temp1 + lowestPrintable); } requestBytes[pos++] = val; } } stream = new MemoryStream(requestBytes); // *** EXECUTE *** \\ var returnStream = serviceProxy.EchoStream(stream); // *** VALIDATE *** \\ MemoryStream ms = new MemoryStream(streamLength); returnStream.CopyTo(ms); Assert.True(streamLength == ms.Length, String.Format("Expected returned stream length = {0}, actual = {1}", streamLength, ms.Length)); ArraySegment <byte> returnedByteArraySegment; ms.TryGetBuffer(out returnedByteArraySegment); Assert.True(requestBytes.SequenceEqual(returnedByteArraySegment.Array), "Returned bytes are different than sent bytes"); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static async Task MaxTransferWindowSizeApplied(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; NetHttpBinding binding = null; string secondRequestHeaderName = "SecondRequest"; try { // *** SETUP *** \\ binding = new NetHttpBinding(BasicHttpSecurityMode.None, true); binding.ReliableSession.Ordered = ordered; var customBinding = new CustomBinding(binding); var reliableSessionBindingElement = customBinding.Elements.Find <ReliableSessionBindingElement>(); reliableSessionBindingElement.MaxTransferWindowSize = 1; reliableSessionBindingElement.ReliableMessagingVersion = rmVersion; factory = new ChannelFactory <IWcfReliableService>(customBinding, new EndpointAddress(Endpoints.ReliableSession_NetHttp + endpointSuffix)); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); bool delayNextCall = false; bool secondRequestSent = false; TaskCompletionSource <object> tcs1 = null, tcs2 = new TaskCompletionSource <object>(); handlerFactoryBehavior.OnSendingAsync = async(request, token) => { if (request.Headers.Contains(secondRequestHeaderName)) { secondRequestSent = true; } // Once the delayNextCall latch is set, all subsequent calls will be on hold until tcs1 is completed. if (delayNextCall) { if (tcs1 == null) // First delayed call { tcs1 = new TaskCompletionSource <object>(); tcs2.TrySetResult(null); // Signal main test code that first request has been attempted } // All calls will wait on the same TCS as trying to prevent requests progressing; await tcs1.Task; } return(null); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ ((IClientChannel)serviceProxy).Open(); // This will establish a reliable session delayNextCall = true; Stopwatch sw = Stopwatch.StartNew(); var resultTask1 = serviceProxy.GetNextNumberAsync(); await tcs2.Task; // Wait for first http request to be attempted sw.Stop(); Task <int> resultTask2; using (var scope = new OperationContextScope((IContextChannel)serviceProxy)) { // Add marker to second request so we can check if it's been seen by handler var httpRequestMessageProperty = new HttpRequestMessageProperty(); httpRequestMessageProperty.Headers.Add(secondRequestHeaderName, secondRequestHeaderName); OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequestMessageProperty); resultTask2 = serviceProxy.GetNextNumberAsync(); } // Wait 6 times the amount of time it took for the first http request to be made to ensure we've allowed // enough time that the second request should have happened by now. await Task.Delay((int)sw.ElapsedMilliseconds * 6); var secondRequestBlocked = !secondRequestSent; tcs1.TrySetResult(null); // Release first request int result1 = await resultTask1; int result2 = await resultTask2; // *** VALIDATE *** \\ Assert.Equal(1, result1); Assert.Equal(2, result2); Assert.True(secondRequestBlocked); // Captured before releasing the first request Assert.True(secondRequestSent); // Validate that header was seen // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void Abort_During_Implicit_Open_Closes_Async_Waiters() { // This test is a regression test of an issue with CallOnceManager. // When a single proxy is used to make several service calls without // explicitly opening it, the CallOnceManager queues up all the requests // that happen while it is opening the channel (or handling previously // queued service calls. If the channel was closed or faulted during // the handling of any queued requests, it caused a pathological worst // case where every queued request waited for its complete SendTimeout // before failing. // // This test operates by making multiple concurrent asynchronous service // calls, but stalls the Opening event to allow them to be queued before // any of them are allowed to proceed. It then closes the channel when // the first service operation is allowed to proceed. This causes the // CallOnce manager to deal with all its queued operations and cause // them to complete other than by timing out. BasicHttpBinding binding = null; ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; int timeoutMs = 20000; long operationsQueued = 0; int operationCount = 5; Task <string>[] tasks = new Task <string> [operationCount]; Exception[] exceptions = new Exception[operationCount]; string[] results = new string[operationCount]; bool isClosed = false; DateTime endOfOpeningStall = DateTime.Now; int serverDelayMs = 100; TimeSpan serverDelayTimeSpan = TimeSpan.FromMilliseconds(serverDelayMs); string testMessage = "testMessage"; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.TransferMode = TransferMode.Streamed; // SendTimeout is the timeout used for implicit opens binding.SendTimeout = TimeSpan.FromMilliseconds(timeoutMs); factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); serviceProxy = factory.CreateChannel(); // Force the implicit open to stall until we have multiple concurrent calls pending. // This forces the CallOnceManager to have a queue of waiters it will need to notify. ((ICommunicationObject)serviceProxy).Opening += (s, e) => { // Wait until we see sync calls have been queued DateTime startOfOpeningStall = DateTime.Now; while (true) { endOfOpeningStall = DateTime.Now; // Don't wait forever -- if we stall longer than the SendTimeout, it means something // is wrong other than what we are testing, so just fail early. if ((endOfOpeningStall - startOfOpeningStall).TotalMilliseconds > timeoutMs) { Assert.True(false, "The Opening event timed out waiting for operations to queue, which was not expected for this test."); } // As soon as we have all our Tasks at least running, wait a little // longer to allow them finish queuing up their waiters, then stop stalling the Opening if (Interlocked.Read(ref operationsQueued) >= operationCount) { Task.Delay(500).Wait(); endOfOpeningStall = DateTime.Now; return; } Task.Delay(100).Wait(); } }; // Each task will make a synchronous service call, which will cause all but the // first to be queued for the implicit open. The first call to complete then closes // the channel so that it is forced to deal with queued waiters. Func <string> callFunc = () => { // We increment the # ops queued before making the actual sync call, which is // technically a short race condition in the test. But reversing the order would // timeout the implicit open and fault the channel. Interlocked.Increment(ref operationsQueued); // The call of the operation is what creates the entry in the CallOnceManager queue. // So as each Task below starts, it increments the count and adds a waiter to the // queue. We ask for a small delay on the server side just to introduce a small // stall after the sync request has been made before it can complete. Otherwise // fast machines can finish all the requests before the first one finishes the Close(). Task <string> t = serviceProxy.EchoWithTimeoutAsync(testMessage, serverDelayTimeSpan); lock (tasks) { if (!isClosed) { try { isClosed = true; ((ICommunicationObject)serviceProxy).Abort(); } catch { } } } return(t.GetAwaiter().GetResult()); }; // *** EXECUTE *** \\ DateTime startTime = DateTime.Now; for (int i = 0; i < operationCount; ++i) { tasks[i] = Task.Run(callFunc); } for (int i = 0; i < operationCount; ++i) { try { results[i] = tasks[i].GetAwaiter().GetResult(); } catch (Exception ex) { exceptions[i] = ex; } } // *** VALIDATE *** \\ double elapsedMs = (DateTime.Now - endOfOpeningStall).TotalMilliseconds; // Before validating that the issue was fixed, first validate that we received the exceptions or the // results we expected. This is to verify the fix did not introduce a behavioral change other than the // elimination of the long unnecessary timeouts after the channel was closed. int nFailures = 0; for (int i = 0; i < operationCount; ++i) { if (exceptions[i] == null) { Assert.True((String.Equals("test", results[i])), String.Format("Expected operation #{0} to return '{1}' but actual was '{2}'", i, testMessage, results[i])); } else { ++nFailures; TimeoutException toe = exceptions[i] as TimeoutException; Assert.True(toe == null, String.Format("Task [{0}] should not have failed with TimeoutException", i)); } } Assert.True(nFailures > 0, String.Format("Expected at least one operation to throw an exception, but none did. Elapsed time = {0} ms.", elapsedMs)); // --- Here is the test of the actual bug fix --- // The original issue was that sync waiters in the CallOnceManager were not notified when // the channel became unusable and therefore continued to time out for the full amount. // Additionally, because they were executed sequentially, it was also possible for each one // to time out for the full amount. Given that we closed the channel, we expect all the queued // waiters to have been immediately waked up and detected failure. int expectedElapsedMs = (operationCount * serverDelayMs) + timeoutMs / 2; Assert.True(elapsedMs < expectedElapsedMs, String.Format("The {0} operations took {1} ms to complete which exceeds the expected {2} ms", operationCount, elapsedMs, expectedElapsedMs)); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static async Task ResendFailedRequest(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; NetHttpBinding binding = null; try { // *** SETUP *** \\ binding = new NetHttpBinding(BasicHttpSecurityMode.None, true); binding.ReliableSession.Ordered = ordered; var customBinding = new CustomBinding(binding); var reliableSessionBindingElement = customBinding.Elements.Find <ReliableSessionBindingElement>(); reliableSessionBindingElement.ReliableMessagingVersion = rmVersion; factory = new ChannelFactory <IWcfReliableService>(customBinding, new EndpointAddress(Endpoints.ReliableSession_NetHttp + endpointSuffix)); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); bool delayNextCall = false; int callCount = 0; TaskCompletionSource <object> tcs1 = null, tcs2 = null; handlerFactoryBehavior.OnSendingAsync = async(request, token) => { Interlocked.Increment(ref callCount); // Once the delayNextCall latch is set, the next call will be held back until after // it has been retried. if (delayNextCall) { delayNextCall = false; tcs1 = new TaskCompletionSource <object>(); await tcs1.Task; } return(null); }; handlerFactoryBehavior.OnSentAsync = (response, token) => { if (tcs2 != null) { // Let the main test code know that the original held back call has returned from the service tcs2.TrySetResult(null); } if (tcs1 != null) { // This is the retry of the first service call. Release the held back initial call tcs1.TrySetResult(null); tcs1 = null; tcs2 = new TaskCompletionSource <object>(); } return(Task.FromResult(response)); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ ((IClientChannel)serviceProxy).Open(); // This will establish a reliable session delayNextCall = true; // Reset call count as it would have incremented in the session open handshake callCount = 0; var result1 = await serviceProxy.GetNextNumberAsync(); // Wait for the first attempt for first call to complete before making second call await tcs2.Task; // This check ensures that the sequence number on the retry was the same as the original. If they // were different, the call on the retry would have been dispatched on the service and an extra // increment would have happened. var result2 = await serviceProxy.GetNextNumberAsync(); // *** VALIDATE *** \\ Assert.Equal(1, result1); Assert.Equal(2, result2); // Validate that 3 http calls were made as first call should have retried. Assert.Equal(3, callCount); // *** CLEANUP *** \\ ((IClientChannel)serviceProxy).Close(); factory.Close(); ((ICommunicationObject)serviceProxy).Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void WebSocket_Https_Duplex_Buffered(NetHttpMessageEncoding messageEncoding) { EndpointAddress endpointAddress; NetHttpsBinding binding = null; ClientReceiver clientReceiver = null; InstanceContext context = null; DuplexChannelFactory <IWSDuplexService> channelFactory = null; IWSDuplexService client = null; try { // *** SETUP *** \\ binding = new NetHttpsBinding() { MaxReceivedMessageSize = ScenarioTestHelpers.SixtyFourMB, MaxBufferSize = ScenarioTestHelpers.SixtyFourMB, }; binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; binding.TransferMode = TransferMode.Buffered; binding.MessageEncoding = messageEncoding; clientReceiver = new ClientReceiver(); context = new InstanceContext(clientReceiver); endpointAddress = new EndpointAddress(Endpoints.WebSocketHttpsDuplexBuffered_Address + Enum.GetName(typeof(NetHttpMessageEncoding), messageEncoding)); channelFactory = new DuplexChannelFactory <IWSDuplexService>(context, binding, endpointAddress); client = channelFactory.CreateChannel(); // *** EXECUTE *** \\ // Invoking UploadData client.UploadData(ScenarioTestHelpers.CreateInterestingString(123)); // Invoking StartPushingData client.StartPushingData(); Assert.True(clientReceiver.ReceiveDataInvoked.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the buffered response from the Service. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveDataInvoked.Reset(); // Invoking StopPushingData client.StopPushingData(); Assert.True(clientReceiver.ReceiveDataCompleted.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the buffered response from the Service to be completed. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); clientReceiver.ReceiveDataCompleted.Reset(); // Getting results from server via callback. client.GetLog(); Assert.True(clientReceiver.LogReceived.WaitOne(ScenarioTestHelpers.TestTimeout), String.Format("Test case timeout was reached while waiting for the Logging from the Service to be received. Timeout was: {0}", ScenarioTestHelpers.TestTimeout)); // *** VALIDATE *** \\ Assert.True(clientReceiver.ServerLog.Count > 0, "The logging done by the Server was not returned via the Callback."); // *** CLEANUP *** \\ ((ICommunicationObject)client).Close(); channelFactory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)client, channelFactory); } }
public static void BasicHttp_Async_Close_ChannelFactory_Operations_Active() { // Test creates 2 channels from a single channel factory and // asynchronously closes the channel factory while both channels are // executing operations. This verifies the operations are cancelled and // the channel factory is in the correct state. BasicHttpBinding binding = null; TimeSpan delayOperation = TimeSpan.FromSeconds(3); ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy1 = null; IWcfService serviceProxy2 = null; string expectedEcho1 = "first"; string expectedEcho2 = "second"; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.CloseTimeout = ScenarioTestHelpers.TestTimeout; binding.SendTimeout = ScenarioTestHelpers.TestTimeout; factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic)); serviceProxy1 = factory.CreateChannel(); serviceProxy2 = factory.CreateChannel(); // *** EXECUTE *** \\ Task <string> t1 = serviceProxy1.EchoWithTimeoutAsync(expectedEcho1, delayOperation); Task <string> t2 = serviceProxy2.EchoWithTimeoutAsync(expectedEcho2, delayOperation); Task factoryTask = Task.Factory.FromAsync(factory.BeginClose, factory.EndClose, TaskCreationOptions.None); // *** VALIDATE *** \\ factoryTask.GetAwaiter().GetResult(); Assert.True(factory.State == CommunicationState.Closed, String.Format("Expected factory state 'Closed', actual was '{0}'", factory.State)); Exception exception1 = null; Exception exception2 = null; string actualEcho1 = null; string actualEcho2 = null; // Verification is slightly more complex for the close with active operations because // we don't know which might have completed first and whether the channel factory // was able to close and dispose either channel before it completed. So we just // ensure the Tasks complete with an exception or a successful return and have // been closed by the factory. try { actualEcho1 = t1.GetAwaiter().GetResult(); } catch (Exception e) { exception1 = e; } try { actualEcho2 = t2.GetAwaiter().GetResult(); } catch (Exception e) { exception2 = e; } Assert.True(exception1 != null || actualEcho1 != null, "First operation should have thrown Exception or returned an echo"); Assert.True(exception2 != null || actualEcho2 != null, "Second operation should have thrown Exception or returned an echo"); Assert.True(actualEcho1 == null || String.Equals(expectedEcho1, actualEcho1), String.Format("First operation returned '{0}' but expected '{1}'.", expectedEcho1, actualEcho1)); Assert.True(actualEcho2 == null || String.Equals(expectedEcho2, actualEcho2), String.Format("Second operation returned '{0}' but expected '{1}'.", expectedEcho2, actualEcho2)); Assert.True(((ICommunicationObject)serviceProxy1).State == CommunicationState.Closed, String.Format("Expected channel 1 state 'Closed', actual was '{0}'", ((ICommunicationObject)serviceProxy1).State)); Assert.True(((ICommunicationObject)serviceProxy2).State == CommunicationState.Closed, String.Format("Expected channel 2 state 'Closed', actual was '{0}'", ((ICommunicationObject)serviceProxy2).State)); // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy1).Abort(); ((ICommunicationObject)serviceProxy2).Abort(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy1, (ICommunicationObject)serviceProxy2, factory); } }