Autofac 中基于环境的不同 DI 实现
Different DI implementation in Autofac based on Environment
我正在尝试根据环境为我的界面 IBlobService
设置不同的 DI 实现。
对于 Dev,我想使用 LocalFileStorageRepository
,而对于 Production,我想使用 AzureStorageRepository
以及需要 BlobServiceClient
.
的构造函数
builder.Register(c =>
{
var environment = Environment.GetEnvironmentVariable("environment_name");
if (environment == "DEV")
{
return new LocalFileStorageRepository();
}
else
{
return new AzureStorageRepository(c.Resolve<BlobServiceClient>());
}
}).As<IBlobService>().InstancePerLifetimeScope();
它不起作用,因为 The type arguments for method 'RegistrationExtensions.Register<T>(ContainerBuilder, Func<IComponentContext, T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
知道如何解决这个问题吗?
尝试明确指定类型参数。
Try specifying the type arguments explicitly.
或者考虑让委托 return 成为一个普通类型
例如
//...
builder.RegisterType<LocalFileStorageRepository>();
builder.RegisterType<AzureStorageRepository>();
builder.RegisterType<BlobServiceClient>(); //<-- May need further details
builder.Register(c => {
var environment = Environment.GetEnvironmentVariable("environment_name");
return (IBlobService) (environment == "DEV"
? c.Resolve<LocalFileStorageRepository>()
: c.Resolve<AzureStorageRepository>());
}).InstancePerLifetimeScope();
//...
注意 return 语句中的转换。
BlobServiceClient
的注册可能需要进一步细化,具体取决于 AzureStorageRepository
的显式依赖关系
除了@Nkosi answer - if you are able to use standard ASPNETCORE_ENVIRONMENT
variable for specifying/determining environment there is one other option: use multiple Startup
classes with name conventions described in the docs:
The app can define multiple Startup
classes for different environments. The appropriate Startup
class is selected at runtime. The class whose name suffix matches the current environment is prioritized. If a matching Startup{EnvironmentName}
class isn't found, the Startup class is used.
所以在你的情况下你可以定义“base”Startup
(并将其用作默认值)并将它与 template method pattern 组合起来看起来像这样(示例代码,甚至可能无法编译, 只是给你一个想法):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
RegisterEnvironmentAutofacServices(builder);
...
}
protected virtual RegisterEnvironmentAutofacServices(ContainerBuilder builder)
{
// do default registrations here or throw depended on your preferences
builder.Register(c => new AzureStorageRepository(c.Resolve<BlobServiceClient>()))
.As<IBlobService>()
.InstancePerLifetimeScope();
}
}
public class StartupDEV : Startup
{
public Startup(IConfiguration configuration): base(configuration)
{
}
protected override RegisterEnvironmentAutofacServices(ContainerBuilder builder)
{
// do environment specific ones:
builder.Register(c => new LocalFileStorageRepository())
.As<IBlobService>()
.InstancePerLifetimeScope();
}
}
对于在运行时不会更改的配置值,而是 wrap Register
在 if
-else
检查中调用。这个:
- 简化注册
- 提高性能
- 确保在启动时检查环境变量的可用性
换句话说,将您的注册重写为以下内容:
var environment = Environment.GetEnvironmentVariable("environment_name");
if (environment == "DEV")
{
builder.RegisterType<LocalFileStorageRepository>().As<IBlobService>()
.InstancePerLifetimeScope();
}
else
{
builder.RegisterType<AzureStorageRepository>().As<IBlobService>()
.InstancePerLifetimeScope();
}
或可选
var environment = Environment.GetEnvironmentVariable("environment_name");
var blogServiceType = environment == "DEV"
? typeof(LocalFileStorageRepository)
: typeof(AzureStorageRepository);
builder.RegisterType(blogServiceType).As<IBlobService>().InstancePerLifetimeScope();
我正在尝试根据环境为我的界面 IBlobService
设置不同的 DI 实现。
对于 Dev,我想使用 LocalFileStorageRepository
,而对于 Production,我想使用 AzureStorageRepository
以及需要 BlobServiceClient
.
builder.Register(c =>
{
var environment = Environment.GetEnvironmentVariable("environment_name");
if (environment == "DEV")
{
return new LocalFileStorageRepository();
}
else
{
return new AzureStorageRepository(c.Resolve<BlobServiceClient>());
}
}).As<IBlobService>().InstancePerLifetimeScope();
它不起作用,因为 The type arguments for method 'RegistrationExtensions.Register<T>(ContainerBuilder, Func<IComponentContext, T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
知道如何解决这个问题吗?
尝试明确指定类型参数。
Try specifying the type arguments explicitly.
或者考虑让委托 return 成为一个普通类型
例如
//...
builder.RegisterType<LocalFileStorageRepository>();
builder.RegisterType<AzureStorageRepository>();
builder.RegisterType<BlobServiceClient>(); //<-- May need further details
builder.Register(c => {
var environment = Environment.GetEnvironmentVariable("environment_name");
return (IBlobService) (environment == "DEV"
? c.Resolve<LocalFileStorageRepository>()
: c.Resolve<AzureStorageRepository>());
}).InstancePerLifetimeScope();
//...
注意 return 语句中的转换。
BlobServiceClient
的注册可能需要进一步细化,具体取决于 AzureStorageRepository
除了@Nkosi answer - if you are able to use standard ASPNETCORE_ENVIRONMENT
variable for specifying/determining environment there is one other option: use multiple Startup
classes with name conventions described in the docs:
The app can define multiple
Startup
classes for different environments. The appropriateStartup
class is selected at runtime. The class whose name suffix matches the current environment is prioritized. If a matchingStartup{EnvironmentName}
class isn't found, the Startup class is used.
所以在你的情况下你可以定义“base”Startup
(并将其用作默认值)并将它与 template method pattern 组合起来看起来像这样(示例代码,甚至可能无法编译, 只是给你一个想法):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
RegisterEnvironmentAutofacServices(builder);
...
}
protected virtual RegisterEnvironmentAutofacServices(ContainerBuilder builder)
{
// do default registrations here or throw depended on your preferences
builder.Register(c => new AzureStorageRepository(c.Resolve<BlobServiceClient>()))
.As<IBlobService>()
.InstancePerLifetimeScope();
}
}
public class StartupDEV : Startup
{
public Startup(IConfiguration configuration): base(configuration)
{
}
protected override RegisterEnvironmentAutofacServices(ContainerBuilder builder)
{
// do environment specific ones:
builder.Register(c => new LocalFileStorageRepository())
.As<IBlobService>()
.InstancePerLifetimeScope();
}
}
对于在运行时不会更改的配置值,而是 wrap Register
在 if
-else
检查中调用。这个:
- 简化注册
- 提高性能
- 确保在启动时检查环境变量的可用性
换句话说,将您的注册重写为以下内容:
var environment = Environment.GetEnvironmentVariable("environment_name");
if (environment == "DEV")
{
builder.RegisterType<LocalFileStorageRepository>().As<IBlobService>()
.InstancePerLifetimeScope();
}
else
{
builder.RegisterType<AzureStorageRepository>().As<IBlobService>()
.InstancePerLifetimeScope();
}
或可选
var environment = Environment.GetEnvironmentVariable("environment_name");
var blogServiceType = environment == "DEV"
? typeof(LocalFileStorageRepository)
: typeof(AzureStorageRepository);
builder.RegisterType(blogServiceType).As<IBlobService>().InstancePerLifetimeScope();