从Autofac Builder获取所有AsClosedTypesOf注册变体
让我们假设这些类/接口:
public interface ICommand { } public class SomeCommand : ICommand { } public interface ICommandHandler where T : ICommand { void Handle(T arg); } public class SomeCommandHandler : ICommandHandler { void Handle(SomeCommand arg){ /* do something */ } } public interface ICommandBus { void RegisterHandler(T t) where T : ICommandHandler; void RegisterHandlerByParam(ICommandHandler t2) where T2 : ICommand; void RegisterHandlerMethod(Action action) where T3 : ICommand } public class TheCommandBus : ICommandBus { // implements ICommandBus ... }
我想自动注册ICommandHandler 的所有实现。 所有变体(Register *)都是有效的解决方案,即使我更喜欢Action参数,它更灵活,并且不依赖于Handler接口(只是动作委托)。
Autofac能够根据程序集扫描注册类型,并注册找到的通用接口实现,例如:
builder.RegisterAssemblyTypes(Assembly.LoadFrom("MyAssembly.dll")) .AsClosedTypesOf(typeof(ICommandHandler));
所以我已经注册了所有实现。 现在我需要将它们全部自动注册到TheCommandBus 。 怎么做?
我可以通过添加这些行手动完成此操作(例如在OnActivated期间):
builder.RegisterType().As().OnActivated(args => { // now I need to list all implementations here!!! please, no... args.Instance.RegisterHandler<ICommandHandler>(args.Context.Resolve<ICommandHandler>()); // does not look better to me than before ... args.Instance.RegisterHandlerByParam(args.Context.Resolve<ICommandHandler>()) // uses delegate for, but still need to list all variants args.Instance.RegisterHandlerMethod(args.Context.Resolve<ICommandHandler>().Handle) });
如果我想在注册期间在lambda表达式中使用这样的类型我有问题,我需要识别具体类型,就像这个关于另一个组件的激活过程的示例一样。 但我不想手动列出所有这些…自动想要这样的东西。
如何捕获所有ICommandHandler实现并使用Register *方法自动注册它们?
编辑:
另一个变体是扩展SomeCommandHandler类,以便在其构造函数中解析时注册自身:
public SomeCommandHandler(ICommandBus commandBus) { // and register here, for example commandBus.RegisterHandlerbyParam(this); }
这样我就必须为AsClosedTypesOf注册结果提供AutoActivate()。 (一种可能的解决方案,但现在“处理程序”有两个职责……注册和处理)
这是一个有趣且棘手的问题。 generics肯定会增加复杂性,因为非generics将是一个简单的IEnumerable
分辨率。
但是…… 我想我可以提供帮助。
你会利用……
-
RegisterAssemblyTypes
的OnRegistered
事件,以便您查看实际注册的内容。 - 总线的
OnActivating
事件 ,以便您可以注册处理程序。 - 用于将已注册的处理程序类型列表带入
OnActivating
事件的闭包。 - 一些奇特的schmancyreflection,以在总线上创建
RegisterHandler
方法的封闭通用版本。
这是一个完整的工作示例,展示了如何做到这一点。 注意我必须更改RegisterHandler
的ICommandBus
接口,因为它不会以最初列出的forms为我编译,但您应该能够根据需要进行调整。 我在ScriptCs中运行它来validation。
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Autofac; public interface ICommand { } public class CommandOne : ICommand { } public class CommandTwo : ICommand { } public interface ICommandHandler where T : ICommand { void Handle(T arg); } public class CommandOneHandler : ICommandHandler { public void Handle(CommandOne arg) { } } public class CommandTwoHandler : ICommandHandler { public void Handle(CommandTwo arg) { } } public interface ICommandBus { IEnumerable