我有一个dotnet核心应用程序。我的Startup.cs
在Autofac中注册类型/实现。我的一个注册需要以前访问服务。
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterSettingsReaders(); // this makes available a ISettingsReader<string> that I can use to read my appsettings.json
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = "foo" //this should come from appsettings
});
containerBuilder.Populate(services);
var applicationContainer = containerBuilder.Build();
难题是,当我必须使用.RegisterMyInfrastructureService
时,我需要使用之前注册的ISettingsReader<string>
(Autofac容器尚未构建(。
我读到了关于在autofac容器构建完成后使用回调进行注册以执行某些操作的文章。所以我可以做这样的事情:
builder.RegisterBuildCallback(c =>
{
var stringReader = c.Resolve<ISettingsReader<string>>();
var usernameValue = stringReader.GetValue("Username");
//now I have my username "foo", but I want to continue registering things! Like the following:
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = usernameValue
});
//now what? again build?
});
但问题是,在我想使用该服务之后,我不想做像启动服务或类似的事情,而是继续注册需要我现在能够提供的设置的东西。
我可以简单地在回调结束时再次调用builder.Build()
,以便在没有任何问题的情况下简单地重建容器吗?这看起来有点奇怪,因为构建器已经构建好了(这就是执行回调的原因(。
使用autofac解决这种困境的最佳方法是什么?
更新1:我读过类似builder的东西。Update((现在已经过时,因为容器应该是不可变的。这证实了我的怀疑,即建造一个容器、增加更多注册并再次建造并不是一个好的做法。
换句话说,我可以理解,使用寄存器构建回调不应该用于注册其他东西。但是,问题仍然存在:如何处理这些问题?
这个讨论问题解释了很多内容,包括如何解决必须更新容器的问题。我将在这里进行总结,但在这个问题中有很多信息是没有意义的,无法尝试全面复制。
- 熟悉注册组件和传递参数的所有方法。不要忘记诸如已解析的参数、可以动态放置参数的模块等等
- Lambda注册几乎解决了我们所看到的每一个问题。如果您需要注册一些提供配置的东西,然后在以后将该配置用作不同注册的一部分,那么lambdas将是巨大的
- 考虑中间接口,比如创建一个由
ISettingsReader<string>
支持的IUsernameProvider
。IUsernameProvider
可以是lambda(解析某些设置、读取特定设置等(,然后下游组件可以直接获取IUsernameProvider
这类问题很难回答,因为如果你利用lambdas和参数之类的东西,有很多方法可以解决必须构建/重建/重新重建容器的问题-没有"最佳实践",因为它总是取决于你的应用程序和你的需求。
就我个人而言,我通常会从lambda方法开始。