Search code examples
eventscastle-windsorcastle-dynamicproxy

Event Interception with Castle DynamicProxy


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)?


Solution

  • 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
        }
    }