命令客户端在运行时添加/删除支持的命令

问题描述 投票:0回答:0

我正在尝试实现一个接收命令并执行它的命令客户端。命令客户端向远程服务报告支持的命令。更改设置后,可能会发生在应用程序运行期间不再支持某些命令的情况。对我来说最具挑战性的是如何即时实现添加/删除支持的命令。

如果命令在整个运行时都是已知的,那可能会很简单,我会按以下方式进行:

public interface ICommandExecutor
{
    string CommandName;
    Task ExecuteCommand(ICommand command);
}

public class CommandClient
{
    private Dictionary<string, ICommandExecutor> _command2Executor;
    public CommandClient(IEnumerable<ICommandExecutor> commandExecutors)
    {
        foreach (var executor in commandExecutors)
        {
            if (!_command2Executor.TryAdd(executor.CommandName, executor))
            {
                throw new ArgumentException("There are multiple executors supporting same command.");
            }            
        }
    }

    public void Start(){
        ... register all commands in the remote service
    }

    private Task OnCommandRecived(ICommand command){
      if(!_command2Executors.TryGetValue(command.Name, out var executor)){
         throw new InvalidOperationException();
      }
      return executor.Execute(command);
    }
}

但在我的情况下,可能会发生设置将被更改并且不再支持其中一个命令的情况,此时我应该更新我支持的命令。并且不确定如何使用 autofac 实现它。

我脑子里有两个选择:

  1. CommandExecutor 将在构建时注册并自行注销。所以它会拥有 CommandClient 实例来调用 register,unregister。可能是最简单的方法,但在我看来这不是正确的方法。
  2. CommandClient(或某些 CommandRegister)将监视事件以创建新的生命周期范围以及我将在标记范围内创建的所有命令。像这样的东西:
builder.Register((context) =>
            {
                var parent = context.Resolve<ILifetimeScope>();
                var scope = parent.BeginLifetimeScope(WellKnownLifeTimeScopeTag.CommandExecutorLifeTimeScope, builder =>

                    builder.RegisterType<CommandExecutor>().AsSelf().As<ICommandExecutor>()
                );
                parent.Disposer.AddInstanceForDisposal(scope);
                return scope.Resolve<CommandExecutor>();

            }).InstancePerLifetimeScope();

有了这个寄存器,我可以监控 CommandExecutor 的创建和销毁,在 CommandClient 或 CommandRegister 内部,我可以观察 CommandExecutorLifeTimeScope 标签的变化。

类似的东西:

public class CommandAutoRegister
    {
        private readonly ICommandClient _commandClient;
        public CommandAutoRegister(ICommandClient commandClient, ILifetimeScope lifeTimescope)
        {
            _ICommandClient commandClient = commandClient;
            lifeTimescope.ChildLifetimeScopeBeginning += LifeTimescope_ChildLifetimeScopeBeginning;
        }

        private void LifeTimescope_ChildLifetimeScopeBeginning(object? sender, Autofac.Core.Lifetime.LifetimeScopeBeginningEventArgs e)
        {
            // Monitor also child lifetime scopes
            e.LifetimeScope.ChildLifetimeScopeBeginning += LifeTimescope_ChildLifetimeScopeBeginning;

            if (e.LifetimeScope.Tag is not WellKnownLifeTimeScopeTag tag || 
                tag == WellKnownLifeTimeScopeTag.CommandExecutorLifeTimeScope)
            {
                return;
            }

            e.LifetimeScope.ResolveOperationBeginning += LifetimeScope_ResolveOperationBeginning;
        }

        private void LifetimeScope_ResolveOperationBeginning(object? sender, Autofac.Core.Resolving.ResolveOperationBeginningEventArgs e)
        {
            e.ResolveOperation.ResolveRequestBeginning += ResolveOperation_ResolveRequestBeginning;
        }

        private void ResolveOperation_ResolveRequestBeginning(object? sender, ResolveRequestBeginningEventArgs e)
        {            
            if (e.RequestContext.NewInstanceActivated &&
                e.RequestContext.Registration.Activator.LimitType.IsAssignableTo<ICommandExecutor>())
            {
                e.RequestContext.RequestCompleting += RequestContext_RequestCompleting;
            }
        }

        private void RequestContext_RequestCompleting(object? sender, ResolveRequestCompletingEventArgs e)
        {
            if (e.RequestContext.Instance is ICommandExecutor executor)
            {
                _commandClient.RegisterExecutor(executor);
                e.RequestContext.ActivationScope.CurrentScopeEnding += (sender, _) =>
                {
                    _commandClient.UnregisterExecutor(executor);
                };
            }
        }
    }

我想有比我想到的那些更好的方法。 (我对 C# 不是很熟悉,所以也许我做的完全错了)

c# dependency-injection autofac
© www.soinside.com 2019 - 2024. All rights reserved.