private static TSoapClient GetChannelFactory <TSoapClient>(string endpointAddress, bool auth = false, string username = null, string password = null, string domain = null) { var mustUseHttpsBinding = endpointAddress.IndexOf("https", StringComparison.InvariantCultureIgnoreCase) != -1; ChannelFactory <TSoapClient> channelFactory = null; if (mustUseHttpsBinding) { channelFactory = new ChannelFactory <TSoapClient>(GetHttpsBinding(), GetEndpoint(endpointAddress)); } else { channelFactory = new ChannelFactory <TSoapClient>(GetHttpBinding(), GetEndpoint(endpointAddress)); } if (auth) { channelFactory.Credentials.Windows.ClientCredential = GetCredentials(username, password, domain); } var handlerFactoryBehavior = new HttpMessageHandlerBehavior { OnSending = (message, token) => { message.Headers.ExpectContinue = false; return(null); } }; channelFactory.Endpoint.EndpointBehaviors.Add(handlerFactoryBehavior); return(channelFactory.CreateChannel()); }
public static void HttpMessageHandlerFactory_ModifyContent_Success(WSMessageEncoding messageEncoding) { ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; string testString = "Hello"; string substituteString = "World"; BasicHttpBinding binding = null; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.MessageEncoding = messageEncoding; factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic + Enum.GetName(typeof(WSMessageEncoding), messageEncoding))); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); handlerFactoryBehavior.OnSendingAsync = (message, token) => { var oldContent = message.Content; string requestMessageBody = oldContent.ReadAsStringAsync().Result; requestMessageBody = requestMessageBody.Replace(testString, substituteString); message.Content = new StringContent(requestMessageBody); foreach (var header in oldContent.Headers) { if (!header.Key.Equals("Content-Length") && message.Content.Headers.Contains(header.Key)) { message.Content.Headers.Remove(header.Key); } message.Content.Headers.Add(header.Key, header.Value); } return(Task.FromResult((HttpResponseMessage)null)); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo("Hello"); // *** VALIDATE *** \\ Assert.True(result == substituteString, String.Format("Error: expected response from service: '{0}' Actual was: '{1}'", testString, result)); // *** CLEANUP *** \\ factory.Close(); ((ICommunicationObject)serviceProxy).Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static async Task InactivityTimeoutApplied(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; WSHttpBinding binding = null; TimeSpan keepAliveInterval = TimeSpan.FromSeconds(2); try { // *** SETUP *** \\ binding = new WSHttpBinding(SecurityMode.None, true); binding.ReliableSession.Ordered = ordered; var customBinding = new CustomBinding(binding); var reliableSessionBindingElement = customBinding.Elements.Find <ReliableSessionBindingElement>(); // Keepalive is sent after half the inactivity timeout duration has passed reliableSessionBindingElement.InactivityTimeout = keepAliveInterval * 2; reliableSessionBindingElement.ReliableMessagingVersion = rmVersion; factory = new ChannelFactory <IWcfReliableService>(customBinding, new EndpointAddress(Endpoints.ReliableSession_WSHttp + endpointSuffix)); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); int httpRequestCount = 0; handlerFactoryBehavior.OnSendingAsync = (request, token) => { Interlocked.Increment(ref httpRequestCount); return(Task.FromResult <HttpResponseMessage>(null)); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ ((IClientChannel)serviceProxy).Open(); // This will establish a reliable session var result1 = await serviceProxy.GetNextNumberAsync(); httpRequestCount = 0; // Wait a little longer than (inactivity timeout / 2) to allow a keepalive request await Task.Delay(keepAliveInterval * 1.1); int httpRequestCountAfterInactivity = httpRequestCount; // *** VALIDATE *** \\ Assert.Equal(1, result1); Assert.Equal(1, httpRequestCountAfterInactivity); // Captured before releasing the first request // *** CLEANUP *** \\ ((ICommunicationObject)serviceProxy).Close(); factory.Close(); } finally { // *** ENSURE CLEANUP *** \\ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); } }
public static void HttpMessageHandlerFactory_Success(WSMessageEncoding messageEncoding) { ChannelFactory <IWcfService> factory = null; IWcfService serviceProxy = null; string testString = "Hello"; BasicHttpBinding binding = null; try { // *** SETUP *** \\ binding = new BasicHttpBinding(BasicHttpSecurityMode.None); binding.MessageEncoding = messageEncoding; factory = new ChannelFactory <IWcfService>(binding, new EndpointAddress(Endpoints.HttpBaseAddress_Basic + Enum.GetName(typeof(WSMessageEncoding), messageEncoding))); var handlerFactoryBehavior = new HttpMessageHandlerBehavior(); bool handlerCalled = false; handlerFactoryBehavior.OnSendingAsync = (message, token) => { handlerCalled = true; return(Task.FromResult((HttpResponseMessage)null)); }; factory.Endpoint.Behaviors.Add(handlerFactoryBehavior); serviceProxy = factory.CreateChannel(); // *** EXECUTE *** \\ string result = serviceProxy.Echo("Hello"); // *** VALIDATE *** \\ Assert.True(handlerCalled, "Error: expected client to call intercepting handler"); Assert.True(result == testString, String.Format("Error: expected response from service: '{0}' Actual was: '{1}'", testString, result)); // *** CLEANUP *** \\ factory.Close(); ((ICommunicationObject)serviceProxy).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; WSHttpBinding binding = null; try { // *** SETUP *** \\ binding = new WSHttpBinding(SecurityMode.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_WSHttp + 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 async Task MaxTransferWindowSizeApplied(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; WSHttpBinding binding = null; string secondRequestHeaderName = "SecondRequest"; try { // *** SETUP *** \\ binding = new WSHttpBinding(SecurityMode.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_WSHttp + 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 async Task RetryCountApplied(ReliableMessagingVersion rmVersion, bool ordered, string endpointSuffix) { ChannelFactory <IWcfReliableService> factory = null; IWcfReliableService serviceProxy = null; WSHttpBinding binding = null; try { // *** SETUP *** \\ binding = new WSHttpBinding(SecurityMode.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_WSHttp + 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); } }
/// <summary> /// Initializes a new instance of the <see cref="InterceptingHttpMessageHandler"/> class. /// </summary> /// <param name="innerHandler"></param> /// <param name="parent"></param> public InterceptingHttpMessageHandler(HttpMessageHandler innerHandler, HttpMessageHandlerBehavior parent) { InnerHandler = innerHandler; this.parent = parent; }