views:

73

answers:

2

Hi,

In googling I can't seem to find an example of intercepting event on a proxied type and it doesn't seem to be working for me. Is there a way I can do this (ie. use an IInterceptor when an event is invoked)?

Thanks.

+2  A: 

I doubt it. Castle Dynamic Proxy works by intercepting the calls made on the proxy. Events are not made on the proxy. They're callbacks handled by the .NET framework.

Patrick Steele
That is correct. With DP you can intercept methods, including event subscription and unsubscription, but that's it.
Krzysztof Koźmic
Thanks, my solution below accomplishes what I was looking for so this isn't necessary.
JeffN825
+1  A: 

I ended up using the ComponentCreated event, then adding a dynamic event handler with a DynamicMethod to accomplish what I wanted:

private static readonly MethodInfo internalPublishEventMethod =
    typeof(EventPublisher).GetMethod("PublishEvent", BindingFlags.Static | BindingFlags.NonPublic);

private void Container_ComponentCreated(global::Castle.Core.ComponentModel model, object instance)
{
    if (instance != null)
    {
        Type type = instance.GetType();

        var eventPublisherAttribute = type.GetAttribute<EventPublisherAttribute>();

        if (eventPublisherAttribute != null)
        {
            foreach (EventInfo ei in type.GetEvents())
            {
                if (eventPublisherAttribute.PublishAllEvents || ei.GetCustomAttributes(typeof(PublishedEventAttribute), false).Length > 0)
                {
                    // emit an event handler

                    MethodInfo invoke = ei.EventHandlerType.GetMethod("Invoke");
                    Type[] parameters = invoke.GetParameters().Select(p => p.ParameterType).ToArray();

                    var method = new DynamicMethod(string.Empty, null, parameters, instance.GetType(),
                                                   true);
                    ILGenerator generator = method.GetILGenerator();
                    // sender
                    generator.Emit(OpCodes.Ldarg_0);
                    // args
                    generator.Emit(OpCodes.Ldarg_1);
                    // topic
                    generator.Emit(OpCodes.Ldstr, ei.Name);
                    generator.Emit(OpCodes.Call, internalPublishEventMethod);
                    generator.Emit(OpCodes.Ret);

                    Delegate d = method.CreateDelegate(ei.EventHandlerType);
                    ei.AddEventHandler(instance, d);
                }
            }
        }
    }
}

private static void PublishEvent(object sender, EventArgs e, string topic)
{
    if (e != null)
    {
    // do stuff
    }
}
JeffN825
I'm having the same issue. Where id you put this event handler?
MediaSlayer