This project is read-only.

Unity to Simple Injector -Interceptor vs Decorators

Aug 25, 2014 at 12:59 AM
Edited Aug 25, 2014 at 5:10 AM
Hi, I've started migrating my existing application from Unity to Simple Injector and am completely blown away by its performance. Thanks very much for such an awesome DI container!! It has made a huge difference in application responsiveness and speed.
I've migrated all the code except the interception part of the application. Our application was intercepting some of the functions of ViewModels and DataServices (we are using MVVM) to perform certain validations, track changes etc. It was checking if the function is virtual and has some attributes (say [Validate]) then intercept that call through a common service (say ViewModelInterceptionBehaviour or DataServiceInterceptionBehaviour). Just to mention that we've several viewmodels and dataservices in our application.

I do understand that Simple Injector supports interception out of the box, however after reading your blogs and posts, I reckon using Decorators could be a better way in such a case as it won't slow down the application. Would appreciate if you could guide me as to how I can incorporate using decorators in my case by using simple injector. A couple of examples or links could be great help. Given below is the code snippet (using unity) just to make my scenario clearer.

In ContainerRegistration.cs:
                if (selectedClass.FullName.ToLower().EndsWith("viewmodel"))
                {
                    _container.RegisterType(selectedClass, selectedClass,
                        new Interceptor<VirtualMethodInterceptor>(),
                        new InterceptionBehavior<ViewModelInterceptionBehaviour>());
                }
In ViewModelInterceptionBehaviour:
    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {
        var methodName = input.MethodBase.Name.ToLower();
        dynamic viewModel = input.Target;
        var validate = _typeService.GetAttributeForMethod<ValidateAttribute>(input.MethodBase);

        if (validate != null)
        {
//Do Something
         }
     }
and in ABCViewModel.cs
    [Validate]
    public virtual TransactionReturnValue Save()
    {
        TransactionReturnValue = _dataService.Save(ViewSettings);
        return TransactionReturnValue;
    }
Coordinator
Aug 25, 2014 at 12:25 PM
I'm sorry I've not responded to this sooner. Both me and qujck are on holliday and your question is a bit more complex to answer. I'll do my best to get to you on this within two days.
Coordinator
Aug 26, 2014 at 5:53 PM
Let me start by saying that there is actually no interception capabilities in Simple Injector out-of-the-box. The documentation however explains how to add interception capabilities and here's how to integrate this with Castle Dynamic Proxy. The reason why we don't have OOTB support for interception is explained here.

It's good that you want to take a look at using decorators instead of interception, because "the use of interception is often an indication of a suboptimal design". Changing your application design in a way to remove the need for interception however is not always easy; especially when you got lots of code already written. Since you didn't provide much information about your design it's a bit hard to advice you about how to apply decorators. One thing to note however is that when applying decorators, you need to often think in a different direction opposed to using interception. With interception you are able to apply cross-cutting concerns around code that has no clear relationship. With decorators on the other hand, there must be a clear relationship (often an interface), since there's no dynamic code generation going on. Having this strong interface-based relationship however, often has many advantages. Not only for performance, but often for readability and maintainability as well.

But one interesting direction that is worth investigating is to introduce an extra layer of abstraction in your application, such as the command/handler pattern. It currently seems that your ViewModel is directly talking to the DAL and a Business Layer abstraction might be missing.

For instance, instead of calling the dataService, your ViewModel could get injected with an ICommandHandler<TCommand>. In this case you define clear command messages for each use case and create an ICommandHandler<TCommand> implementation for each command message. Since each operation uses a unique type (the command), you extract the validation logic to its own class as well and apply the IValidator<T> abstraction to that type. Now all business logic in the system will be applied with the ICommandHandler<TCommand> abstraction and all validation logic will be applied with the IValidator<T> abstraction. This has nice benefits. The ViewModel can get its own command handler injected and it now becomes very easy to create a command handler decorator that does the validation based on the given command like this:
public class ValidationCommmandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decoratee;
    private readonly IEnumerable<IValidator<TCommand>> validators;

    public ValidationCommmandHandlerDecorator(
        ICommandHandler<TCommand> decoratee,
        IEnumerable<IValidator<TCommand>> validators) {
        this.decoratee = decoratee;
        this.validators = validators;
    }

    public void Handle(TCommand command) {
        foreach (var validator in this.validators) {
            validator.Validate(command);
        }
        this.decoratee.Handle(command);
    }
}
Advantage of this is that both the ViewModel nor the command handler need to know nothing about validation. You don't have to apply [Validation] attribute to the ViewModel, since you might forget that anyway. And you can add validations without having to make any changes to the command handler by adding new IValidator<T> implementations to your code base. And if you register them using the RegisterManyForOpenGeneric overloads, there's no need to make any changes to your composition root as well.

As I said, I'm guessing here a bit, and this suggestion might actually not work in your case, but use this as an example, and try to look at the general pattern here that you can apply to solve the problem here. But remember, it might be a too big step at a time to go to such design, but that's up to you. You can always start of with interception and move to decorators later on.

Good luck.
Marked as answer by dot_NET_Junkie on 9/28/2014 at 4:19 AM
Aug 27, 2014 at 6:06 AM
Thanks a lot for your valuable advice Steven! I am going through the links you provided and will try to work out a solution in my case. The existing application has come a long way though so will need to transition it gradually from interception to decorators.