对于一个应用程序,我有多个IAuthentificationProvider:
public interface IAuthentificationProvider
{
bool IsUserValid(string login, string password)
}
对于每个IAuthentificationProvider,我都有一个IAuthentificationProviderConfig与以下内容关联:
public interface IAuthentificationProvider
{
bool IsEnabled { get; set; }
}
要使用所有这些启用的提供程序,我还有另一个课程:
public class AuthentificationManager
{
public AuthentificationManager(IEnumerable<IAuthentificationProvider> providers)
{
//do something with providers
}
//other class logic
}
现在,我只想注册已启用的提供程序。我尝试过类似的东西:
//finding all possible providers in assembly
var providerInterface = typeof(IAuthentificationProvider);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => providerInterface.IsAssignableFrom(p) && !p.IsAbstract).ToList();
foreach (var type in types)
{
//Register type as self for simple resolve in lambda expression
containerBuilder.RegisterType(type).AsSelf().SingleInstance();
containerBuilder.Register(c =>
{
var configs = c.Resolve<IAuthentificationProvidersConfig>();
//get specific configuration for provider
var config = configs.GetConfig(type.Name);
if (config.IsEnabled)
{
//return provider
return c.Resolve(type);
}
else
{
//"cancel the register"
return new object();
}
}).As<IAuthentificationProvider>().SingleInstance();
}
在Autofac 4.9中,上面的代码有效,但是现在在Autofac 5.1.2中,行return new object();
不再起作用:
InvalidCastException: Object cannot be stored in an array of this type.
我还有另一种取消lambda内寄存器的方法吗?
您无法在同一注册的lambda中取消注册。在我看来,您有两个选择:
您应该更喜欢在应用程序启动时分割阶段,在此阶段您从注册容器的阶段读取配置。这使您可以根据配置值有条件地进行注册。
例如:
var configs = new AuthentificationProvidersConfig();
builder.RegisterInstance(configs).As<IAuthentificationProvidersConfig>();
foreach (var type in types)
{
if (configs.GetConfig(type.Name).IsEnabled)
{
builder.Register(type).As<IAuthentificationProvider>().AsSingleInstance();
}
}
如果第一个解决方案不可行,则可以在运行时过滤这些类型。这可以在AuthentificationManager
内部执行,也可以在Composite IAuthentificationProvider
实现内部进行。