user1112906
user1112906

Reputation: 61

Need help on setting Unity interception

First, I never used Unity before... I want to introduce Tracing / Logging to our project through unity interception.
The project is considerably big (~30000 files). The goal is to trace performance / execution period every time we try to call outside service. Regrettably I cannot use any other library.
To get familiar with how this concept is going to work, I built a small program that I found on MSDN; however my interception with log attribute still does not fire. I am sure I am missing some configuration or / and initialization. I appreciate any help.

Here is my Main program:

namespace calc
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var t = new calc.Calculator.Calculator().Sub(5, 8);
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.Message);
            }
        }
     }
}

Here is Calculator class:

namespace calc.Calculator
{
    public interface ICalculator
    {
        Int32 Sum(Int32 x, Int32 y);        
        Int32 Sub(Int32 x, Int32 y);
    }

    public class Calculator : ICalculator
    {        
        public Int32 Sum(Int32 x, Int32 y)
        {
            return x + y;
        }

        [NonNegativeCallHandler] // Intercept this method and run tracing on it
        public Int32 Sub(Int32 x, Int32 y)
        {
            return x - y;
        }
    }
}

Here is my CallHandler:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace calc.Tracing
{
    public class NonNegativeCallHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input,
                                GetNextHandlerDelegate getNext)
        {
            // Perform the operation
            var methodReturn = getNext().Invoke(input, getNext);

            // Method failed, go ahead
            if (methodReturn.Exception != null)
                return methodReturn;

            // If the result is negative, then throw an exception
            var result = (Int32)methodReturn.ReturnValue;

            if (result < 0)
            {
                var exception = new ArgumentException("...");
                var response = input.CreateExceptionMethodReturn(exception);

                // Return exception instead of original return value
                return response;
            }

            return methodReturn;
        }

        public int Order { get; set; }
    }
}

And Finally

*Here is my Attribute definition:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.Practices.Unity;

namespace calc.Tracing
{
     public class NonNegativeCallHandlerAttribute : HandlerAttribute
     {
         public override ICallHandler CreateHandler(IUnityContainer container)
         {
             return new NonNegativeCallHandler();
         }
     }
}

What else exactly I need to add, and where (config file or inside constructor, etc..) in order for this code to work.

Upvotes: 1

Views: 1260

Answers (2)

user1112906
user1112906

Reputation: 61

I found one of the solutions... I've modified my program class to register container.. And it looks like no additional configuration is required at all. Here is modified program:

namespace calc
{
class Program
{
    static void Main(string[] args)
    {
        ICalculator iCal;
        try
        {

            iCal = ConfigurePolicyInjectionWithUnity();

            var t = iCal.Sub(8, 5);
        }
        catch (Exception ex)
        {
            System.Console.WriteLine(ex.Message);
        }
    }

    static ICalculator ConfigurePolicyInjectionWithUnity()
    {
        IUnityContainer container = new UnityContainer();

        container.AddNewExtension<Interception>();
        container.RegisterType<ICalculator, 
                           calc.Calculator.Calculator>().Configure<Interception>()
            .SetInterceptorFor<ICalculator>(new InterfaceInterceptor());

            // resolve
            return container.Resolve<ICalculator>(); ;
        }
    }
}

Now, here is the question... Lets say that I have about 20 different flavors of calculators each class has about 3 - 4 methods to be traced. Each of those methods have unique signatures. So 3-4 methods x 20 classes = ~80 methods with unique signatures to be traced. What I am leading to is that I cannot have single interface to describe all these methods... From the solution above, at least in my case, it looks like I must have an interface per class in order to implement interceptor. This does not look very elegant to introduce 20-30 new interfaces just to have logging. In this case, there is no difference between using interception and just having some helper class to do logging. Am I correct?

Is there any other way I can use interception without defining interface? All I need is to be able to Log time when methods start running and the time when they complete execution.

Any help or ideas would be appreciated.

Upvotes: 0

Sebastian Weber
Sebastian Weber

Reputation: 6806

Your code looks like it origins from this article by Dino Esposito. Looks like you missed the section on configuration (paragraphs Using Fluent Code or Adding Policies through configuration).


Update

Did you have a look at this page on MSDN?

Upvotes: 0

Related Questions