Story started this way, I used Castle EventWiring facility to define listeners to events in my classes, and it worked fine, I used to raise events like this:
if (null != BlaBlaEvent)
{
BlaBlaEvent(someData);
}
Recently I faced a business requirement and thought probably the best solution is to use a proxy pattern so I used DynamicProxy, in my IoC resolving function (a small wrapper to Castle Windsor) I have the following code:
T componenet = _container.Resolve<T>();
var gen = new ProxyGenerator();
if (typeof(T).IsClass)
{
return gen.CreateClassProxyWithTarget(componenet, _container.Resolve<StashInterceptor>());
}
else
{
return gen.CreateInterfaceProxyWithTarget(componenet, _container.Resolve<StashInterceptor>());
}
this also worked, and instead of returning a concrete class it returns a proxy that intercepts the function calls and does some processing, then forwards the call to the original concrete class methods.
problem now is that the events in the concrete class have no listeners (Even though the configurations says they do).
not sure if this is a bug or a design decision not to load the listeners when invoking the method from a proxy, but currently I'm in a boggle and need a solution or a workaround.
Anyone has an idea?
Here are my castle xml configurations in web.config:
<castle>
<facilities>
<facility id="event.wiring" type="Castle.Facilities.EventWiring.EventWiringFacility, Castle.Facilities.EventWiring" />
</facilities>
<components>
<component id="SomeInterceptor" type="Namespace.SomeInterceptor, MyAssembly" />
<component id="SomePublisher" type="Namespace.SomePublisher, MyAssembly">
<subscribers>
<subscriber id="SomeSubscriber" event="SomeEvent" handler="OnSomeEvent" />
</subscribers>
</component>
<component id="SomeSubscriber" type="Namespace.SomeSubscriber, MyAssembly" />
</components>
Note: The problem is not xml or fluent configuration but the fact that your are generating your proxies through Castle.DynamicProxy yourself. If you instead leverage the container and register your interceptors using the functionality in your container (which uses DynamicProxy by the way), this will work.
Not sure what your are exactly trying to do, but as shown below it's not a problem to register an interceptor with a listener and have it intercept listener method calls, and at the same time use the event wiring functionality. This is windsor 3.3
public class EventWiringFacilityTests
{
public void RegisterInterceptorWithListenerAndMakeSureListenerSubscribes()
{
var container = new WindsorContainer();
container.AddFacility<EventWiringFacility>();
container.Register(Component.For<SomeInterceptor>());
container.Register(
Component.For<SimplePublisher>()
.PublishEvent(p => p.Event += null,
x => x.To<SimpleListener>("foo", l => l.OnEvent(null, null))),
Component.For<SimpleListener>().Interceptors<SomeInterceptor>().Named("foo"));
var someInterceptor = container.Resolve<SomeInterceptor>();
var simpleListener = container.Resolve<SimpleListener>();
Assert.That(simpleListener.EventHasHappened, Is.False);
var simplePublisher = container.Resolve<SimplePublisher>();
simplePublisher.Trigger();
Assert.That(simpleListener.EventHasHappened);
simpleListener.Snap();
Assert.That(someInterceptor.Intercepted);
}
}
public class SomeInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Intercepted = true;
invocation.Proceed();
}
public bool Intercepted { get; set; }
}
public class SimplePublisher
{
public event EventHandler Event;
public void Trigger()
{
if (Event != null)
{
Event(this, new EventArgs());
}
}
}
public class SimpleListener
{
public bool EventHasHappened { get; set; }
public void OnEvent(object sender, EventArgs e)
{
EventHasHappened = true;
}
public virtual void Snap()
{
}
}