Worth a Thousand Words
In case you are wondering, yes, that is a screenshot of LinFu.AOP
intercepting calls to Console.WriteLine()
at runtime.
One of the more useful things that LinFu.AOP
can do is intercept calls to third-party assemblies that aren't necessarily under your control. In fact, LinFu makes it so easy that all you have to do to make the interception happen is add the reference to LinFu like the following lines to your CSProj file just like I did with my SampleLibrary.csproj file:
<PropertyGroup>
<PostWeaveTaskLocation>
$(MSBuildProjectDirectory)\$(OutputPath)\..\..\..\lib\LinFu.Core.dll
</PostWeaveTaskLocation>
</PropertyGroup>
<UsingTask TaskName="PostWeaveTask" AssemblyFile="$(PostWeaveTaskLocation)" />
<Target Name="AfterBuild">
<PostWeaveTask TargetFile="$(MSBuildProjectDirectory)\
$(OutputPath)$(MSBuildProjectName).dll"
InterceptAllMethodCalls="true" />
</Target>
'Automagically' Delicious
Once you reload and rebuild the solution, LinFu.AOP
will automatically modify your code after the build runs so that you can intercept it at runtime. LinFu does this by adding hooks to your code so you can change it as the program is running. In this case, I casted the modified BankAccount
class to an IModifiableType
instance so that I could add my custom ConsoleInterceptor
instance:
var account = new BankAccount(100);
var modifiableType = account as IModifiableType;
if (modifiableType != null)
modifiableType.MethodCallReplacementProvider = new WriteLineMethodReplacementProvider();
account.Deposit(100);
The WriteLineMethodReplacementProvider
class, in turn, determines the method calls that should be intercepted at runtime:
public class WriteLineMethodReplacementProvider : IMethodReplacementProvider
{
public bool CanReplace(object host, IInvocationInfo info)
{
var declaringType = info.TargetMethod.DeclaringType;
if (declaringType != typeof(System.Console))
return false;
var targetMethod = info.TargetMethod;
return targetMethod.Name == "WriteLine";
}
public IInterceptor GetMethodReplacement(object host, IInvocationInfo info)
{
return new ConsoleInterceptor();
}
}
Choosing Which Methods to Intercept
As you can see from the example above, this class ensures that only calls to Console.WriteLine()
are ever intercepted. The ConsoleInterceptor
itself is responsible for replacing and intercepting the Console.WriteLine()
method itself:
public class ConsoleInterceptor : IInterceptor
{
public object Intercept(IInvocationInfo info)
{
var targetType = info.TargetMethod.DeclaringType;
var target = info.Target;
var targetMethod = info.TargetMethod;
var arguments = info.Arguments;
Console.WriteLine("Intercepted method named '{0}'", targetMethod.Name);
targetMethod.Invoke(null, arguments);
return null;
}
}
The most interesting part about the code example is how LinFu.AOP
adds the method call hooks without touching a single line of the source code. All of the IL rewriting is done behind the scenes so you won't have to worry about the gory details of using an AOP framework in your legacy code. The beauty of this approach is that it allows you to intercept any method call, even if that method call is a part of the .NET base class libraries.
You can find the LinFu.AOP.Examples
library here at Github.
Note: Please intercept BCL method calls responsibly.