I'm looking for some advice/recomendations on structuring an application which involved multiple classes that need access to each other for the sole purpose of tasking (i.e. class A needs to pass something to class B for processing, but class A doesn't care about the result. Class B may later produce a result which needs to be passed to class A for transmission over a network connection).
The application I'm designing (in C#) consists of two primary I/O classes: a web socket client and a named pipe server, both of which receive and send various messages from/to their connected clients.
Received messages need to be passed to one of many (3-4 at this stage but this may grow) types of processors depending on the message type. These processors may generate responses at a later stage at which point these processers will need to send data via either the websocket or the named pipe connection.
The only real limitation I have is the messages must be processed in the order they are received.
Given this setup, what would be a good way to pass tasking around my application?
I've been tossing up several options so far:
Option 1 - References everywhere
Not ideal. In this situation, when my application starts it would create a websocket client, named pipe server, and all processor classes then pass all required references via setters (taskProcessor1.webSocketHandler = webSocketHandler;
etc). This feels like a horrible solution and is not scalable.
Option 2 - Static classes
This could work if I place my websocket, named pipe and each processor type behind a static manager class of some kind which would accept tasking and pass it to various instances under it but this feels like one of those abuse of staic classes situations.
Option 3 - Event Handlers
Using .NET's event handlers works (this is my currently working solution) however its not that nice. You essentially end up with either one over arching class which instantiates your IO and processor class instances, then wires up all the event handlers or event handlers calling event handlers to bubble and event up and down your class hirachy.
Option 4 - MediatR
MediatR looks like a potential solution to this issue and should remove the need for the various IO classes to ever need to know about the processors.
Thank you for any recommendations you can provide, I've been thinking about this for days now and am going around in circles on the merits and downsides of each option.