Method interception
There are many ways to configure method interception.
OnBefore callback
It always runs before the target method execution.
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Perform()) .OnBefore(() => Console.WriteLine("Called Before")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform();
The output will look like this:
Called Before The actual call
OnAfter callback
It runs after the target method execution, but only if it does not throw an exception.
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Perform()) .OnAfter(() => Console.WriteLine("Called After")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform();
The output will look like this:
The actual call Called After
OnCatch and OnFinally callbacks
OnCatch callback runs after the target method execution, but only if it throws an exception. OnFinally callback runs after the target method execution. But OnAfter and OnCatch callbacks always run first if they exist.
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Fail()) .OnCatch(exception => Console.WriteLine("An error of type '{0}' occurs with message : \n'{1}'", exception.GetType().Name, exception.Message)) .OnFinally(() => Console.Write("You can dispose resources here")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Fail();
The output will look like this:
An error of type 'TargetInvocationException' occurs with message: 'Exception has been thrown by the target of an invocation' You can dispose resources here
OnInvoke callback
It runs instead of the target method execution.
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Perform()) .OnInvoke(invocation => Console.Write("The original call has been replaced by this")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform();
The output will look like this:
The original call has been replaced by this
OnReturn callback
It runs right before the proxy method execution is over. OnFinally callback runs first if it exist.
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.ReturnNull()) .OnReturn((invocation, returnedValue) => returnedValue ?? "This is a replaced value"); var testService = serviceLocator.ResolveType<ITestService>(); var result = testService.ReturnNull(); Console.WriteLine(result);
The output will look like this:
This is the replaced value
Intercepting multiple method calls at once
You can configure interception of multiple methods call at once just like this:
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethods ( service => service.Perform(), service => service.Perform(It.IsAny<string>()), service => service.Return() ) .OnBefore(() => Console.WriteLine("Called On Before")) .OnAfter(() => Console.WriteLine("Called On After")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform(); testService.Perform("testValue"); testService.Return();
The output will look like this:
Called On Before The actual call Called On after Called On Before Called On After Called On Before Called On After
Intercepting all members calls at once
To intercept all member calls at once, use the following code:
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptAll() .OnBefore(() => Console.WriteLine("Called On Before")) .OnAfter(() => Console.WriteLine("Called On After")); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform(); testService.Name = "testValue"; var value = testService.Name;
The output will look like this:
Called On Before The actual call Called On after Called On Before Called On After Called On Before Called On After
Exclude members
If you want to exclude some members using InterceptAll* methods, you can decorate your membre with the DoNotInterceptAttribute in the interface type.
Differentiating between overloaded methods
To differentiate between overloaded methods, use the following code:
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Perform(It.IsAny<string>())) .OnBefore(invocation => invocation.Arguments[0] = "Intercepted"); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform("testValue"); testService.Perform(45);
The output will look like this:
Intercepted 45
Stacking several methods on a single fluent instruction
Use the following code:
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptMethod(service => service.Perform()) .OnBefore(() => Console.WriteLine("1,2,3...")) .OnAfter(() => Console.WriteLine("Excecution Succeeded")) .And() .InterceptMethod(service => service.Fail()) .OnCatch(exception => Console.WriteLine("Exception occurs: '{0}'", exception.Message)) .OnFinally(() => Console.Write("Dispose Resources Here")) .And() .InterceptMethod(service => service.ReturnNull()) .OnReturn((invocation, returnedValue) => returnedValue ?? "Replace Any Null Value Here"); var testService = serviceLocator.ResolveType<ITestService>(); testService.Perform(); testService.Fail(); testService.ReturnNull();
The output will look like this:
1,2,3... The actual call Execution Succeeded Exception occurs: 'Exception has been thrown by the target of an invocation.' Dispose Resources Here
Utilizing predicates to select multiple methods
Use the following code:
var serviceLocator = ServiceLocator.Default; serviceLocator.ConfigureInterceptionForType<ITestService, TestService>() .InterceptWhere(method => method.Name == "Perform") .OnBefore(() => Console.WriteLine("Called before")) .OnAfter(() => Console.WriteLine("Called after")); var testService = serviceLocator.ResolveType<ITestService>(); testService.ReturnNull(); testService.Perform();
The output will look like this:
Called before The actual call Called after