public async Task <Command> ProcessCommandAsync(ICommandSenderChannel commandSenderChannel, Command requestCommand, CancellationToken cancellationToken) { if (commandSenderChannel == null) { throw new ArgumentNullException(nameof(commandSenderChannel)); } if (requestCommand == null) { throw new ArgumentNullException(nameof(requestCommand)); } if (requestCommand.Status != CommandStatus.Pending) { throw new ArgumentException("Invalid command status", nameof(requestCommand)); } if (requestCommand.Method == CommandMethod.Observe) { throw new ArgumentException("Invalid command method", nameof(requestCommand)); } if (requestCommand.Id.IsNullOrEmpty()) { throw new ArgumentException("Invalid command id", nameof(requestCommand)); } #if NETSTANDARD1_1 // TODO: Without the TaskCreationOptions.RunContinuationsAsynchronously, there may occurs deadlock on command results. var tcs = new TaskCompletionSource <Command>(); #else var tcs = new TaskCompletionSource <Command>(TaskCreationOptions.RunContinuationsAsynchronously); #endif if (!_pendingCommandsDictionary.TryAdd(requestCommand.Id, tcs)) { throw new InvalidOperationException("Could not register the pending command request. The command id is already in use."); } try { #if NETSTANDARD1_1 using (cancellationToken.Register(() => tcs.TrySetCanceled())) #else using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) #endif { await commandSenderChannel.SendCommandAsync(requestCommand, cancellationToken).ConfigureAwait(false); var result = await tcs.Task.ConfigureAwait(false); return(result); } } finally { TaskCompletionSource <Command> removedTcs; _pendingCommandsDictionary.TryRemove(requestCommand.Id, out removedTcs); } }
public async Task <Command> ProcessCommandAsync(ICommandSenderChannel commandSenderChannel, Command requestCommand, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (commandSenderChannel == null) { throw new ArgumentNullException(nameof(commandSenderChannel)); } if (requestCommand == null) { throw new ArgumentNullException(nameof(requestCommand)); } if (requestCommand.Status != CommandStatus.Pending) { throw new ArgumentException("Invalid command status", nameof(requestCommand)); } if (requestCommand.Id.IsNullOrEmpty()) { throw new ArgumentException("Invalid command id", nameof(requestCommand)); } var tcs = new TaskCompletionSource <Command>(TaskCreationOptions.RunContinuationsAsynchronously); if (!_pendingCommandsDictionary.TryAdd(requestCommand.Id, tcs)) { throw new InvalidOperationException("Could not register the pending command request. The command id is already in use."); } try { using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) { await commandSenderChannel.SendCommandAsync(requestCommand, cancellationToken).ConfigureAwait(false); var result = await tcs.Task.ConfigureAwait(false); return(result); } } finally { TaskCompletionSource <Command> removedTcs; _pendingCommandsDictionary.TryRemove(requestCommand.Id, out removedTcs); } }
/// <summary> /// Sends a command to the remote node. /// </summary> /// <param name="channel"></param> /// <param name="command"></param> /// <returns></returns> public static Task SendCommandAsync(this ICommandSenderChannel channel, Command command) { return(channel.SendCommandAsync(command, CancellationToken.None)); }