Command pattern and handling of asynchronous operations in C #

I would like to hear opinions on the best way to handle asynchronous operations with the Command pattern. Say we have the following example:

public class MyCommand { // Sets up receiver and does whatever stuff public void Execute() { _myReceiver.DoSomething(); } } 

The problem is this: MyCommand does not know if MyReceiver.DoSomething () has asynchronous parts of the code. If I wanted to push MyCommand to the cancellation table after it was executed, I could not guarantee that its receiver action was completely completed, which makes it undefined to find out if MyCommand reached the state in which the capability was canceled or not.

I personally thought of the following solution:

  • Implement some kind of state control in Command
  • Include "BeginExecute" and "EndExecute" in Command
  • Include events in MyReceiver and make the team subscribe to them (this seems smelly to me)

To wrap everything up, MyCommand will turn into:

 public class MyCommand { public MyCommand(MyReceiver receiver) { _myReceiver = receiver; _myReceiver.DoSomethingFinished += () => this.EndExecute(); } public void BeginExecute() { this.EnterExecutionState(); _myReceiver.DoSomething(); } public void EndExecute() { this.LeaveExecutionState(); } // State handling related stuff } 

Now I have the means to make sure that the command receiver has completed any action and is ready to push it onto the cancel stack. However, for the spam case, every single Receiver class containing asynchronous operations really bothers me.

I have not found much about this topic on the Internet and would like to hear different approaches.

OBS: getting a command to manage all asynchronous code is not an option :).

+4
source share
4 answers

Something like that?

 public interface ICommand { void Execute(); event EventHandler Finished; } public class MyCommand : ICommand { public MyCommand(MyReceiver receiver) { _myReceiver = receiver; _myReceiver.DoSomethingFinished += () => Finished(); // dont forget null check here. } public void Execute() { _myReceiver.DoSomething(); } public event EventHandler Finished; } 

Thus, the user of this command can register the Finished event so that he knows when the command has completed asynchronous behavior and can act accordingly.

Or, if you do not want to use the event, then what about a callback?

 public class MyCommand : ICommand { public MyCommand(MyReceiver receiver) { _myReceiver = receiver; } public void Execute() { _myReceiver.DoSomething(() => Finished()); // dont forget null check here. } public event EventHandler Finished; } 

In any case, you just need MyReciever to notify its caller that it has finished. You can not get around it.

+1
source

I think you have too much going on in the same class. I would break it like this:

 // An immutable command, to be handled in-process. // ICommand is a marker interface with no members. public class DoSomething : ICommand { public readonly Id; public DoSomething(Guid id) { Id = id; } } // To be handled out-of-process. [AsynchronousCommand] public class DoSomethingThatTakesAReallyLongTime : ICommand { public readonly Id; public DoSomethingThatTakesAReallyLongTime(Guid id) { Id = id; } } // This guy could take any number of dependencies: ISomethingRepository, DbContext, etc. // Doesn't matter, but it probably gonna have dependencies. public class DoSomethingHandler : IHandler<DoSomething> { public void Handle(DoSomething command) // IHandler<T> only member { // CRUD or call call a domain method } } public class CommandService : ICommandService { public void Execute(params ICommand[] commands) // ICommandService only member { foreach(var command in commands) { var handler = GetHandler(command); // Could use your IOC container. if (HasAsyncAttribute()) new Action(() => handler.Handle(command)).BeginInvoke(null, null); else handler.Handle(command); } } } // Something that might consume these public class SomethingController { private readonly ICommandService _commandService; public SomethingController(ICommandService commandService) { _commandService = commandService; } [HttpPost] public void DoSomething(Guid id) { _commandService.Execute(new DoSomething(id)); } [HttpPost] public void DoSomethingThatTakesAReallyLongTime(Guid id) { _commandService.Execute(new DoSomethingThatTakesAReallyLongTime(id)); } } 

The big advantage here is that you can distribute your commands to clients without explicitly dragging all the dependencies that come with the handlers. Handlers should not be known to the client. The whole client should know that he sent the team, and all teams should be considered successful.

+2
source

First, I would add Async to the method name to explicitly signal to your consumer of the Command class that this method is executing asynchronously.

Secondly, I would add as a parameter a Action<T> , which will be called as an async call complete method. Thus, this calling method can be notified of the termination of asynchronous transfer.

Edit

obj.DoSomethingAsync(... params, Action<T> onComplete)

+1
source

If you intend to require that all processing be completed before control returns to your Execute method without changing the behavior of the calling code, you can change the way you perform your actions.

Initialize all your asynchronous calls first and block (wait) in the current thread to return calls. I'm not sure what the nature of your asynchronous calls is, for example, if they are in a thread you know about, or will be returned on an arbitrary thread, but you should be able to create some kind of synchronization thread for your problem.

Try using Semaphore to block the current thread (after calling async methods) and free the semaphore when all your async methods have returned the answer (s). This will result in a "resynchronization" of your asynchronous calls.

You can use a different synchronization method, but the Semaphore is simple enough to understand.

+1
source

Source: https://habr.com/ru/post/1389547/


All Articles