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