我正在尝试实现一个接收命令并执行它的命令客户端。命令客户端向远程服务报告支持的命令。更改设置后,可能会发生在应用程序运行期间不再支持某些命令的情况。对我来说最具挑战性的是如何即时实现添加/删除支持的命令。
如果命令在整个运行时都是已知的,那可能会很简单,我会按以下方式进行:
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 实现它。
我脑子里有两个选择:
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# 不是很熟悉,所以也许我做的完全错了)