diff --git a/.semver b/.semver index 6520791..4b3e029 100644 --- a/.semver +++ b/.semver @@ -1,5 +1,5 @@ --- :major: 2 -:minor: 0 -:patch: 9 +:minor: 1 +:patch: 0 :special: '' diff --git a/README.md b/README.md index 5e4119d..6cfd71b 100644 --- a/README.md +++ b/README.md @@ -83,18 +83,34 @@ Exposes the full configuration available. See the [Configuration](#configuration Async Support ------------- -WCF service contract interfaces that define task based async methods will automatically work with the .NET 4.5 async/await support. +At runtime, generating the proxy will ensure that all non-async operation contract methods have an associated Async implementation. What this means is that if your service contract is defined as: - var proxy = WcfClientProxy.Create(); - int result = await proxy.MakeCallAsync("test"); + [ServiceContract] + interface IService + { + [OperationContract] + int MakeCall(string input); + } -Service contracts that don't define task based methods can be used in an async/await fashion by calling the `WcfClientProxy.CreateAsyncProxy()` method. This call returns a type `IAsyncProxy` that exposes a `CallAsync()` method. +then the proxy returned by calling `WcfClientProxy.Create()` will automatically define a `Task MakeCallAsync(string input)` operation contract method at runtime. + +To utilize this runtime generated async method, an async friendly wrapped proxy can be generated by calling the `WcfClientProxy.CreateAsyncProxy()` method. This call returns a type `IAsyncProxy` that exposes a `CallAsync()` method. -For example, a service contract interface with method `int MakeCall(string input)` can be called asynchronously like: +The `int MakeCall(string input)` method can now be called asynchronously like: var proxy = WcfClientProxy.CreateAsyncProxy(); int result = await proxy.CallAsync(s => s.MakeCall("test")); +It is also possible to call into the runtime generated Async methods dynamically without use of the `IAsyncProxy` wrapper. For example, the same service contract interface with the non-async method defined can be called asynchronously as so: + + var proxy = WcfClientProxy.Create(); + int result = await ((dynamic) proxy).MakeCallAsync("test"); + +WCF service contract interfaces that define task based async methods at compile will automatically work with the C# 5 async/await support. + + var proxy = WcfClientProxy.Create(); + int result = await proxy.MakeCallAsync("test"); + ### Async Limitations Methods that define `out` or `ref` parameters are not supported when making async/await calls. Attempts to make async calls using a proxy with these parameter types will result in a runtime exception being thrown. @@ -128,12 +144,54 @@ will configure the proxy based on the `` as setup in the _app.config_ #### SetEndpoint(Binding binding, EndpointAddress endpointAddress) Configures the proxy to communicate with the endpoint using the given `binding` at the `endpointAddress` +#### HandleRequestArgument\(Func\ where, Action\ handler) +_overload:_ `HandleRequestArgument(Func where, Func handler)` + +Sets up the proxy to run handlers on argument values that are used for making WCF requests. An example use case would be to inject authentication keys into all requests where an argument value matches expectation. + +The `TArgument` value can be a type as specific or general as needed. For example, configuring the proxy to handle the `object` type will result in the handler being run for all operation contract arguments, whereas configuring with a sealed type will result in only those types being handled. + +This example sets the `AccessKey` property for all requests inheriting from `IAuthenticatedRequest`: + + var proxy = WcfClientProxy.Create(c => + { + c.HandleRequestArgument(req => + { + req.AccessKey = "..."; + }); + }); + +The `where` condition takes the request object as its first parameter and the actual name of the operation contract parameter secondly. This allows for conditional handling of non-specific types based on naming conventions. + +For example, a service contract defined as: + + [ServiceContract] + public interface IAuthenticatedService + { + [OperationContract] + void OperationOne(string accessKey, string input); + + [OperationContract] + void OperationTwo(string accessKey, string anotherInput); + } + +can have the `accessKey` parameter automatically filled in with the following proxy configuration: + + var proxy = WcfClientProxy.Create(c => + { + c.HandleRequestArgument( + where: (req, paramName) => paramName == "accessKey", + handler: req => "access key value"); + }); + +the proxy can now be called with with any value in the `accessKey` parameter (e.g. `proxy.OperationOne(null, "input value")` and before the request is actually started, the `accessKey` value will be swapped out with `access key value`. + #### HandleResponse\(Predicate\ where, Action\ handler) _overload:_ `HandleResponse(Predicate where, Func handler)` Sets up the proxy to allow inspection and manipulation of responses from the service. -The `TResponse` value can be a type as specific or general as needed. For instance, `c.HandleResponse(...)` will only handle responses of type `SealedResponseType` whereas `c.HandleResponse(...)` will be fired for all responses. +Similar to `HandleRequestArgument`, the `TResponse` value can be a type as specific or general as needed. For instance, `c.HandleResponse(...)` will only handle responses of type `SealedResponseType` whereas `c.HandleResponse(...)` will be fired for all responses. For example, if sensitive information is needed to be stripped out of certain response messages, `HandleResponse` can be used to do this. diff --git a/source/WcfClientProxyGenerator.Tests/Infrastructure/ITestService.cs b/source/WcfClientProxyGenerator.Tests/Infrastructure/ITestService.cs index a5476c5..945b67b 100644 --- a/source/WcfClientProxyGenerator.Tests/Infrastructure/ITestService.cs +++ b/source/WcfClientProxyGenerator.Tests/Infrastructure/ITestService.cs @@ -12,6 +12,9 @@ public interface ITestService [OperationContract(Name = "TestMethod2")] string TestMethod(string input, string two); + [OperationContract] + int TestMethodMixed(string input, int input2); + [OperationContract] void VoidMethod(string input); diff --git a/source/WcfClientProxyGenerator.Tests/Infrastructure/TestServiceImpl.cs b/source/WcfClientProxyGenerator.Tests/Infrastructure/TestServiceImpl.cs index b9b7b02..ff8b2be 100644 --- a/source/WcfClientProxyGenerator.Tests/Infrastructure/TestServiceImpl.cs +++ b/source/WcfClientProxyGenerator.Tests/Infrastructure/TestServiceImpl.cs @@ -37,6 +37,14 @@ public string TestMethod(string input, string two) return string.Format("Echo: {0}, {1}", input, two); } + public int TestMethodMixed(string input, int input2) + { + if (_mock != null) + return _mock.Object.TestMethodMixed(input, input2); + + return input2; + } + public void VoidMethod(string input) { if (_mock != null) diff --git a/source/WcfClientProxyGenerator.Tests/ProxyTests.cs b/source/WcfClientProxyGenerator.Tests/ProxyTests.cs index 94dc918..eaea219 100644 --- a/source/WcfClientProxyGenerator.Tests/ProxyTests.cs +++ b/source/WcfClientProxyGenerator.Tests/ProxyTests.cs @@ -1243,6 +1243,112 @@ public void Proxy_ChannelFactory_UsesConfiguredEndpoint() #endregion + #region HandleRequestArgument + + [Test] + public void HandleRequestArgument_ModifiesComplexRequest_BeforeSendingToService() + { + var mockService = new Mock(); + mockService + .Setup(m => m.TestMethodComplex(It.IsAny())) + .Returns((Request r) => new Response + { + ResponseMessage = r.RequestMessage + }); + + var serviceHost = InProcTestFactory.CreateHost(new TestServiceImpl(mockService)); + + var proxy = WcfClientProxy.Create(c => + { + c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress); + c.HandleRequestArgument( + where: (arg, param) => arg == null, + handler: arg => + { + return new Request + { + RequestMessage = "default message" + }; + }); + }); + + proxy.TestMethodComplex(null); + mockService + .Verify(m => m.TestMethodComplex(It.Is(r => r.RequestMessage == "default message")), Times.Once()); + + proxy.TestMethodComplex(new Request { RequestMessage = "set" }); + mockService + .Verify(m => m.TestMethodComplex(It.Is(r => r.RequestMessage == "set")), Times.Once()); + } + + [Test] + public void HandleRequestArgument_MatchesArgumentsOfSameType_BasedOnParameterName() + { + var mockService = new Mock(); + mockService + .Setup(m => m.TestMethod(It.IsAny() /* input */, It.IsAny() /* two */)) + .Returns("response"); + + var serviceHost = InProcTestFactory.CreateHost(new TestServiceImpl(mockService)); + + var proxy = WcfClientProxy.Create(c => + { + c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress); + + c.HandleRequestArgument( + where: (arg, paramName) => paramName == "input", + handler: arg => + { + return "always input"; + }); + + c.HandleRequestArgument( + where: (arg, paramName) => paramName == "two", + handler: arg => + { + return "always two"; + }); + }); + + proxy.TestMethod("first argument", "second argument"); + + mockService + .Verify(m => m.TestMethod("always input", "always two"), Times.Once()); + } + + [Test] + public void HandleRequestArgument_MatchesArgumentsByBaseTypes() + { + int handleRequestArgumentCounter = 0; + + var mockService = new Mock(); + mockService + .Setup(m => m.TestMethodMixed(It.IsAny(), It.IsAny())) + .Returns(10); + + var serviceHost = InProcTestFactory.CreateHost(new TestServiceImpl(mockService)); + + var proxy = WcfClientProxy.Create(c => + { + c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress); + + c.HandleRequestArgument( + handler: arg => + { + handleRequestArgumentCounter++; + }); + }); + + proxy.TestMethodMixed("first argument", 100); + + mockService + .Verify(m => m.TestMethodMixed("first argument", 100), Times.Once()); + + Assert.That(handleRequestArgumentCounter, Is.EqualTo(2)); + } + + #endregion + #region HandleResponse [Test] @@ -1717,6 +1823,51 @@ public async Task Async_HandleResponse_ActionWithoutPredicate_CanInspectResponse #endregion + #region Dynamic Async Invocation + + [Test] + public async Task Async_DynamicConversion_Proxy_ReturnsExpectedValue_WhenCallingGeneratedAsyncMethod() + { + var mockService = new Mock(); + mockService.Setup(m => m.TestMethod("good")).Returns("OK"); + + var serviceHost = InProcTestFactory.CreateHost(new TestServiceImpl(mockService)); + + var proxy = WcfClientProxy.Create(c => c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress)); + + // ITestService does not define TestMethodAsync, it's generated at runtime + var result = await ((dynamic) proxy).TestMethodAsync("good"); + + Assert.AreEqual("OK", result); + } + + [Test] + public async Task Async_DynamicConversion_Proxy_CanCallGeneratedAsyncVoidMethod() + { + var resetEvent = new AutoResetEvent(false); + + var mockService = new Mock(); + mockService + .Setup(m => m.VoidMethod("good")) + .Callback(input => + { + Assert.That(input, Is.EqualTo("good")); + resetEvent.Set(); + }); + + var serviceHost = InProcTestFactory.CreateHost(new TestServiceImpl(mockService)); + + var proxy = WcfClientProxy.Create(c => c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress)); + + // ITestService does not define VoidMethodAsync, it's generated at runtime + await ((dynamic) proxy).VoidMethodAsync("good"); + + if (!resetEvent.WaitOne(300)) + Assert.Fail("Timeout occurred when waiting for callback"); + } + + #endregion + #region Better error messages tests [ServiceContract] diff --git a/source/WcfClientProxyGenerator/DynamicProxyTypeGenerator.cs b/source/WcfClientProxyGenerator/DynamicProxyTypeGenerator.cs index a7615e7..a17405d 100644 --- a/source/WcfClientProxyGenerator/DynamicProxyTypeGenerator.cs +++ b/source/WcfClientProxyGenerator/DynamicProxyTypeGenerator.cs @@ -241,7 +241,11 @@ private static void GenerateAsyncTaskMethod( MethodInfo methodInfo, TypeBuilder typeBuilder) { - var parameterTypes = methodInfo.GetParameters() + var parameters = methodInfo + .GetParameters() + .ToArray(); + + var parameterTypes = parameters .Select(m => m.ParameterType) .ToArray(); @@ -266,8 +270,8 @@ private static void GenerateAsyncTaskMethod( parameterTypes); for (int i = 1; i <= parameterTypes.Length; i++) - methodBuilder.DefineParameter(i, ParameterAttributes.None, "arg" + i); - + methodBuilder.DefineParameter(i, ParameterAttributes.None, parameters[i-1].Name); + var originalOperationContract = methodInfo.GetCustomAttribute(); var attributeCtor = typeof(OperationContractAttribute) @@ -324,7 +328,11 @@ private static void GenerateServiceProxyMethod( MethodInfo methodInfo, TypeBuilder typeBuilder) { - var parameterTypes = methodInfo.GetParameters() + var parameters = methodInfo + .GetParameters() + .ToArray(); + + var parameterTypes = parameters .Select(m => m.ParameterType) .ToArray(); @@ -335,8 +343,8 @@ private static void GenerateServiceProxyMethod( methodInfo.ReturnType, parameterTypes); - for (int i = 1; i <= parameterTypes.Length; i++) - methodBuilder.DefineParameter(i, ParameterAttributes.None, "arg" + i); + for (int i = 1; i <= parameters.Length; i++) + methodBuilder.DefineParameter(i, ParameterAttributes.None, parameters[i-1].Name); Type serviceCallWrapperType; var serviceCallWrapperFields = GenerateServiceCallWrapperType( @@ -380,6 +388,24 @@ private static void GenerateServiceProxyMethod( if (serviceCallWrapperCtor == null) throw new Exception("Parameterless constructor not found for type: " + serviceCallWrapperType); + for (int i = 0; i < parameterTypes.Length; i++) + { + Type parameterType = parameterTypes[i]; + if (parameterType.IsByRef) + continue; + + var handleRequestParameterMethod = typeof(RetryingWcfActionInvokerProvider<>) + .MakeGenericType(asyncInterfaceType) + .GetMethod("HandleRequestArgument", BindingFlags.Instance | BindingFlags.NonPublic) + .MakeGenericMethod(parameterType); + + ilGenerator.Emit(OpCodes.Ldarg, 0); + ilGenerator.Emit(OpCodes.Ldarg, i + 1); + ilGenerator.Emit(OpCodes.Ldstr, parameters[i].Name); + ilGenerator.Emit(OpCodes.Call, handleRequestParameterMethod); + ilGenerator.Emit(OpCodes.Starg_S, i + 1); + } + // local2 = new MethodType(); ilGenerator.Emit(OpCodes.Newobj, serviceCallWrapperCtor); ilGenerator.Emit(OpCodes.Stloc_2); diff --git a/source/WcfClientProxyGenerator/IProxyConfigurator.cs b/source/WcfClientProxyGenerator/IProxyConfigurator.cs index f539f0f..6f174c4 100644 --- a/source/WcfClientProxyGenerator/IProxyConfigurator.cs +++ b/source/WcfClientProxyGenerator/IProxyConfigurator.cs @@ -62,6 +62,42 @@ public interface IProxyConfigurator /// ChannelFactory ChannelFactory { get; } + #region HandleRequestArgument + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Predicate to filter the request arguments by properties of the request, or the parameter name + /// Delegate that takes a + void HandleRequestArgument(Func where, Action handler); + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Delegate that takes a + void HandleRequestArgument(Action handler); + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Predicate to filter the request arguments by properties of the request, or the parameter name + /// Delegate that takes a and returns a + void HandleRequestArgument(Func where, Func handler); + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Delegate that takes a and returns a + void HandleRequestArgument(Func handler); + + #endregion + + #region HandleResponse + /// /// Allows inspecting and modifying the object /// before returning the response to the calling method. @@ -103,5 +139,7 @@ public interface IProxyConfigurator /// Delegate that takes a and returns a /// void HandleResponse(Func handler); + + #endregion } } \ No newline at end of file diff --git a/source/WcfClientProxyGenerator/RetryingWcfActionInvoker.cs b/source/WcfClientProxyGenerator/RetryingWcfActionInvoker.cs index 960f9b1..e6e592a 100644 --- a/source/WcfClientProxyGenerator/RetryingWcfActionInvoker.cs +++ b/source/WcfClientProxyGenerator/RetryingWcfActionInvoker.cs @@ -15,12 +15,6 @@ namespace WcfClientProxyGenerator { - class ResponseHandlerHolder - { - public object Predicate { get; set; } - public object ResponseHandler { get; set; } - } - internal class RetryingWcfActionInvoker : IActionInvoker where TServiceInterface : class { @@ -39,7 +33,7 @@ private static ConcurrentDictionary> ResponseHandlerCache private readonly Type _originalServiceInterfaceType; private readonly IDictionary> _retryPredicates; - private readonly IDictionary> _responseHandlers; + private readonly IDictionary> _responseHandlers; /// /// The method that initializes new WCF action providers @@ -63,7 +57,7 @@ public RetryingWcfActionInvoker( { typeof(ServerTooBusyException), new List { null } } }; - _responseHandlers = new Dictionary>(); + _responseHandlers = new Dictionary>(); _originalServiceInterfaceType = GetOriginalServiceInterface(); } @@ -143,12 +137,12 @@ public void AddResponseToRetryOn(Predicate where) public void AddResponseHandler(Func handler, Predicate @where) { if (!_responseHandlers.ContainsKey(typeof(TResponse))) - _responseHandlers.Add(typeof(TResponse), new List()); + _responseHandlers.Add(typeof(TResponse), new List()); - _responseHandlers[typeof(TResponse)].Add(new ResponseHandlerHolder + _responseHandlers[typeof(TResponse)].Add(new PredicateHandlerHolder { Predicate = @where, - ResponseHandler = handler + Handler = handler }); } @@ -450,7 +444,7 @@ private TResponse ExecuteResponseHandlers(TResponse response, Type ty if (!this._responseHandlers.ContainsKey(@type)) return response; - IList responseHandlerHolders = this._responseHandlers[@type]; + IList responseHandlerHolders = this._responseHandlers[@type]; MethodInfo predicateInvokeMethod = ResponseHandlerPredicateCache.GetOrAddSafe(@type, _ => { @@ -476,7 +470,7 @@ private TResponse ExecuteResponseHandlers(TResponse response, Type ty { try { - response = (TResponse) handlerMethod.Invoke(handler.ResponseHandler, new object[] { response }); + response = (TResponse) handlerMethod.Invoke(handler.Handler, new object[] { response }); } catch (TargetInvocationException ex) { diff --git a/source/WcfClientProxyGenerator/RetryingWcfActionInvokerProvider.cs b/source/WcfClientProxyGenerator/RetryingWcfActionInvokerProvider.cs index 8549f69..9b9ebab 100644 --- a/source/WcfClientProxyGenerator/RetryingWcfActionInvokerProvider.cs +++ b/source/WcfClientProxyGenerator/RetryingWcfActionInvokerProvider.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; @@ -8,30 +11,182 @@ namespace WcfClientProxyGenerator { + class PredicateHandlerHolder + { + public object Predicate { get; set; } + public object Handler { get; set; } + } + internal class RetryingWcfActionInvokerProvider : IActionInvokerProvider, IRetryingProxyConfigurator where TServiceInterface : class { - private ChannelFactory _channelFactory; - private readonly RetryingWcfActionInvoker _actionInvoker; + private static ConcurrentDictionary>> TypeHierarchyCache + = new ConcurrentDictionary>>(); + + private static ConcurrentDictionary> RequestParameterHandlerPredicateCache + = new ConcurrentDictionary>(); + + private static ConcurrentDictionary> RequestParameterHandlerCache + = new ConcurrentDictionary>(); + + private ChannelFactory channelFactory; + private readonly RetryingWcfActionInvoker actionInvoker; + + private readonly IDictionary> requestArgumentHandlers + = new Dictionary>(); public RetryingWcfActionInvokerProvider() { - _actionInvoker = new RetryingWcfActionInvoker(() => + actionInvoker = new RetryingWcfActionInvoker(() => { - if (_channelFactory == null) + if (channelFactory == null) this.UseDefaultEndpoint(); - return _channelFactory.CreateChannel(); + return channelFactory.CreateChannel(); }); } public IActionInvoker ActionInvoker { - get { return _actionInvoker; } + get { return actionInvoker; } + } + + #region HandleRequestArgument + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Predicate to filter the request arguments by properties of the request, or the parameter name + /// Delegate that takes a + public void HandleRequestArgument(Func where, Action handler) + { + this.HandleRequestArgument(where, r => + { + handler(r); + return r; + }); } + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Delegate that takes a + public void HandleRequestArgument(Action handler) + { + this.HandleRequestArgument(null, handler); + } + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Predicate to filter the request arguments by properties of the request, or the parameter name + /// Delegate that takes a and returns a + public void HandleRequestArgument(Func where, Func handler) + { + if (!this.requestArgumentHandlers.ContainsKey(typeof(TArgument))) + this.requestArgumentHandlers.Add(typeof(TArgument), new List()); + + this.requestArgumentHandlers[typeof(TArgument)].Add(new PredicateHandlerHolder + { + Predicate = where, + Handler = handler + }); + } + + /// + /// Allows inspection or modification of request arguments immediately before sending the request. + /// + /// Type or parent type/interface of the argument + /// Delegate that takes a and returns a + public void HandleRequestArgument(Func handler) + { + this.HandleRequestArgument(null, handler); + } + + #region Runtime Handler Resolution + + /// + /// Called into by the dynamically generated proxy + /// + protected TArgument HandleRequestArgument(TArgument argument, string parameterName) + { + // Don't attempt handler resolution if there aren't any registered + if (!this.requestArgumentHandlers.Any()) + return argument; + + argument = ExecuteRequestArgumentHandlers(argument, parameterName); + return argument; + } + + private TArgument ExecuteRequestArgumentHandlers(TArgument requestArgument, string parameterName) + { + Type @type = typeof(TArgument); + var baseTypes = TypeHierarchyCache.GetOrAddSafe(@type, _ => + { + return @type.GetAllInheritedTypes(); + }); + + foreach (var baseType in baseTypes) + requestArgument = this.ExecuteRequestArgumentHandlers(requestArgument, parameterName, baseType); + + return requestArgument; + } + + private TArgument ExecuteRequestArgumentHandlers(TArgument response, string parameterName, Type @type) + { + if (!this.requestArgumentHandlers.ContainsKey(@type)) + return response; + + IList requestParameterHandlerHolders = this.requestArgumentHandlers[@type]; + + MethodInfo predicateInvokeMethod = RequestParameterHandlerPredicateCache.GetOrAddSafe(@type, _ => + { + Type predicateType = typeof(Func<,,>) + .MakeGenericType(@type, typeof(string), typeof(bool)); + + return predicateType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public); + }); + + var handlers = requestParameterHandlerHolders + .Where(m => m.Predicate == null + || ((bool) predicateInvokeMethod.Invoke(m.Predicate, new object[] { response, parameterName }))) + .ToList(); + + if (!handlers.Any()) + return response; + + MethodInfo handlerMethod = RequestParameterHandlerCache.GetOrAddSafe(@type, _ => + { + Type actionType = typeof(Func<,>).MakeGenericType(@type, @type); + return actionType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public); + }); + + foreach (var handler in handlers) + { + try + { + response = (TArgument) handlerMethod.Invoke(handler.Handler, new object[] { response }); + } + catch (TargetInvocationException ex) + { + throw ex.InnerException; + } + } + + return response; + } + + #endregion + + #endregion + + #region HandleResponse + /// /// Allows inspecting and modifying the object /// before returning the response to the calling method. @@ -43,7 +198,7 @@ public IActionInvoker ActionInvoker /// public void HandleResponse(Predicate @where, Action handler) { - _actionInvoker.AddResponseHandler(r => + actionInvoker.AddResponseHandler(r => { handler(r); return r; @@ -60,7 +215,7 @@ public void HandleResponse(Predicate @where, Action public void HandleResponse(Action handler) { - _actionInvoker.AddResponseHandler(r => + actionInvoker.AddResponseHandler(r => { handler(r); return r; @@ -77,7 +232,7 @@ public void HandleResponse(Action handler) /// public void HandleResponse(Func handler) { - _actionInvoker.AddResponseHandler(handler, null); + actionInvoker.AddResponseHandler(handler, null); } /// @@ -91,9 +246,11 @@ public void HandleResponse(Func handler) /// public void HandleResponse(Predicate @where, Func handler) { - _actionInvoker.AddResponseHandler(handler, @where); + actionInvoker.AddResponseHandler(handler, @where); } + #endregion + #region IRetryingProxyConfigurator /// @@ -102,8 +259,8 @@ public void HandleResponse(Predicate @where, Func public event OnCallBeginHandler OnCallBegin { - add { _actionInvoker.OnCallBegin += value; } - remove { _actionInvoker.OnCallBegin -= value; } + add { actionInvoker.OnCallBegin += value; } + remove { actionInvoker.OnCallBegin -= value; } } /// @@ -111,8 +268,8 @@ public event OnCallBeginHandler OnCallBegin /// public event OnCallSuccessHandler OnCallSuccess { - add { _actionInvoker.OnCallSuccess += value; } - remove { _actionInvoker.OnCallSuccess -= value; } + add { actionInvoker.OnCallSuccess += value; } + remove { actionInvoker.OnCallSuccess -= value; } } /// @@ -120,8 +277,8 @@ public event OnCallSuccessHandler OnCallSuccess /// public event OnInvokeHandler OnBeforeInvoke { - add { _actionInvoker.OnBeforeInvoke += value; } - remove { _actionInvoker.OnBeforeInvoke -= value; } + add { actionInvoker.OnBeforeInvoke += value; } + remove { actionInvoker.OnBeforeInvoke -= value; } } /// @@ -129,8 +286,8 @@ public event OnInvokeHandler OnBeforeInvoke /// public event OnInvokeHandler OnAfterInvoke { - add { _actionInvoker.OnAfterInvoke += value; } - remove { _actionInvoker.OnAfterInvoke -= value; } + add { actionInvoker.OnAfterInvoke += value; } + remove { actionInvoker.OnAfterInvoke -= value; } } /// @@ -138,8 +295,8 @@ public event OnInvokeHandler OnAfterInvoke /// public event OnExceptionHandler OnException { - add { _actionInvoker.OnException += value; } - remove { _actionInvoker.OnException -= value; } + add { actionInvoker.OnException += value; } + remove { actionInvoker.OnException -= value; } } /// @@ -150,12 +307,12 @@ public ChannelFactory ChannelFactory get { // if requested without endpoint set, use default - if (_channelFactory == null) + if (channelFactory == null) { UseDefaultEndpoint(); } - return _channelFactory; + return channelFactory; } } @@ -166,11 +323,11 @@ public void UseDefaultEndpoint() if (typeof(TServiceInterface).GetCustomAttribute() != null) { Type originalServiceInterfaceType = typeof(TServiceInterface).GetInterfaces()[0]; - _channelFactory = ChannelFactoryProvider.GetChannelFactory(originalServiceInterfaceType); + channelFactory = ChannelFactoryProvider.GetChannelFactory(originalServiceInterfaceType); } else { - _channelFactory = ChannelFactoryProvider.GetChannelFactory(typeof(TServiceInterface)); + channelFactory = ChannelFactoryProvider.GetChannelFactory(typeof(TServiceInterface)); } } @@ -179,48 +336,48 @@ public void SetEndpoint(string endpointConfigurationName) if (typeof(TServiceInterface).HasAttribute()) { Type originalServiceInterfaceType = typeof(TServiceInterface).GetInterfaces()[0]; - _channelFactory = ChannelFactoryProvider.GetChannelFactory(endpointConfigurationName, originalServiceInterfaceType); + channelFactory = ChannelFactoryProvider.GetChannelFactory(endpointConfigurationName, originalServiceInterfaceType); } else { - _channelFactory = ChannelFactoryProvider.GetChannelFactory(endpointConfigurationName); + channelFactory = ChannelFactoryProvider.GetChannelFactory(endpointConfigurationName); } } public void SetEndpoint(Binding binding, EndpointAddress endpointAddress) { - _channelFactory = ChannelFactoryProvider.GetChannelFactory(binding, endpointAddress); + channelFactory = ChannelFactoryProvider.GetChannelFactory(binding, endpointAddress); } public void MaximumRetries(int retryCount) { - _actionInvoker.RetryCount = retryCount; + actionInvoker.RetryCount = retryCount; } public void SetDelayPolicy(Func policyFactory) { - _actionInvoker.DelayPolicyFactory = policyFactory; + actionInvoker.DelayPolicyFactory = policyFactory; } public void RetryOnException(Predicate where = null) where TException : Exception { - _actionInvoker.AddExceptionToRetryOn(where); + actionInvoker.AddExceptionToRetryOn(where); } public void RetryOnException(Type exceptionType, Predicate where = null) { - _actionInvoker.AddExceptionToRetryOn(exceptionType, where); + actionInvoker.AddExceptionToRetryOn(exceptionType, where); } public void RetryOnResponse(Predicate where) { - _actionInvoker.AddResponseToRetryOn(where); + actionInvoker.AddResponseToRetryOn(where); } public void RetryFailureExceptionFactory(RetryFailureExceptionFactoryDelegate factory) { - _actionInvoker.RetryFailureExceptionFactory = factory; + actionInvoker.RetryFailureExceptionFactory = factory; } #endregion