依赖注入统一 - 条件解析

ame*_*els 14 c# dependency-injection inversion-of-control unity-container

有条件的解决是目前我​​还不了解的最后一件事.

让我们说我们有一个界面IAuthenticate:

public interface IAuthenticate{
    bool Login(string user, string pass);
}
Run Code Online (Sandbox Code Playgroud)

现在我有两种类型的身份验证.

Twitter认证

public class TwitterAuth : IAuthenticate
{
  bool Login(string user, string pass)
{
   //connect to twitter api
}

}
Run Code Online (Sandbox Code Playgroud)

Facebook Auth

public class FacebookAuth: IAuthenticate
{
  bool Login(string user, string pass)
{
   //connect to fb api
}

}
Run Code Online (Sandbox Code Playgroud)

在unity配置中注册类型:

unityContainer.RegisterType<IAuthenticate, TwitterAuth>();
unityContainer.RegisterType<IAuthenticate, FacebookAuth>();
Run Code Online (Sandbox Code Playgroud)

在我们的控制器中通过DI注入对象:

private readonly IAuthenticate _authenticate;

public AuthenticateController(IAuthenticate authenticate)
{
    _authenticate = authenticate;
}



// login with twitter
public virtual ActionResult Twitter(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}



// login with fb
public virtual ActionResult Facebook(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}



// login with google
public virtual ActionResult Google(string user, string pass)
{
    bool success =
            _authenticate.Login(user, pass);
}
Run Code Online (Sandbox Code Playgroud)

团结如何知道它必须为不同类型的身份验证解决哪个对象?在这种情况下如何进行条件解决?

我和我的朋友谈过,他解释说如果这种情况出现是错误的设计,但这只是工厂模式使用的.

Nig*_*888 40

解决此问题的一种简单方法是使用策略模式.请注意,您可以在不更改设计的情况下添加或删除登录提供程序 - 您只需更改DI配置即可.

接口

public interface IAuthenticate{
    bool Login(string user, string pass);
    bool AppliesTo(string providerName);
}

public interface IAuthenticateStrategy
{
    bool Login(string providerName, string user, string pass);
}
Run Code Online (Sandbox Code Playgroud)

验证提供商

public class TwitterAuth : IAuthenticate
{
    bool Login(string user, string pass)
    {
        //connect to twitter api
    }

    bool AppliesTo(string providerName)
    {
        // I used the type name for this example, but
        // note that you could use any string or other
        // datatype to select the correct provider.
        return this.GetType().Name.Equals(providerName);
    }
}

public class FacebookAuth: IAuthenticate
{
    bool Login(string user, string pass)
    {
        //connect to fb api
    }

    bool AppliesTo(string providerName)
    {
        return this.GetType().Name.Equals(providerName);
    }
}
Run Code Online (Sandbox Code Playgroud)

战略

public class AuthenticateStrategy: IAuthenticateStrategy
{
    private readonly IAuthenticate[] authenticateProviders;

    public AuthenticateStrategy(IAuthenticate[] authenticateProviders)
    {
        if (authenticateProviders == null)
            throw new ArgumentNullException("authenticateProviders");

        this.authenticateProviders = authenticateProviders;
    }

    public bool Login(string providerName, string user, string pass)
    {
        var provider = this.authenticateProviders
            .FirstOrDefault(x => x.AppliesTo(providerName));

        if (provider == null)
        {
            throw new Exception("Login provider not registered");
        }

        return provider.Login(user, pass);
    }
}
Run Code Online (Sandbox Code Playgroud)

团结注册

// Note that the strings used here for instance names have nothing 
// to do with the strings used to select the instance in the strategy pattern
unityContainer.RegisterType<IAuthenticate, TwitterAuth>("twitterAuth");
unityContainer.RegisterType<IAuthenticate, FacebookAuth>("facebookAuth");
unityContainer.RegisterType<IAuthenticateStrategy, AuthenticateStrategy>(
    new InjectionConstructor(
        new ResolvedArrayParameter<IAuthenticate>(
            new ResolvedParameter<IAuthenticate>("twitterAuth")
        ),
        new ResolvedArrayParameter<IAuthenticate>(
            new ResolvedParameter<IAuthenticate>("facebookAuth")
        )
    ));
Run Code Online (Sandbox Code Playgroud)

用法

private readonly IAuthenticateStrategy _authenticateStrategy;

public AuthenticateController(IAuthenticateStrategy authenticateStrategy)
{
    if (authenticateStrategy == null)
        throw new ArgumentNullException("authenticateStrategy");

    _authenticateStrategy = authenticateStrategy;
}



// login with twitter
public virtual ActionResult Twitter(string user, string pass)
{
    bool success =
            _authenticateStrategy.Login("TwitterAuth", user, pass);
}



// login with fb
public virtual ActionResult Facebook(string user, string pass)
{
    bool success =
            _authenticateStrategy.Login("FacebookAuth", user, pass);
}
Run Code Online (Sandbox Code Playgroud)


Rob*_*kal 6

团结不会没有你的帮助.您可以在注册IAuthenticate类型时提供名称:

unityContainer.RegisterType<IAuthenticate, TwitterAuth>("Twitter");
unityContainer.RegisterType<IAuthenticate, FacebookAuth>("Facebook");
Run Code Online (Sandbox Code Playgroud)

您将不再希望将IAuthenticate实例直接注入AuthenticateController.您将根据一致的条件(服务定位器样式)获得所需的实例:

myContainer.Resolve<IAuthenticate>("Twitter");
Run Code Online (Sandbox Code Playgroud)

或者你会注入一个为你做这个的工厂(如果你喜欢严格的DI风格).