views:

180

answers:

2

So, i have this problem, and no one seems to be able to help. So rather than keep bashing away i'm going to throw it out there for alternative ways to skin this particular cat.

I currently have the following:

public interface ICustomerService
{
    Customer GetCustomer(int id);
}

public class CustomerService : ICustomerService
{
    public Customer GetCustomer(int id)
    {
        ...
    }
}

... and with Unity i have IOC setup, and at the same time configuring interception like :

IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<ICustomerService, CustomerService>()
    .Configure<Interception>()
    .SetInterceptorFor<ICustomerService>(new InterfaceInterceptor());

What i want to achive is to be able to place attributes in the interface like this:

public interface ICustomerService
{
    [Log]
    Customer GetCustomer(int id);
}

... defined like :

public class LogAttribute: HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new LogHandler();
    }
}

... and then in the LogHandler class do all the logging that i want like :

public class LogHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        ... log stuff
    }
}

What i want to achieve is a tracing/logging system where the handler logs what namespace.class.methodname is being called, AND the parent namespace.class.methodname that called that. I've tried with no success to use the "input" IMethodInvocation parameter to get the info i want, the issue being, input returns the "ICustomerService" interface, whilst checking a stackframe for the parent returns the implemented class of the parent (eg. CustomerService) meaning that when i try to create a tree structure using the namespace.class.methodname as the entitys ID's, the ID's and parentID's don't match up.

Dropping a parameter into the [Log] attribute isn't going to work either really, because what could i put in there? If i put the interface name, i still have the same problem as above where the ID of one is an interface and the parent is the implementing class. And, i can't put the implementing class name in the attribute on the interface as that defeats the purpose of having an interface in the first place!

So, that's the dilema. Anyone got fresh ideas?

A: 

I ended up using PostSharp to implement logging exactly like this. http://www.postsharp.org

Yeah i'm aware of PostSharp, but before i start complicating the issue further with more dll references and tools, is PostSharp worth it, and more importantly, is what i want possible using just Unity and Entlib?
krisg
I don't know if it's possible with just Unity and Entlib.I found PostSharp to be very simple to use to achieve this, and since it's a compile time IL modification, there is no need to distribute the PostSharp assemblies.
A: 

I've got logging working using Unity and Interception. Due to my horrendous lack of configuration setup skills, I had to do it programmatically. You need to set up at least one interceptor, as well as one or more policy objects. Oh yeah, the UnityContainer.Configure<Interception> is critical.

Kind of like this:

// I'm using the TransparentProxyInterceptor because I want to trace EVERYTHING...
var intp = myUnityContainer.Configure<Interception>().
    SetInterceptorFor(typeof(MyTypeToLog), new TransparentProxyInterceptor());

var policy = intp.AddPolicy("somePolicyName");

policy.AddMatchingRule<TypeMatchingRule>(
    new InjectionConstructor(
        new InjectionParameter(typeof(MyTypeToLog)))
          .AddCallHandler(typeof(MyCallHandler), 
               new ContainerControlledLifetimeManager());

Of course I need to define the interception call handler as well:

public class MyCallHandler : ICallHandler, IDisposable
{
    public IMethodReturn Invoke(IMethodInvocation input, 
        GetNextHandlerDelegate getNext)
    {
        var methodReturn = getNext().Invoke(input, getNext);

        // log everything...
        LogMethodCall(input, methodReturn);

        // log exception if there is one...
        if (methodReturn.Exception != null)
        {
            LogException(methodReturn);
        }

        return methodReturn;
    }
}
code4life