// // CommandProcessor.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NosSmooth.Core.Errors; using Remora.Results; namespace NosSmooth.Core.Commands; /// /// Calls for the executing command /// by using dependency injection. /// public class CommandProcessor { private readonly IServiceProvider _provider; /// /// Initializes a new instance of the class. /// /// The dependency injection provider. public CommandProcessor(IServiceProvider provider) { _provider = provider; } /// /// Processes the given command, calling its handler or returning error. /// /// The command to process. /// The cancellation token for cancelling the operation. /// A result that may or may not have succeeded. /// Thrown on critical error. public Task ProcessCommand(ICommand command, CancellationToken ct = default) { var processMethod = GetType().GetMethod ( nameof(DispatchCommandHandler), BindingFlags.NonPublic | BindingFlags.Instance ); if (processMethod is null) { throw new InvalidOperationException("Could not find process command generic method in command processor."); } var boundProcessMethod = processMethod.MakeGenericMethod(command.GetType()); return (Task)boundProcessMethod.Invoke(this, new object[] { command, ct })!; } private Task DispatchCommandHandler(TCommand command, CancellationToken ct = default) where TCommand : class, ICommand { using var scope = _provider.CreateScope(); var commandHandler = scope.ServiceProvider.GetService>(); if (commandHandler is null) { return Task.FromResult(Result.FromError(new CommandHandlerNotFound(command.GetType()))); } return commandHandler.HandleCommand(command, ct); } }