asp.net-core - Autofac 无法解析 ASP。NET Core Controller 尝试传递参数进行注册时
问题描述
我们一直使用 Autofac 作为依赖注入的 IoC 容器。为了在注册期间将参数传递给 Web API 控制器,我们希望将其传递给 Controller 构造函数。它是一个双类型参数,名称ratio
在下面的构造函数中。
但是,Autofac 会抛出异常,因为它无法解析 double 类型的最后一个参数(ratio
此处)并且无法创建DataProcessController
.
public DataProcessController(ILogger logger, IDataProvider dataProvider, double ratio)
{
...
}
通过 usingWithParameter
方法来指定要使用的值。
builder.RegisterType<DataProcessController>().AsSelf()
.WithParameter("ratio", 0.4);
我还调用AddControllersAsServices
以将控制器注册为服务并从容器中解析它。
services.AddMvc()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
并Populate()
在完成注册后打电话。
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
全部在下面的函数中定义:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddHttpClient();
services.AddMvc()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//Autofac
var builder = new ContainerBuilder();
builder.RegisterInstance(_logger).As<ILogger>().SingleInstance();
//All other dependencies are defined here....
builder.RegisterType<DataProcessController>().AsSelf()
.WithParameter("ratio", 0.4);
// auto-discover examples from this assembly
services.AddSwaggerExamplesFromAssemblyOf<Startup>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
我尝试将原始数据类型和引用数据类型(如另一个类)作为容器来保存双精度值,但都未能通过 Autofac 解析控制器。
解决方案
您需要builder.Populate(services)
在将内容添加到要覆盖的容器之前调用。
如果您查看有关新产品如何IServiceProviderFactory
工作的文档,则基本上是:
- 用来
ConfigureServices
注册东西IServiceCollection
- 在服务提供者工厂的幕后,a被创建并为您
ContainerBuilder
调用builder.Populate(services)
- 用于
ConfigureContainer
直接向 Autofac 注册事物 - 在服务提供者工厂的幕后,最终的容器被构建并放入一个
IServiceProvider
在您AutofacServiceProvider
自己构建的旧集成中,您必须注意顺序。它仍然是 Autofac - 最后获胜。
当你这样做时services.AddControllersAsServices()
,就像在说builder.RegisterType<DataProcessController>().AsSelf()
......但它实际上还没有与建造者交谈。这就像一个“存储的注册”,在您调用之前不会“回放” Populate
。
因此,如果您简化注册并按照它们实际执行的顺序排列:
// These will NOT be executed until builder.Populate()
// services.AddOptions();
// services.AddHttpClient();
// services.AddMvc()
// .AddControllersAsServices()
// .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var builder = new ContainerBuilder();
builder.RegisterInstance(_logger).As<ILogger>().SingleInstance();
builder.RegisterType<DataProcessController>().AsSelf()
.WithParameter("ratio", 0.4);
// Still not executed until builder.Populate()
services.AddSwaggerExamplesFromAssemblyOf<Startup>();
// Here goes everything!
// - AddOptions => ContainerBuilder
// - AddHttpClient => ContainerBuilder
// - AddMvc => ContainerBuilder
// - AddControllersAsServices => ContainerBuilder
// ---- OH NO! JUST OVERWROTE THE WITHPARAMETER REGISTRATION!
// - AddSwaggerExamplesFromAssemblyOf => ContainerBuilder
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
这是我的建议:
最佳案例:转向服务提供商工厂支持
在文档中,这是在 ASP.NET 1.1-2.2 中您不自己构建 AutofacServiceProvider 而是在 web 主机级别注册 Autofac 的地方。这是最佳选择,因为它可以让您在准备好后为升级到 ASP.NET Core 3.0 做好更多准备。一旦你达到 3.0,你无论如何都必须这样做。
后备选项:组织您的注册
如果你不能切换集成来强制你使用单独的ConfigureServices
和ConfigureContainer
方法,至少要组织好代码,ConfigureServices
这样你就做好了准备。这也将确保以正确的顺序调用所有内容,以避免现在和将来出现此问题。
services.AddWhatever()
将所有注册分组IServiceCollection
在顶部。例如,不要services.AddSwaggerExamplesFromAssembly
在 Autofac 注册中流连忘返。- 创建
ContainerBuilder
并立即调用Populate
。不要在这两件事之间进行任何注册。 - 通话后将所有
builder.Register<T>()
注册分组。ContainerBuilder
builder.Populate
- 像现在一样,将服务提供者的创建作为方法中的最后一件事。
推荐阅读
- iis - 部署多个生产环境
- jquery - 调整大小时的动态值
- javascript - if 块中具有不同数值的这个数字函数的含义
- tabs - 从 TabView Flutter 打开屏幕而不是全屏
- ubuntu - Windows 的 linux 子系统在哪里寻找 SSH 密钥?
- git - Azure devops - 服务器端 git 挂钩
- java - 在 GCP 上运行 spring boot 应用程序:nginx 反向代理:加载资源失败:服务器响应状态为 502 (Bad Gateway)
- android - Android EditText MultiLine 可绘制重力
- knockout.js - 如何使用带有 KnockoutJS 的 JQuery DataTables 添加事件点击
- c++ - 调用 C 标准库函数的标准 C++ 方式