I have WinForms app with MVC pattern implemented, where Model is running asynchronously (backgroundWorker thread) from View (Form). View is subscribed to couple of events that are raised from Model.
Now I need to convert this to WCF app, where event-eventHandler concept has to be present.
At first, I wanted to implement this via callback interface, but in my case one method from Model is raising more than one type of events, and I am constrained on usage of single callback interface when defining service contract.
At this moment I came up with the idea of specifying different type of events as methods in callback service and implement it in client. For example:
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void EventHandler1();
[OperationContract(IsOneWay = true)]
void EventHandler2(string callbackValue);
[OperationContract(IsOneWay = true)]
void EventHandler3(string callbackValue);
}
Should I go along with this solution or there are some better alternatives (publish-subscribe wcf pattern)?
Sounds like you definitely want pub/sub architecture here.
Take a look at Juval Lowy's Publish-Subscribe Framework from this MSDN article:
http://msdn.microsoft.com/en-us/magazine/cc163537.aspx
You can use single method with a base type parameter to activate your call. Then in your service code, jump to specific handler based on the type of the event.
public class BaseEvent { }
public class MyFirstEvent : BaseEvent { }
public class MySecondEvent : BaseEvent { }
public class MyThirdEvent : BaseEvent { }
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void EventHandler(BaseEvent myEvent);
}
public class MyService : ICallbacks
{
public void EventHandler(BaseEvent myEvent)
{
//Now you can check for the concrete type of myEvent and jump to specific method.
//e.g.:
if (myEvent is MyFirstEvent)
{
//Call your handler here.
}
//Another approach can be predefined dictionary map of your event handlers
//You want to define this as static map in class scope,
//not necessarily within this method.
Dictionary<Type, string> map = new Dictionary<Type, string>()
{
{ typeof(MyFirstEvent), "MyFirstEventHandlerMethod" },
{ typeof(MySecondEvent), "MySecondEventHandlerMethod" }
{ typeof(MyThridEvent), "MyThirdEventHandlerMethod" }
};
//Get method name from the map and invoke it.
var targetMethod = map[myEvent.GetType()];
this.GetType().GetMethod(targetMethod).Invoke(myEvent);
}
}
Using a Duplex is not a good idea unless your application runs on the same at least on the same network and there are not proxies, etc to interferer with. You will also end up with a tight coupling between publisher and subscriber.
Related
I'm using the event-based design pattern and I want to know if there's a simple and clean way to make all classes that implement a certain interface also subscribe to a public static event declared on another class. I will try to express what I'm trying to do with a simple code:
public interface IPlayControl
{
void OnStart();
void OnStop();
}
public class ClassWithEvent : SomeOtherClass
{
//this event needs to be subscribed to OnStart/OnStop methods of IPlayControl
public static event Action ActionStarted, ActionStopped;
}
public class Subscriber : IPlayControl
{
public void OnStart() {}
public void OnStop() {}
}
I want all classes like Subscriber to automatically subscribe their OnStart and OnStop methods to those single static ActionStarted, ActionStopped events of the ClassWithEvent.
So instead of registering them everytime like:
ClassWithEvent.ActionStarted += OnStart;
ClassWithEvent.ActionStopped += OnStop;
I think it would be easier and look cleaner without adding these lines to every class.
I feel like it would be an unconventional way of doing this but should I do it manually by checking all types that implement this interface and subscribing their methods with a loop? I found this code on another post.
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Thanks.
I have event handlers that currently have class and method signatures like this:
public class MyEventHandler : IIntegrationEventHandler
public void Handle(IntegrationEventintegrationEvent) // IntegrationEvent is the base class
What I want to do is this (so that the handler can accept the concrete type):
public class MyEventHandler : IIntegrationEventHandler<MyEvent>
public void Handle(MyEvent integrationEvent)
In Startup.cs, I did this:
services.AddTransient<IIntegrationEventHandler<MyEvent>, MyEventHandler>();
The issue is that the service that gets these handlers injected can't use open generics, like this:
public MyService(IEnumerable<IIntegrationEventHandler<>> eventHandlers)
: base(eventHandlers)
Specifying the base class doesn't work either:
public MyService(IEnumerable<IIntegrationEventHandler<IntegrationEvent>> eventHandlers)
: base(eventHandlers)
That gives me 0 handlers.
The current approach works in that I get all 7 handlers injected. But that means the handler has to accept the base class in its method and then cast it. Not a huge deal, but would be nice if I could have the handler accept the concrete type it cares about. Is this possible?
What you request cannot be done directly. C# collections are always bound to a specific item type and that type must be cast if a different type is desired. And IIntegrationEventHandler<MyEvent> and IIntegrationEventHandler<DifferentEvent> are different types.
As an alternate solution, you could dispatch events through an intermediary (dispatcher) and route them to concrete handler type using reflection and DI. The handlers will be registered with DI with the specific event type they declare to handle. You can also handle multiple types of events with a single handler implementation. The dispatcher will inject a collection of concrete event handlers based on run-time type of the received event directly from IServiceProvider.
I have not compiled or tested the following code but it should give you the general idea.
Startup.cs
services
.AddTransient<IIntegrationEventHandler<MyEvent>, MyEventHandler>()
.AddTransient<IntegrationEventDispatcher>();
IntegrationEventDispatcher.cs
private readonly IServiceProvider _serviceProvider;
public IntegrationEventDispatcher(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Dispatch(IntegrationEvent #event)
{
var eventType = #event.GetType();
// TODO: Possibly cache the below reflected types for improved performance
var handlerType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
var handlerCollectionType = typeof(IEnumerable<>).MakeGenericType(handlerType);
var handlers = (IEnumerable)_serviceProvider.GetService(handlerCollectionType);
var handleMethod = handlerType.GetMethod("Handle", eventType);
foreach (var handler in handlers)
{
handleMethod.Invoke(handler, new[] { #event });
}
}
MyService.cs
// ...
private readonly IntegrationEventDispatcher _eventDispatcher;
public MyService(IntegrationEventDispatcher eventDispatcher)
{
_eventDispatcher = eventDispatcher;
}
public void DoStuffAndDispatchEvents()
{
// ...
_eventDispatcher.Dispatch(new MyEvent());
_eventDispatcher.Dispatch(new DifferentEvent());
}
Edit:
Generics-based dispatcher implementation (gist):
public void Dispatch<TEvent>(TEvent #event) where TEvent : IntegrationEvent
{
var handlers = _serviceProvider.GetRequiredService<IEnumerable<IIntegrationEventHandler<TEvent>>>();
foreach (var handler in handlers)
{
handler.Handle(#event);
}
}
Edit 2:
In order to support event handling from the base type, there are a couple of approaches that come to my mind:
a) Use the reflection-based approach from above.
Performance-wise this won't be the best but it will work for any type it will receive.
b) Use a type switch
Switch on event type to invoke Dispatch<T> with proper type. The downside is that you need to list all supported event types and update the list when any new event type is introduced. Also, this might be somewhat tricky to catch with tests.
The IntegrationEventDispatcher logic becomes
public void Dispatch(IntegrationEvent #event)
{
switch (#event)
{
case MyIntegrationEvent e:
Dispatch(e); // Calls Dispatch<TEvent> as the overload with a more specific type
break;
case OtherIntegrationEvent e:
Dispatch(e);
break;
default:
throw new NotSupportedException($"Event type {#event.GetType().FullName} not supported.");
}
}
private void Dispatch<TEvent>(TEvent #event) where TEvent : IntegrationEvent
{
var handlers = _serviceProvider.GetRequiredService<IEnumerable<IEventHandler<TEvent>>>();
foreach (var handler in handlers)
{
handler.Handle(#event);
}
}
Gist with a minimal implementation is available here.
c) Use visitor pattern
Make base event type accept a visitor which visits the concrete event type. This is quite a bit more code and requires changes to the base event type. When new event type is added, it is automatically supported, although a new overload may be necessary if overloads are used instead of generic method (as in proper visitor).
A IIntegrationEventVisitor should exist on the same level as IntegrationEvent - that may be an architectural issue, however, since events are already designed as objects, I would expect that having a behavior should not be a problem, especially this abstract.
IntegrationEvent.cs
public abstract class IntegrationEvent
{
public abstract void Accept(IIntegrationEventVisitor visitor);
}
MyIntegrationEvent.cs
public class MyIntegrationEvent : IntegrationEvent
{
public override void Accept(IIntegrationEventVisitor visitor)
{
visitor.Visit(this); // "this" is the concrete type so TEvent is inferred properly
}
}
IIntegrationEventVisitor.cs
public interface IIntegrationEventVisitor
{
// Note: This is not a proper visitor, feel free to implement
// overloads for individual concrete event types for proper design.
// Generic method is not very useful for a visitor in general
// so this is actually an abstraction leak.
void Visit<TEvent>(TEvent #event) where TEvent : IntegrationEvent;
}
IntegrationEventDispatcher.cs
public class IntegrationEventDispatcher : IIntegrationEventVisitor
{
// Previously known as Dispatch
public void Visit<TEvent>(TEvent #event) where TEvent : IntegrationEvent
{
var handlers = _serviceProvider.GetRequiredService<IEnumerable<IEventHandler<TEvent>>>();
foreach (var handler in handlers)
{
handler.Handle(#event);
}
}
}
Gist with a minimal implementation is available here.
d) Take a step back
If you want to dispatch a base type, maybe injecting concrete handlers is not what you need at all and there could be another way.
How about we create an event handler that takes a base type and handles it only if it's relevant? But let's not duplicate these relevance checks in each handler, let's make a class that does it for us in general and delegates to proper handlers.
We will use IIntegrationEventHandler as a general handler to accept the base type, implement it with a generic type that checks if the accepted type is relevant and then forwards it to handlers of that type which implement IIntegrationEventHandler<TEvent>.
This approach will let you use constructor injection everywhere as you originally requested and generally feels like the closest to your original approach. The downside is that all handlers are instantiated even if they are not used. This could be avoided with e.g. Lazy<T> over the concrete handlers collection.
Note that there is no generic Dispatch method or any of its variant, you just inject a collection of IIntegrationEventHandler where each delegates to collection of IIntegrationEventHandler<TEvent> if the received event type is TEvent.
IIntegrationEventHandler.cs
public interface IIntegrationEventHandler
{
void Handle(IntegrationEvent #event);
}
public interface IIntegrationEventHandler<TEvent> where TEvent : IntegrationEvent
{
void Handle(TEvent #event);
}
DelegatingIntegrationEventHandler.cs
public class DelegatingIntegrationEventHandler<TEvent> : IIntegrationEventHandler where TEvent : IntegrationEvent
{
private readonly IEnumerable<IEventHandler<TEvent>> _handlers;
public DelegatingIntegrationEventHandler(IEnumerable<IEventHandler<TEvent>> handlers)
{
_handlers = handlers;
}
public void Handle(IntegrationEvent #event)
{
// Check if this event should be handled by this type
if (!(#event is TEvent concreteEvent))
{
return;
}
// Forward the event to concrete handlers
foreach (var handler in _handlers)
{
handler.Handle(concreteEvent);
}
}
}
MyIntegrationEventHandler.cs
public class MyIntegrationEventHandler : IIntegrationEventHandler<MyIntegrationEvent>
{
public void Handle(MyIntegrationEvent #event)
{
// ...
}
}
Gist with a minimal implementation is available here. Check it out for actual setup and usage as it is slightly more complex to get it right.
In the past I've built a MessageDispatcher component that scans an assembly for types decorated with certain attributes and initializes an instance of each. Then, when any object is fed to the MessageDispatcher instance, every previously initialized instance which contains a method which signature contains the type of the passed object has said method triggered with the specified parameter. For example, in a scenario like:
[Listener]
public class MyListener
{
MessageDispatcher _dispatcher; //Assigned elsewhere
[MessageListener]
public async Task DoSomething(int value)
{
var otherValue = await _dispatcher.Next<string>();
Console.WriteLine($"{value} is {otherValue}.");
}
}
The following code initializes an instance of the MyListener class, calls DoSomething and prints "7 is okay.":
var listener = new MessageDispatcher(typeof (ListenerAttribute));
listener.Dispatch(7);
listener.Dispatch("okay");
I would like to know if there are any libraries out there that are dedicated to or include a service like such. It has to be able to:
Scan assemblies and initialize types based on an attribute.
Dynamically "subscribe" to certain types
"Wait" on a value to be pumped from the dispatcher (like with the Next method in my example).
(as library recommendations is not allowed per the SO rules, here is an attempt to instead answer with an implementation)
You can get that with virtually any IoC. All they need is to be able to register services using an attribute or some other conventional way.
As for the message dispatching. Just create an interface like IMessageHandler<TMessage>. Implement it on all classes that should handle messages.
Example:
public interface IMessageHandler<TMessage>
{
void Handle(TMessage msg);
}
public class SomeService : IMessageHandler<UserCreated>
{
//[.. all other methods ..]
public void Handle(UserCreated msg)
{
// ...
}
}
To publish messages you create a dispatcher. Since you use a container you do not have to make it static. Use your container inside it (service location) to dispatch the messages. Now some peeps might say oohh no, service location is anti-pattern, buhuhuhu. Well no. Not in all cases. In this case it's an implementation details in a class with the specific purpose to identify and invoke other classes.
public interface IMessageDispatcher
{
void Dispatch<TMessage>(TMessage msg);
}
// The actual implementation differs
// depending on your choice of container.
public class ContainerBasedMessageDispatcher : IMessageDispatcher
{
Container _container;
public ContainerBasedMessageDispatcher(Container container)
{
_container = container;
}
public void Dispatch<TMessage>(TMessage message)
{
using (var scope = container.BeginLifetimeScope())
{
var handlers = scope.Resolve<IEnumerable<IMessageHandler<TMessage>>();
foreach (var handler in handlers)
{
handler.Handle(message);
}
}
}
}
The code is written directly in SO. So it might not work as-is. But hopefully it's given you an idea how to achieve what you want.
Usage:
public class UserService
{
IMessageDispatcher _dispatcher;
public UserService(IMessageDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Create(User user)
{
//[...]
_dispatcher.Dispatch(new UserCreated(user.Id));
}
}
this do however not dynamically allow you to subscribe on what you want. If just ignoring unwanted messages is not feasible. Then this answer is not for you.
I read about Strategy pattern in this question. I ran into a problem when wrapping all this in MessageProcessor, and cannot give the user of my class any strong typed callback.
public class MessageProcessor
{
private IMessageProcessing Processing {get; set;} // a processing strategy
public void ProcessMessage(HubMessage message) //SignalR data message
{
ContentBase content = MessageProcessingBase.GetMessageContent(message); //just get content object from message
if (content is DocumentFile) //this content holds info about file to download
Processing = new DocumentFileProcessing();//implementation of IMessageProcessing strategy interface
Processing.ProcessMessage(message); //here a file is being downloaded and I want to raise event or call a callback method to inform a client (this class's caller) about a path of downloaded file
}
}
I tried to explain my problem in code comments. Is it possible to give a user of my DLL any typed callback if I only provide a MessageProcessor class that determines a type of message and calls typed strategy class? Or I should leave the user to write strategy determination code (in this case MessageProcessor)?
I know I can have event to call when processing is done, but that event would be in base MessageProcessing class, so it cannot have typed event arguments.
EDIT I provided some more code, to help understand what I need.
//lib code
public class Message
{
public string From { get; set; }
public string To { get; set; }
public MessageContentBase Conent{get;set;}
}
public class MessageContentBase
{
public string Note{get; set;}
}
public class DocumentFile: MessageContentBase
{
public string FilePath { get; set; }
}
public abstract class MessageProcessing
{
public abstract void ProcessMessage(Message message);
}
public class DocumentFileMessageProcessing:MessageProcessing
{
public override void ProcessMessage(Message message)
{
DocumentFile df = message.Conent as DocumentFile;
//1. download file
//2. raise event or do callback in client code with parameter df.FilePath
}
}
public class SomeOtherProcessing : MessageProcessing
{
public override void ProcessMessage(Message message)
{
MessageContentBase content = message.Conent;
//log.WriteLine("Message was from " + message.From);
}
}
public class MessageProcessor
{
MessageProcessing processing;
public void ProcessMessage(Message message)
{
if (message.Conent is DocumentFile)
processing = new DocumentFileMessageProcessing();
//else if, else if.....
processing.ProcessMessage(message);
}
}
// end lib code
public class Program //client code
{
public static void Main(string[] args)
{
Message m = new Message();
MessageProcessor mp = new MessageProcessor();
mp.ProcessMessage(m);
// need something to call return-result-type-dependent post processing code
}
}
It is not strictly necessary to use an interface for the strategy pattern. You can declare an abstract class MessageProcessing and a method ProcessMessage which uses the template pattern. In his logic, the code executes internal processing method and then raises an event.
Something like this:
internal abstract class MessageProcessing {
// TODO: declare event variable
abstract string ProcessInternalMessage(HubMessage message);
void ProcessMessage(HubMessage message) {
// Here he call the ProcessInternalMessage which returns
// the path. Depending on the derived class the logic or the processor.
string path = this.ProcessInternalMessage(message);
// here we raise event with the path in the parameters
}
}
As you can see, the ProcessMessage acts as a template. This means that it has a logic flow (very simple, just two lines of code) in which first executes an abstract method. After that, it raise the event.
The abstract method must be implemented for each class that derives from this class. This method has the logic of your classes that implement your current interface.
With this, you only execute methods on the abstraction, and internally the event is raised.
Is that what you need?
Greetings!
I ran into a problem when wrapping all this in MessageProcessor, and cannot give the user of my class any strong typed callback.
The problem here is that MessageProcessor creates all MessageProcessing instances.
Or I should leave the user to write strategy determination code (in this case MessageProcessor)?
The solution is to write a MessageProcessor, that can be configured by the user by registering MessageProcessing instances.
Is it possible to give a user of my DLL any typed callback if I only provide a MessageProcessor class that determines a type of message and calls typed strategy class?
Configuration phase:
The user creates a MessageProcessor instance provided by the library
The user creates all necessary MessageProcessings, provided by the library or by the user, registers callbacks and subscribes to MessageProcessings events
The user registers all created MessageProcessings in the MessageProcessor
Message processing phase:
The user calls the configured MessageProcessor to process a Message
The configured MessageProcessor looks though registered MessageProcessings for a MessageProcessing, capable of processing the Message
The MessageProcessor passes the Message to the found MessageProcessing
The MessageProcessing makes all necessary callbacks and raises events to interact with the user
Hint:
To check if MessageProcessing is capable of processing a Message add abstract bool CanProcess(Message) method to the base MessageProcessing class and override it in concrete MessageProcessing classes.
I have a class that instantiates two classes which implement interfaces. I want one class to notify another class that something is OK. I could do it with an Action and then use private variables in the class but wondered if there was a direct way of doing it with properties so that when a property's value changes it updates a property on another class.
For example:
public class MyClass
{
public ILogger Logger {get;set;}
public ILogic Logic {get;set;}
private Form MyWinform;
public void Setup()
{
MyWinform = new MyWinform();
MyWinform.StartBatch += Logger.CreateFile; //Create file when user presses start
//How can I set a property on ILogic to be AllOk once ILogger says so??
//I could use an Action so that once all is ok I call IDecidedAlOK in ILogger which
//can then assign a private bool variable inside the class
Logic.ItsOKMethodSoSetVariableToTrue = Logger.IDecidedAllOKMethod;
}
public void DataIn(string Value)
{
Logic.DataIn(Value);
}
public void CreateInstances()
{
Logger = new FileLogger();
Logic = new MyLogic();
}
}
public class MyLogic : ILogic
{
public void DataIn(string Value)
{
//I want to check that all is ok before I do anything
//if (!AllOK)
//return;
//Do stuff
}
}
Implement INotifyPropertyChanged interface and subscribe to PropertyChanged event
I feel like it might be a bit more conventional to have your ILogger interface expose something like a "FileCreated" or "Ready" event, and allow your application to handle that event in order to update the ILogic object (or do whatever else is necessary).
EDIT: my apologies, after re-reading the question, I think I misunderstood what you were asking for.
There isn't any "natural" object that does exactly what you're asking, but you could create an anonymous delegate (or lambda expression) for this purpose:
Action<bool> loggerResult = (value) => Logic.ItsOKMethodSoSetVariableToTrue = value;
A property internally consists of two private methods, a get_XXX and a set_XXX, so unless you want to fetch the MethodInfo of those methods and invoke them (which are again methods) you have no choice but to implement a method calling approach.
Subscribing to event (INotifyPropertyChanged or some custom one) is OK, so is the method to pass a lambda-setter, but in some cases it might be more convinient to use a shared context object (much like the shared memory concept):
class ConversationContext
{
public bool EverythingIsOK { get; set;}
}
This object is passed to all interested objects (ILogic and ILogger) and they operate directly on it, instead of some internal properties. If change notifications are required, Implement INotifyPropertyChanged on it.
One positive aspect of this approach is that you won't get tangled in repeatedly firing events triggering other events and so on. A single object will hold the current state and no recurrent updates are needed.
Again, this is just one of many options.