Autofac中IStartable.Start()先于RegisterBuildCallback执行:Bug还是特性?
IStartable.Start()先于RegisterBuildCallback执行:Bug还是特性?
咱们先直接聊核心结论:目前Autofac中这个执行顺序没有明确的官方定义,但从逻辑设计的角度来看,这属于不符合预期的行为——容器构建回调本就属于容器构建流程的一部分,可启动组件理应在容器完全构建完成、所有回调执行完毕后再启动。
依据Autofac官方文档的描述:
可启动组件(Startable Components):容器初始构建时会激活可启动组件
容器构建回调(Container Build Callbacks):可注册任意动作在容器构建时执行,回调会在容器从ContainerBuilder.Build返回前获取已构建的容器。
从文档描述来看,两者都属于容器构建阶段的操作,但官方没有明确规定执行顺序。不过从合理的流程逻辑出发,构建回调是对已构建容器的收尾操作,可启动组件的启动应该在所有构建相关操作完成后才触发,这样才能保证启动时容器的状态是完整的。
复现代码
using System; using Autofac; namespace AutofacBuildOrderRepro { class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterBuildCallback(ctx => StaticClass.ObjectProvider = () => new object()); // 这段代码会抛出异常 builder.RegisterType<StartableClass>().As<IStartable>().AsSelf().SingleInstance(); builder.Build(); // 这段代码可以正常运行 //builder.RegisterType<StartableClass>().AsSelf().SingleInstance(); //var container = builder.Build(); //container.Resolve<StartableClass>().Start(); } class StartableClass : IStartable { public void Start() { StaticClass.Run(); } } public static class StaticClass { public static Func<object> ObjectProvider { private get; set; } public static void Run() { if (ObjectProvider == null) { throw new InvalidOperationException("ObjectProvider is null"); } Console.WriteLine("Success"); } } } }
异常调用栈
Unhandled Exception: Autofac.Core.DependencyResolutionException: An exception was thrown while executing a resolve operation. See the InnerException for details. ---> ObjectProvider is null (See inner exception for details.) ---> System.InvalidOperationException: ObjectProvider is null at AutofacBuildOrderRepro.Program.StaticClass.Run() in c:\path\AutofacBuildOrderRepro\Program.cs:line 39 at AutofacBuildOrderRepro.Program.StartableClass.Start() in c:\path\AutofacBuildOrderRepro\Program.cs:line 27 at Autofac.Core.Resolving.InstanceLookup.StartStartableComponent(Object instance) at Autofac.Core.Resolving.InstanceLookup.Execute() at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) --- End of inner exception stack trace --- at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.Builder.StartableManager.StartStartableComponents(IComponentContext componentContext) at Autofac.ContainerBuilder.Build(ContainerBuildOptions options) at AutofacBuildOrderRepro.Program.Main(String[] args) in c:\path\AutofacBuildOrderRepro\Program.cs:line 15
测试使用的Autofac版本为4.8.1和3.0.4。
内容的提问来源于stack exchange,提问作者Grzegorz Smulko
相关产品推荐
相关产品推荐

