Real World Example of Adding Auditing With Dependency Injection’s Interception

Synopsis: This article walks through a real world example in which the Crosscutting Concern (1) ‘Auditing’ was added to the application without breaking the Single Responsibility Principle (2), nor the Open/Closed Principle (3), by utilizing Dependency Injection’s Interception. Get the example from my GitHub: https://github.com/DannyvanderKraan/DependencyInjectionInterception . If you can read Dutch you can also download the SDN magazine (Microsoft Azure/Xamarin) in which this article is featured: http://www.sdn.nl/portals/1/magazine/SDN-Magazine%20126.pdf

Intro

For this article I assume you have some basic knowledge of Depency Injection. But if you don’t, not to worry! I have introduced Dependency Injection (4) and showed a possible route to take when the dependencies depend on run-time values (5). Common scenario: After a few months of developing the core domains of an application ‘auditing’ capability needs to be added. Adding Crosscutting Concerns like auditing to an existing application can be quite a hassle if the architecture hasn’t taken it into account from the ground up. However, taking all Crosscutting Concerns into account while ‘growing’ the architecture is not beneficial in an Agile Scrum environment, in which you are supposed to deliver potentially shippable increments every sprint. Enter the domain of Aspect-oriented Programming (6). AOP promotes a loosely coupled design with which you can mitigate these problems. Add in an Inversion of Control (7) framework that supports AOP by enabling Interception (like Unity) and Crosscutting Concerns become a breeze. Let me show you how I added auditing and let us scratch the surface of Interception.

Case

As this particular application deals with patients and their medical data it is important to log which user did what, when and where. Next to a mutation database on the medical data (which is a core domain due to the nature of the application) I also wanted to log things more in detail, like: User A read prescription X of patient Y at July 23th 2015 8:40 am. Or User B authorized contact moment #11 of patient B created by User A at July 23th 2015 8:42 am. This is not a concern the first few sprints of development. But at a certain point you’ll want to add this auditing capability and you’ll have to crack open several classes to insert said functionality, violating the Open/Closed principle. And the Single Responsibility Principle, because now the classes are apparently also responsible for auditing? We’ll get to the solution for this problem with Dependency Injection and Interception soon. But to really understand what is going on, let’s solve this problem by taking a look at the Decorator Pattern (8) with poor man’s Dependency Injection first.

Sidenote: This blogpost does not address the Decorator Pattern with inheritance due to its drawbacks, which is a subject for another article perhaps.

Decorator Pattern

Figuur 1 Decorator Pattern in actie
Figure 1: Decorator Pattern in action!

We have a class named PrescriptionService which implements interface IPrescriptionService. The interface consists out of only one method: GetPrescriptionByID. GetPrescriptionByID is implemented as follows:

Console.WriteLine("{0} is called!", nameof(GetPrescriptionByID));
IPrescription prescription = Program.Container.Resolve();
prescription.ID = ID;
switch (ID)
{
case 1:
prescription.PatientID = 1;
prescription.MedicationName = "Aspirin";
prescription.Dosage = "2 tablets each day";
break;
case 2:
prescription.PatientID = 1;
prescription.MedicationName = "Unisom";
prescription.Dosage = "1 tablet each day";
break;
case 3:
prescription.PatientID = 2;
prescription.MedicationName = "Dulcolax";
prescription.Dosage = "2 tablets every other day";
break;
case 4:
prescription.PatientID = 3;
prescription.MedicationName = "Travatan";
prescription.Dosage = "3 drops each day";
break;
case 5:
prescription.PatientID = 4;
prescription.MedicationName = "Canesten";
prescription.Dosage = "Apply 6 times each day";
break;
default:
throw new ArgumentException(String.Format("{0} has unknown value", nameof(ID)));
}
return prescription;

Listing 1: GetPrescriptionByID

But after GetPrescriptionByID is called we want to log this event. So I’ve added AuditingPrescriptionService whose sole purpose it is to log this call. It wraps the original PrescriptionService by demanding an instance of any class that implements IPrescriptionService in its constructor (Constructor Injection). And it needs to know the user for my Auditing requirements, so demands that too in its constructor. Like so:

public AuditingPrescriptionService(IPrescriptionService service, int userID)
{
if(service == null)
{
throw new ArgumentNullException(nameof(service));
}
if(userID <= 0)
{
throw new ArgumentOutOfRangeException(nameof(userID));
}
this.Service = service;
this.UserID = userID;
}

Listing 2: Constructor AuditingPrescriptionService

And the method GetPrescriptionByID is augmented in AuditingPrescriptionService:

IPrescription prescription = Service.GetPrescriptionByID(ID);
//TODO write to log that user ? read prescription ? of patient ? at a certain date and time
return prescription;

Listing 3: Augmented GetPrescriptionByID

Let us not worry about the actual implementation right now. What is important to note however is that with this approach you will have to write a decorator for everything you need to wrap. And what if you have more than one Crosscutting Concern to implement, like caching, or authorizing? The number of Decorator classes will grow exponentially. Lots of little objects will have to be created to implement all Crosscutting Concerns creating a potential maintenance nightmare. The solution as said before is Interception, but let’s take a brief look at how this problem could be solved with an AOP framework as well, to fully appreciate Interception.

AOP Framework

There are lots of fantastic AOP frameworks out there for .NET like LOOM.NET, Aspect.NET and Spring.NET supports it now too. But PostSharp must be one of the most popular frameworks at the moment of writing this. There are loads of aspects to choose from in PostSharp and it can be as easy as moving the caret to the name of the class or method you want to enhance and choosing the pattern from the light bulb (smart tag in versions previous to Visual Studio 2015). If we want to add logging to a method all you have to do is follow these simple steps (9). It is like magic right? Why wouldn’t I want to use an AOP framework?

There are a few reasons in order of importance to me:

  1. It’s tightly coupled to the AOP framework’s implementation of logging, even if you have choice.
    Due to the nature of of the branche I work for the operational environment has some restrictions which is why I have to build specialized logging.
  2. If you’ve followed the steps from the link above to add logging you have seen that the attribute [Log] is added on top of a method. Without settings it’ll be default logging. So if I don’t want default behaviour anymore I need to adjust the logging attribute. I’ll have to change all the [Log] attributes to be clear on this.
    I can see people’s minds change a lot of times in the nearby future about logging (often pushed from our government), so I need something more flexible.
  3. You can’t late bind these aspects through the configuration file since these aspects are compiled into the assemblies.
    An extension to points one and two in a way. Some operational environments will require another behaviour from the logging than other environments. If I can’t tell at run time which logging aspect I need then I won’t be able to fulfil this requirement.
  4. Complexity of unit tests increases by using an AOP framework
    I am a big fan of TDD and while Dependency Injection actually caters to unit testing from the ground up, AOP framework impedes unit testing to a point where your tests become harder to read (and people feel the need to write documentation about how to actually go about doing it: (10)).

SideNote: What is important to mention here is that I am not against AOP frameworks. On the contrary, I don’t understand the whole DI versus AOP topics out there, since I think they complement each other in certain architectures. If you are interested in this kind of information I can recommend a good blogpost by Kenneth Truyers: (11) (keep in mind he favours DI in this post though). And PostSharp for instance has the SkipPostSharp flag which you can apply in your testproject.

These problems sketched above can easily be solved with an IoC Container’s ability to dynamically apply Interception.

Dependency Injection and Interception

Interception looks conceptually like this:
Figuur 2 Concept of Interception
Figure 2: Concept of Interception

Some client calls method GetPrescriptionByID of the PrescriptionService class and the call gets ‘intercepted’ by some Logging behaviour first, hence the name. In the above figure for illustrative purposes I have drawn a ‘chain’ of Interceptions (and the funny thing is that the arrows look like a chain this way). All three very common Crosscutting Concerns which you can chain together. So in this case the retrieved Prescription gets cached for a period of time apparently, but not before there is a check if the user is authorized to see prescriptions at all. And the call gets logged no matter what. Boy, I really wish I could add these behaviours (or ‘aspects’) dynamically later on in development. But I can! Just need a little help of Unity.

Interception with Unity

There are a few simple steps:

  1. Make sure you get Unity.Interception from NuGet
  2. Add AddNewExtension<Interception>(); in the Composition Root
  3. Add a class named LoggingInterceptionBehavior (the ‘InterceptionBehavior’ part is a convention you don’t necessarily need to abide to)
  4. Add usingPractices.Unity.InterceptionExtension; on top of the file
  5. Have the class implement interface IInterceptionBehavior (that is how Unity actually understands this class can be used to intercept calls)

The interface has two methods and a property you need to implement:

public interface IInterceptionBehavior
{
bool WillExecute { get; }
IEnumerable<Type> GetRequiredInterfaces();
IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext);
}

Listing 4: Interface IInterceptionBehavior

The property WillExecute is to determine if it makes sense to have the call be intercepted by this behavior. If it doesn’t make sense you can have this property be set to false and you won’t have the unnecessary overhead of the proxy or intercepting class generation. I want my logging behaviour to always run, so I will simply let WillExecute return True (get { return true; }).

The method GetRequiredInterfaces is basically there to pre-set which types you would like to intercept with this behaviour. But I like to do that in the Composition Root (and so should you), so I just let this method return an empty array of type Type (return Type.EmptyTypes;).

The Invoke method is where the real work gets done. The parameter ‘input’ represents the call to a method (12) and getNext is the parameter which actually contains a delegate which can be invoked to get the next delegate to call, to keep the chain going (13). For our AuditingInterceptionBehavior I have implemented it as follows:

//The logged in user happens to be Danny all the time. ;-)
string identity = "Danny";
//Before: You can write a message to the log before the next behaviour in the chain/intended target gets called.
WriteLog(String.Format(
"{0}: User {1} {2}. Technical details: Invoked method {3}",
DateTime.Now.ToLongTimeString(),
identity,
(input.MethodBase.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute)?.Description,
input.MethodBase));
//Actual call to the next behaviour in the chain or the intended target.
var result = getNext()(input, getNext);
//After: And you can write a message to the log after the call returns.
if (result.Exception != null)
{
//You can for instance write to the log if an exception has occurred.
WriteLog(String.Format(
"{0}: Method {1} threw exception: {2}",
DateTime.Now.ToLongTimeString(),
input.MethodBase,
result.Exception.Message));
}
else
{
//Or you can write more useful information.
WriteLog(String.Format(
"{0} User {1} {2}: {3}. Technical details: Returned from method {4}",
DateTime.Now.ToLongTimeString(),
identity,
(input.MethodBase.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute)?.Description,
result.ReturnValue,
input.MethodBase));
}
return result;

Listing 5: Implementation of the Invoke method

Side note: I decorated the GetPrescriptionByID in the interface with a Description attribute and I have overridden the ToString method in Prescription so the message is easier to read for display purposes.

The actual implementation is not important.
The important part is in the middle: var result = getNext()(input, getNext); this actually keeps the chain going. By invoking the delegate GetNext() a InvokeInterceptionBehaviorDelegate is returned with which you can either call Invoke on the next behaviour or invoke the intended target depending on the chain.
The other important bit is: return result; which keeps the chain going back up by returning the IMethodReturn instance (13). It contains the intended return value in its property ReturnValue which is used in listing 4. Another useful property is used in listing 4, which is Exception, so you can handle exceptions in the chain. WriteLog is actually a simple call to the Console (Console.WriteLine(message);) as this example is a Console Application, but it could be a call to your auditing library of choice of course.

Now in the Main method of the Program class, which we’ll use as the Composition Root, the following lines of code are needed:

Container.RegisterType<IPrescription, Prescription>();
Container.RegisterType<IPrescriptionService, PrescriptionService>(
new Interceptor(),
new InterceptionBehavior());
IPrescriptionService service = Container.Resolve();
IPrescription prescription = service.GetPrescriptionByID(1);
Console.WriteLine("Retrieved: {0}", prescription);
Console.ReadKey();

Listing 6: Main method of class Program

Let’s have a brief explanation about the Interceptor types. As you can see at “new Interceptor” we are using the “InterfaceInterceptor”, because the class only implements one interface. Always try to use this type of intercepting for performance reasons. Only use TransparantProxyInterceptor if your class implements more than one interface (or no interface at all) and you’d like to add behaviour to all implemented methods. The aforementioned intercept types work by dynamically creating a proxy object which is not type compatible with the target object. Try it. If you write for instance “?service.GetType()” in the Immediate Window you’ll get something like “DynamicModule.ns.Wrapped_IPrescriptionService_83729647ce664f89b08534edc98a7858” as FullName. If you want more control over your behaviours and you need to intercept internal calls in the class (or abstract classes) you’d need VirtualMethodInterceptor. But because it works by extending the type of the target object you’ll need to make your methods virtual, the class public and it cannot be used on existing objects. Only by configuring the type interception. The chain of behaviours is established by overriding the virtual methods in the base type.

For this example InterfaceInterceptor was enough. And in conclusion Listing 5 will output:
Figuur 3 Output
Figure 3: Output

As you can see in figure 3 “GetPrescriptionID is called!” is right in between the two messages from the AuditingInterceptionBehavior thus showing that this behaviour was added dynamically in the call chain.

Question: A question I got specifically about this example is what you should do if you need a finer detail of Auditing and you need to log messages within the method?
If you feel the need to do this I sincerely implore you to look critically at your design. Are your methods not too large and doing too much? And then change the design accordingly, so you get Auditing exactly where you need it.

Conclusion

Thank you for reading my article. I would like to leave you with the following thoughts. First of all, we’ve scratched the surface here of Interception, so be prepared to learn more along the way. Second of all, Dependency Injection’s Interception is not the silver bullet to Crosscutting Concerns as AOP frameworks are not either. Don’t be afraid to use what suits your needs the most in your current architecture. If you can read Dutch you can also download the SDN magazine (Microsoft Azure/Xamarin) in which this article is featured: http://www.sdn.nl/portals/1/magazine/SDN-Magazine%20126.pdf. Now go have fun with my example on GitHub and add some behaviours: https://github.com/DannyvanderKraan/DependencyInjectionInterception

Links

  1. Crosscutting Concern: https://msdn.microsoft.com/en-us/library/ee658105.aspx
  2. SRP: https://en.wikipedia.org/wiki/Single_responsibility_principle
  3. Open/closed principle: https://en.wikipedia.org/wiki/Open/closed_principle
  4. Intro DI: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/
  5. DI and run-time values: https://dannyvanderkraan.wordpress.com/2015/06/29/real-world-example-of-dependency-injection-based-on-run-time-values/
  6. AOP: https://en.wikipedia.org/wiki/Aspect-oriented_programming
  7. IoC: https://en.wikipedia.org/wiki/Inversion_of_control
  8. Decorator Pattern: https://en.wikipedia.org/wiki/Decorator_pattern
  9. PostSharp’s simple steps: http://doc.postsharp.net/logging
  10. PostSharp testing: http://doc.postsharp.net/simple-tests
  11. DI vs. AOP: http://www.kenneth-truyers.net/2013/05/16/why-choose-di-interception-over-aspect-oriented-programming/
  12. IMethodInvocation: http://www.nudoq.org/#!/Packages/Unity.Interception/Microsoft.Practices.Unity.Interception/IMethodInvocation
  13. GetNextInterceptionBehaviorDelegate: http://www.nudoq.org/#!/Packages/Unity.Interception/Microsoft.Practices.Unity.Interception/GetNextInterceptionBehaviorDelegate
  14. IMethodReturn: http://www.nudoq.org/#!/Packages/Unity.Interception/Microsoft.Practices.Unity.Interception/IMethodReturn
Advertisements

About Danny

Bachelor in Commercial ICT MCTS Winforms .NET 2.0 MCTS ASP.NET 3.5 PSM I
This entry was posted in .NET programming, Dependency Injection, Software design patterns and tagged , , . Bookmark the permalink.

3 Responses to Real World Example of Adding Auditing With Dependency Injection’s Interception

  1. Hey Danny

    Nice article. I started on the interceptor pattern 2 days ago, but this sums it up really nice.

    Suggestion for formatting of your listings: if you use Google Chrome, the app ‘Markdown here’ should be able to format your listings the same way you markdown on GitHub (aka. Jekyll formatting), just by hitting Ctrl + Alt + m.

    I haven’t tried it on my own WordPress yet, but I’m in dire need of changing my ‘SyntaxHighlighter Evolved’ plugin.

    Link to Markdown Here:
    https://chrome.google.com/webstore/detail/markdown-here/elifhakcjgalahccnjkneoccemfahfoa?hl=en

    • Danny says:

      Hey Rasmus,

      Thank you for reading it and the nice comment.

      Yeah I’ve been wrestling with WordPress to get my listings right (and it was winning hehe). Thank you for your tip! I’ll look into that asap.

      I hope you will apply the interceptor pattern succesfully (it is based on the ‘pipeline’ pattern by the way). If you need to exchange thoughts, you know where to find me.

  2. Pingback: Unit Testing made easy with Dependency Injection | Danny van der Kraan's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s