我有AuthenticationStrategy
类,我将在控制器构造函数中注入。
我有两个IAuthenticationProviders
:InternalAuthenticationProvider
和ExternalAuthenticationProvider
在AuthenticationStrategy
构造函数中,我想注入所有提供者
示例代码:
public class AuthenticationStrategy
{
private readonly Dictionary<string, IAuthenticationProvider> _authenticationProviders;
public AuthenticationStrategy(IAuthenticationProvider[] authenticationProviders)
{
if (authenticationProviders == null)
{
throw new ArgumentNullException("AuthenticationProviders");
}
_authenticationProviders = authenticationProviders
.ToDictionary(x => nameof(x), x => x);
}
}
如何使用依赖注入注入多个提供程序? 示例代码:
services.AddScoped<IAuthenticationProvider, InternalAuthenticationProvider>();
services.AddScoped<IAuthenticationProvider, ExternalAuthenticationProvider>();
services.AddScoped<AuthenticationStrategy>();
有什么想法吗?
答案 0 :(得分:0)
一种选择是使AuthenticationStrategy成为通用的。然后你可以与类型
不同config.Scan(assembly =>
{
assembly.AssemblyContainingType(typeof(AuthenticationProvider));
assembly.ConnectImplementationsToTypesClosing(typeof(IAuthenticationProvider<>));
});
上面的代码会扫描dll,因此您也不必每次都注册。
答案 1 :(得分:0)
如果您坚持使用OOTB依赖注入设置,即不使用第三方容器,那么在您的构造函数args中将有一个选项明确:
public class AuthenticationStrategy
{
public AuthenticationStrategy(
IInternalAuthenticationProvider internal,
IExternalAuthenticationProvider external)
{
...
}
}
IInternalAuthenticationProvider
和IExternalAuthenticationProvider
接口只不过是标记接口,如下所示:
public interface IInternalAuthenticationProvider : IAuthenticationProvider { }
public interface IExternalAuthenticationProvider : IAuthenticationProvider { }
所以你的DI设置现在看起来像这样:
services.AddScoped<IInternalAuthenticationProvider , InternalAuthenticationProvider>();
services.AddScoped<IExternalAuthenticationProvider , ExternalAuthenticationProvider>();
services.AddScoped<AuthenticationStrategy>();
答案 2 :(得分:0)
假设您在Visual Studio 2017中使用Asp.Net Core项目类型
让我们假设您对界面有如下定义:
public interface IAuthenticationProvider
{
}
实现类似的类:
public class WindowsAuthentication : IAuthenticationProvider { }
public class NTMLAuthentication : IAuthenticationProvider { }
public class KerberosAuthentication : IAuthenticationProvider { }
public class CustomAuthentication : IAuthenticationProvider { }
到目前为止一切顺利。现在要解决实现相同接口的类型的依赖关系,我将使用自定义解析器类及其接口:
public interface IAuthenticationResolver
{
IAuthenticationProvider GetProvider(Type type);
}
及其实施:
public class AuthenticationResolver : IAuthenticationResolver
{
private readonly IServiceProvider services;
public AuthenticationResolver(IServiceProvider services)
{
this.services = services;
}
public IAuthenticationProvider GetProvider(Type type)
{
return this.services.GetService(type) as IAuthenticationProvider;
}
}
在Startup
课程中,ConfigureServices
下注册这些类型
services.AddTransient<IAuthenticationResolver, AuthenticationResolver>();
services.AddTransient<WindowsAuthentication>();
services.AddTransient<KerberosAuthentication>();
services.AddTransient<NTMLAuthentication>();
services.AddTransient<CustomAuthentication>();
当然你可以使用Scopped,如果这就是你需要的。
完成所有设置后,返回到注入依赖项的控制器/客户机类:
public class HomeController : Controller
{
private readonly Dictionary<string, IAuthenticationProvider> authProvidersDictionary;
public HomeController(IAuthenticationResolver resolver)
{
System.Reflection.Assembly ass = System.Reflection.Assembly.GetEntryAssembly();
this.authProvidersDictionary = new Dictionary<string, IAuthenticationProvider>();
foreach (System.Reflection.TypeInfo ti in ass.DefinedTypes)
{
if (ti.ImplementedInterfaces.Contains(typeof(IAuthenticationProvider)))
{
this.authProvidersDictionary.Add(ti.Name, resolver.GetProvider(ti.UnderlyingSystemType));
}
}
}
}
希望这有帮助!
答案 3 :(得分:0)
我认为在您的策略中存储Dictionary
是一个代码污点,因为它看起来像一个反模式Service Locator
。您可能需要introduce the factory基于密钥的身份验证提供程序。这是.Core
依赖注入中的理想方法,但是您可以使用其他IoC containers with similar features(例如,命名依赖项)。
所以,你的代码可能是这样的:
public enum AuthType
{
Internal,
External,
}
public interface IAuthenticationProviderResolver
{
IAuthenticationProvider GetAuthByType(AuthType type);
}
public class ProviderResolver : IAuthenticationProviderResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IAuthenticationProvider GetAuthByName(AuthType type)
{
switch (type)
{
case AuthType.Internal:
return _serviceProvider.GetService<InternalAuthenticationProvider>();
case AuthType.External:
return _serviceProvider.GetService<ExternalAuthenticationProvider>();
default:
throw new ArgumentException("Unknown type for authentication", nameof(type))
}
}
}
现在您只需要像往常一样注册课程:
services.AddSingleton<IAuthenticationProviderResolver, ProviderResolver>();
services.AddScoped<InternalAuthenticationProvider>();
services.AddScoped<ExternalAuthenticationProvider>();
services.AddScoped<AuthenticationStrategy>();
战略中的用法:
public class AuthenticationStrategy
{
private readonly IAuthenticationProviderResolver _resolver;
public AuthenticationStrategy(IAuthenticationProviderResolver resolver)
{
if (resolver== null)
{
throw new ArgumentNullException("Provider Resolver");
}
_resolver = resolver;
}
public void MakeDecision()
{
_resolver.GetAuthByType(authType).Authenticate();
}
}
答案 4 :(得分:0)
问题本身就是依赖注入的反模式示例,它是.net核心选择的“金锤”工具。
您的类应该能够访问这两个身份验证提供程序,而不必使用不相干的依赖项注入代码。
.net依赖项注入中的脱节代码:
刚从学校毕业的初级开发人员应该能够查看任何方法的任何一行,并快速找到该方法的调用方式,调用方法的位置以及为什么调用该方法-无需知道数十(数百? )核心框架的小型微功能。
通过模拟类进行单元测试可以轻松实现,而不必使用依赖注入。