I am having a rough time implementing eventing in a recent project.
I have verified that structuremap is scanning properly assemble and adding EventHandlers
Scan(cfg =>
{
cfg.TheCallingAssembly();
cfg.IncludeNamespace("ABC.EventHandler");
cfg.ConnectImplementationsToTypesClosing(typeof(IHandle<>));
});
public class StructureMapEventDispatcher : IEventDispatcher
{
public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
{
foreach (var handler in ObjectFactory.GetAllInstances<IHandle<TEvent>>())
{
handler.Handle(eventToDispatch);
}
}
}
Before I used to fire Event from Domain. Somthing like Dispatcher.RaiseEvent(new [domainEvent class](x,y,z));
and the event will get fired up. I had to change the design where I am now collectiong events in a collection
_domainEvents = new Collection<IDomainEvent>();
and then raising it after I have saved the domain to Repository
public static void Raise(ICollection<IDomainEvent> domainEvents)
{
foreach (var domainEvent in domainEvents)
{
DomainEventDispatcher.Raise(domainEvent);
}
}
but now
ObjectFactory.GetAllInstances<IHandle<TEvent>>() returns 0 count of handlers
if I watch for
ObjectFactory.GetAllInstances<IHandle<DomainEventClass>>() it returns collection of handlers properly ( currently I have 2 and it shows 2 count)
... I am assuming this has something to do with events being raised as of type IDomainEvent instead of actual type and that is making it hard for structuremap to resolve it.
How can I solve this issue?
Regards,
The Mar
--
Edit 1:
I have conformed that struturemap container contains all event handlers scanned from the assembly.
Edit 2
I dont know how to make this question attract more attention. I am adding bounty for a solution to achieve the results desired. If the question is not clear, please ask.
Basically I want the ObjectFactory.GetAllInstances<IHandle<TEvent>>() to return handlers for TEvent where TEvent is of Type IDomainEvent. Events to be raised are stored in Collection of IDomainEvent and raised after the fact that Domain was saved (from service layer).
I am thinking there should be some way to make structuremap know that the event raised as IDomainEvent is actually of Type DomainEvent
var eventsToRaise= dealer.EventsToRaise();
Adding Information from Debug Window:
After the events have been raised in the dispatcher window
Edit 3:
Eventhough eventToRaise shows as "DealerName Changed" and "DealerCommunicationChanged"
typeof(TEvent) gives Type as Domain.IDomainEvent
I guesss if it is possible to get be able to cast to right type ( from whereever VS watch window is getting info) the problem could get resolved
----- Result---
Both approach worked. I put both approached to 2 other members in my team and we felt that solution without reflection to be selected as right answer.
Today we will be doing a test with changed implementation and see if there are any issues with this solution in the solution.
I have upvoted reflection based solution as it is also right answer.
As you say, the problem is that you're asking structure map for all instances of IHandle<IDomainEvent> and it has none of those, structuremap has handlers for concrete events. You'd need to construct the type using the actual type of the event and then ask for all handlers of that event:
Type genericHandler = typeof(IHandle<>);
Type[] typeArgs = { eventToDispatch.GetType() };
Type neededHandler = genericHandler.MakeGenericType(typeArgs);
var handlers = ObjectFactory.GetAllInstances(neededHandler);
the problem is that you end up with an IList of objects and you need to cast them to the correct handler type and it get's a bit tricky.... a possible solution is to use reflection to call the Handle() method:
var methodInfo = neededHandler.GetMethod("Handle");
object[] methodArgs = new object[] { eventToDispatch };
foreach (var h in handlers)
{
methodInfo.Invoke(h, methodArgs);
}
Instead of a reflection-based approach, I would recommend using a record to hold onto the type information for you. Something like this:
interface IEventRecord
{
void Dispatch(IEventDispatcher dispatcher);
}
public class EventRecord<TEvent> : IEventRecord where TEvent : IDomainEvent
{
TEvent theEvent;
public EventRecord(TEvent theEvent)
{
this.theEvent = theEvent;
}
public void Dispatch(IEventDispatcher dispatcher)
{
dispatcher.Dispatch(theEvent);
}
}
If you find instantiating an event records to be cumbersome, a helper could infer the type parameter like this:
public static EventRecord<TEvent> CreateEventRecord<TEvent>(TEvent theEvent) where TEvent : IDomainEvent
{
return new EventRecord<TEvent>(theEvent);
}
Which would allow you to instantiate event records like this:
var record = CreateEventRecord(myDomainEvent);
Then instead of holding onto a collection of IDomainEvents, hold onto a collection of IEventRecords that hold the necessary type data to raise themselves:
foreach (var eventRecord in Records)
{
eventRecord.Dispatch(myDispatcher);
}
Related
This question deals with events (base class events and subclass events) and event handlers. I'm working on existing code, that doesn't seem to work the way the author expected it. I have difficulty understanding why it doesn't work though, so I want to understand what's going on before I try to fix the existing code.
I've found the following question, which may or may not suggest I need to make an additional event handler for the subtype events:
C#: Raising an inherited event
If making an additional event handler is indeed the solution, I would still like to learn why this is the case. This is my first question here, and I did really try to search for the answer/explanation to my question, but sincere apologies if it's still something I should've easily found. A stern "RTFM!" with a educational link would be fine with me at this point :)
We have 2 event classes, a base type and a subtype. The subtype event exists to deal with deletion events.
public class BaseTypeEvent
{
public Guid Id { get; set; }
public string Name { get; set; }
public BaseTypeEvent()
{ }
public BaseTypeEvent(SomeRandomThing item)
{
Id = item.Id;
Name = item.Name;
}
}
public class SubTypeEvent : BaseTypeEvent
{
public DateTimeOffset Deleted { get; set; }
public SubTypeEvent()
{
Deleted = DateTimeOffset.UtcNow;
}
}
A usage of these events that seems to be failing:
public class UsageClass
{
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyBaseTypeEvents += HandleMethod;
}
private void HandleMethod(BaseTypeEvent e)
{
if(e is SubTypeEvent)
{
//code that deals with deletion events
//execution never actually gets here
}
//code that deals with events that are not deletion events
}
}
The declaration of the events are in the IEventBusService and EventBusService:
public delegate void MyEventHandler(BaseTypeEvent e);
public interface IEventBusService
{
public event MyEventHandler MyBaseTypeEvents;
void PublishStuff(BaseTypeEvent e);
}
public class EventBusService : IEventBusService, IDisposable
{
public void Initialize()
{
//Bus is MassTransit
Bus.Initialize(sbc =>
{
sbc.Subscribe(subs => subs.Handler<BaseTypeEvent>(OnBaseTypeEvent));
}
}
private void OnBaseTypeEvent(BaseTypeEvent e)
{
if (MyBaseTypeEvents == null) return;
try
{
MyBaseTypeEvents(e);
}
catch (Exception e)
{
//some logging
}
}
public event MyEventHandler MyBaseTypeEvents;
public void PublishStuff(BaseTypeEvent e)
{
//some logging
//publish e to the event bus of our choice (MassTransit)
Bus.Instance.Publish(e);
}
}
And then finally the place where we send the deletion event (to try to delete an item of what I have cleverly named SomeRandomThing above):
eventBusService.PublishStuff(new SubTypeEvent
{
Id = id,
Deleted = DateTimeOffset.UtcNow
});
So the problem: after sending the deletion event with the last line of code above, the if-statement in the UsageClass that checks whether an incoming event is of type SubTypeEvent is never actually true. The type of e in HandleMethod of UsageClass is BaseTypeEvent.
Edit:
I've decided to get rid of the subtyping in this case. We now no longer have BaseTypeEvent and SubTypeEvent, but simply EventTypeA and EventTypeB. One deals with creates and updates, the other deals with deletes (for which we need significantly less information that the creates and updates anyway).
public delegate void MyEventAHandler(EventTypeA e);
public delegate void MyEventBHandler(EventTypeB e);
and
void PublishStuffForA(EventTypeA e);
void PublishStuffForB(EventTypeB e);
and so on.
I've made an extra subscription to MassTransit in the Initialize method of our EventbusService, and made extra handlers in the various UsageClasses that needed them:
sbc.Subscribe(subs => subs.Handler<EventTypeA>(OnEventTypeA));
sbc.Subscribe(subs => subs.Handler<EventTypeB>(OnEventTypeB));
and
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyEventTypeAEvents += HandleMethodForA;
eventBusService.MyEventTypeBEvents += HandleMethodForB;
}
and so on.
I now no longer have to check if an incoming event is of a certain type, I just handle to two types separately. Perhaps a cop out, but it works.
I'm hesitant to qualify this as the answer to my own question, as #Glubus' comments as well as #Travis' comments were what answered my question. Still thought this small edit write-up might be nice to let everyone know what I did as a solution :)
Edit 2:
Sources of information that were helpful:
Derived types are not published to consumers in MassTransit
MassTransit message mis-typing
MassTransit: Message contracts, polymorphism and dynamic proxy objects
https://groups.google.com/forum/#!searchin/masstransit-discuss/polymorphism/masstransit-discuss/q_M4erHQ7OI/FxaotfIzI7YJ
So I can tell you the short answer:
Using polymorphism in messaging contracts introduces coupling.
We believe, as MassTransit developers, that this is a bad idea. It's still possible, but not out of the box. You have to use binary serialization or a customer serializer. The default the serialization pipeline only populates a proxy of the type in the consumer.
I have an issue regarding automatic registration of IEventHandler<> with RegisterManyForOpenGeneric which results in duplicate registrations (something I am doing wrong I am sure).
In my application an event is raised by an external input which is then dispatched to all classes which implement the IEventHandler<> of the incoming event type:
// during bootstrap, the below code is called
resolver.RegisterManyForOpenGeneric(typeof(IEventHandler<>), AppDomain.CurrentDomain.GetAssemblies());
// when the app is running, an external event is published below:
public void PublishEvent(object evnt)
{
var handlerType = (typeof(IEventHandler<>)).MakeGenericType(evnt.getType());
var handlers = resolver.GetAllInstances(handlerType).ToList();
foreach(var handler in handlers)
{
/* do some reflection to get method */
method.Invoke(handler, new[] { evnt } });
}
}
// the below is an event handlers that get automatically wired up OK
class TopicVoteStatisticsProjection : IEventHandler<AdminActedOnTopic>
{
public void Handle(AdminActedOnTopic evnt)
{
// for every event, this gets called once and all is good
}
}
With the above all the IEventHandler<> classes are wired up automatically, and all events published via the above code are sent to the handlers OK (for the above scenario where I have the single interface IEventHandler<AdminActedOnTopic>).
If however I register more than one event handler interface within the same implementation class:
class TopicVoteStatisticsProjection : IEventHandler<UserVotedOnTopic>, IEventHandler<AdminActedOnTopic>
{
public void Handle(UserVotedOnTopic evnt)
{
}
public void Handle(AdminActedOnTopic evnt)
{
// for every event, this gets called twice!!
}
}
Then what happens is is the same handler for IEventHandler is returned twice as:
handlers = resolver.GetAllInstances(typeof(IEventHandler<AdminActedOnTopic>)).ToList();
/* above query returns the following instances:
Projections.TopicVoteStatistics.TopicVoteStatisticsProjection
Projections.TopicVoteStatistics.TopicVoteStatisticsProjection
*/
This is bad as it doubles up on my calculations! In this case the two events are related and I would ideally like to keep them together in the same handler implementation.
My question is please - How can I have automatic registration of handlers, some of which that implement more than one IEventHandler<> interface, without the duplicate registrations?
I think that the behaviour you are seeing is a bug which was introduced in version 2.7. It is described in detail here: https://simpleinjector.codeplex.com/workitem/20996
It should be fixed from version 2.7.2.
I am kind of new to programming in this manner - is there a way that I can work around or a recommended practice to using events and handlers?
eg:
class objectA
{
public List<Handler> handlers;
...
public onActionHappened
{
foreach(Handler h in handlers)
{
raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null
}
}
raiseEvent() will go on an call a few other methods, one of which will invoke DeleteThis(). When everything ends and the program flow returns back to raiseEvent() at the "}" for the foreach loop, it finds that handler has been modified = null, thus throwing the error of InvalidOperationException.
Some method handling should disable this objectA as part of the functionality - thus Deletethis() MAY be called by client code at some point. To fix this, I had modified from List handlers to just a single Handler object, but I feel that that should be a better way of workaround. Or better way of coding.
Any advice? Thanks in advance!
If you use ToArray on the list, you create a copy of its contents and are not dependant on the handler variable itself:
foreach(Handler h in handlers.ToArray()
{
//optional break if you don't want the loop to continue after DeleteThis is called: if(handlers==null)break;
raiseEvent(this, eventArgs);
}
To address the core of your question: The most straightforward way to fix the issue is to assign the list to a local variable before enumerating over it.
class objectA
{
public List<Handler> handlers;
...
public void OnActionHappened()
{
List<Handler> lh = handlers;
// TODO: Would probably make sense to check if lh is null here.
foreach(Handler h in lh)
{
h.raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null;
}
}
There is really no need to create a copy of the list as suggested elsewhere.
Since you seem to be new to C# programming, let me give you some idea what is going on here.
List<T> is a reference type. Let us assume that you create a new List<T> by calling its constructor:
List<Handler> handlers = new List<Handler>();
Now, executing this statement creates two things in the computer's memory:
The list object itself.
A variable ("handlers") that refers to the list object.
Now, if the computer executes the following line:
List<Handler> lh = handlers;
we end up with something like this:
Finally, if the computer executes the following line:
handlers = null;
the situation looks as follows:
As you can see, this way we maintain a valid reference to the list object via the local list variable "lh" and setting the member variable "handlers" to null doesn't affect the foreach enumeration any longer.
An event cannot be triggered outside the class in which the event is defined. So, if you move handlers outside class A, you can no more trigger events in handlers in the class A.
To work around this issue, put handlers in another class, say class B, and define a public method that triggers the events in the handlers in the class B (in this case, the onActionHappened method). For class A, simply call that public method (onActionHappened) of the class B.
I'm not sure how to get a collection of the observers of an event from the observed class, when using events and delegates.
http://msdn.microsoft.com/en-us/library/aa645739%28v=vs.71%29.aspx
In this example an instance of EventListener is subscribed to an instance of ListWithChangedEvent. Using the vanilla observer pattern it would be easy to get a collection objects that are listening to ListWithChangedEvent (as it has to maintain a collection of observers anyway). However, using events, its a bit less clear how to produce this collection within ListWithChanged of the observer objects.
Is it something like:
Changed.GetInvocationList().Select(item => item.Target).OfType<EventListener>().ToList();
Seems doubtful, it seems a bit complex.
Edit: This compiles and gives me my answer. I'm just a bit wary that its a bad way to do it.
You're just about there, you just have to remember that you can't use GetInvocationList() on delegates marked with event from outside the declaring class, so you need to either declare a backing field or make the call from within the class.
class EventListener
{
public EventPublisher publisher = new EventPublisher();
public EventListener()
{
publisher.Event += HandleEvent;
}
void HandleEvent(object sender, EventArgs e)
{
}
}
class EventPublisher
{
public event EventHandler Event;
public List<EventListener> GetListeners()
{
return Event.GetInvocationList().Select(i => i.Target).OfType<EventListener>().ToList();
}
}
EDIT: If you're dealing with a 3rd party class, so you can't use a backing field or call GetInvocationList() within the class, then you can use reflection:
var fieldInfo = typeof(EventPublisher).GetField("Event", BindingFlags.Instance | BindingFlags.NonPublic);
var eventHandler = (EventHandler)fieldInfo.GetValue(listener.publisher);
var listeners = eventHandler.GetInvocationList().Select(i => i.Target).ToList();
I am getting ready to create a generic EventArgs class for event args that carry a single argument:
public class EventArg<T> : EventArgs
{
// Property variable
private readonly T p_EventData;
// Constructor
public EventArg(T data)
{
p_EventData = data;
}
// Property for EventArgs argument
public T Data
{
get { return p_EventData; }
}
}
Before I do that, does C# have the same feature built in to the language? I seem to recall coming across something like that when C# 2.0 came out, but now I can't find it.
Or to put it another way, do I have to create my own generic EventArgs class, or does C# provide one? Thanks for your help.
No. You probably were thinking of EventHandler<T>, which allows you to define the delegate for any specific type of EventArgs.
I personally don't feel that EventArgs<T> is quite as good of a fit, though. The information used as a "payload" in the event args should be, in my opinion, a custom class to make its usage and expected properties very clear. Using a generic class will prevent you from being able to put meaningful names into place. (What does "Data" represent?)
I must say I don't understand all the 'purists' here.
i.e. if you already have a bag class defined - which has all the specifics, properties etc. - why the hack create one extra unnecessary class just to be able to follow the event/args mechanism, signature style?
thing is - not everything that is in .NET - or is 'missing from' for that matter - is 'good' - MS's been 'correcting' itself for years...
I'd say just go and create one - like I did - cause I needed it just like that - and saved me lot of time,
It does exist. At least, it does now.
You can find DataEventArgs<TData> in some different Microsoft assemblies/namespaces, for instance Microsoft.Practices.Prism.Events. However these are namespaces that you might not find natural to include in your project so you might just use your own implementation.
In case you choose not to use Prism, but still would like to try a generic EventArgs approach.
public class GenericEventArgs<T> : EventArgs
{
public T EventData { get; private set; }
public GenericEventArgs(T EventData)
{
this.EventData = EventData;
}
}
// Use the following sample code to declare ObjAdded event
public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;
// Use the following sample code to raise ObjAdded event
private void OnObjAdded(TargetObjType TargetObj)
{
if (ObjAdded!= null)
{
ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
}
}
// And finnaly you can subscribe your ObjAdded event
SubscriberObj.ObjAdded += (object sender, GenericEventArgs<TargetObjType> e) =>
{
// Here you can explore your e.EventData properties
};
THERE IS NO BUILT-IN GENERIC ARGS.
If you follow Microsoft EventHandler pattern, then you implement your derived EventArgs like you suggested:
public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.
HOWEVER - if your team style guide accepts a simplification - your project can use a lightweight events, like this:
public event Action<object, string> MyStringChanged;
usage :
// How to rise
private void OnMyStringChanged(string e)
{
Action<object, string> handler = MyStringChanged; // thread safeness
if (handler != null)
{
handler(this, e);
}
}
// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);
Usually a PoC projects use the latter approach. In professional applicatons, however, be aware of FX cop justification #CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx
The problem with a generic type is that even if DerivedType inherits from BaseType, EventArgs(DerivedType) would not inherit from EventArgs(BaseType). Using EventArgs(BaseType) would thus prevent later using a derived version of the type.
The reason this does not exist is because what would end up happening is you implement this, and then when you go to fill in the T you should create a class with strongly typed unambiguous properties that acts as the data bag for your event arg, but halfway through implementing that you realize there's no reason you don't just make that class inherit from EventArgs and call it good.
Unless you just want a string or something similarly basic for your data bag, in which case there are probably EventArgs classes standard in .NET which are meant to serve whatever simple purpose you're getting at.