C#.Net核心依赖注入,将多个参数注入构造函数

时间:2017-03-28 07:22:43

标签: c# .net dependency-injection constructor .net-core

我有AuthenticationStrategy类,我将在控制器构造函数中注入。

我有两个IAuthenticationProvidersInternalAuthenticationProviderExternalAuthenticationProviderAuthenticationStrategy构造函数中,我想注入所有提供者 示例代码:

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>();

有什么想法吗?

5 个答案:

答案 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)
    {
        ...
    }
}

IInternalAuthenticationProviderIExternalAuthenticationProvider接口只不过是标记接口,如下所示:

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依赖项注入中的脱节代码:

  • 在应用程序的启动中注册注入的对象
  • 以匿名方法与该对象的实现分离的注入对象的对象构造
  • .net核心的其余应用程序代码从未直接调用对象构造。 .net核心框架调用构造函数。

刚从学校毕业的初级开发人员应该能够查看任何方法的任何一行,并快速找到该方法的调用方式,调用方法的位置以及为什么调用该方法-无需知道数十(数百? )核心框架的小型微功能。

通过模拟类进行单元测试可以轻松实现,而不必使用依赖注入。