使用运行时参数

时间:2016-08-08 11:53:54

标签: unity-container

我有以下问题。我注册我的组件并在Unity中初始化它们(例如用于控制台应用程序):

public class SharePointBootstrapper : UnityBootstrapper
{
    ...

    public object Initialize(Type type, object parameter) =>
        Container.Resolve(type,
            new DependencyOverride<IClientContext>(Container.Resolve<IClientContext>(parameter.ToString())),
            new DependencyOverride<ITenantRepository>(Container.Resolve<ITenantRepository>(parameter.ToString())));

    public void RegisterComponents()
    {
        Container
            .RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString())
            .RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString())
            .RegisterType<ITenantRepository, DocumentDbTenantRepository>(SharePointClientContext.Online.ToString())
            .RegisterType<ITenantRepository, JsonTenantRepository>(SharePointClientContext.OnPremise.ToString());
    }
}

public enum SharePointClientContext
{
    Online,
    OnPremise
}

class Program
{
    static void Main(string[] args)
    {
        ...

        bootstrap.RegisterComponents();
        var bla = bootstrap.Initialize(typeof(ISharePointManager), SharePointClientContext.Online);
    }
}

因此,我使用RegisterComponents()在MVC,WCF,Console等中注册我的组件,并使用Initialize()初始化它们。

我的问题是,如果我想在运行时初始化特定的命名注册,例如,用户输入,是否可以在提供的代码(使用InjectionFactory或类似代码)时完成?

此代码工作正常,但我对其实现不满意。我觉得它可以用RegisterComponents()而不是Initialize()编写,这样它就可以接受某种类型的参数,但我不知道该怎么做。

或者,也许我的整个概念都错了?如果是这样,你会建议什么?我需要从只在运行时知道的参数解析命名注册,无论技术如何(MVC,WCF,控制台......)。

谢谢!

1 个答案:

答案 0 :(得分:0)

我会做不同的解决方案而不是做不同的注册。

假设你需要注入IClientContext,但是你需要不同的实现,具体取决于运行时参数。

我写了similiar answer here。您可以注入IClientContext而不是注入IClientContextFactory,这将负责返回正确的IClientContext。它被称为Strategy Pattern

public interface IClientContextFactory
{
    string Context { get; } // Add context to the interface.
}

public class SharePointOnlineClientContext : IClientContextFactory
{
    public string Context 
    {
        get 
        {
            return SharePointClientContext.Online.ToString(); 
        }
    }
}

// Factory for resolving IClientContext.
public class ClientContextFactory : IClientContextFactory
{
    public IEnumerable<IClientContext> _clientContexts;

    public Factory(IClientContext[] clientContexts)
    {
        _clientContexts = clientContexts;
    }

    public IClientContext GetClientContext(string parameter)
    {
        IClientContext clientContext = _clientContexts.FirstOrDefault(x => x.Context == parameter);
        return clientContext;
    }
}

将它们全部注册,就像你一样。但是注入IClientContext而不是注入IClientContextFactor

还有另一种使用Func工厂的解决方案。在this answer中查看选项3。有人可能会说这是服务定位器模式的包装器,但我会再讨论这个讨论。

public class ClientContextFactory : IClientContextFactory
{
    private readonly Func<string, IClientContext> _createFunc;

    public Factory(Func<string, IClientContext> createFunc)
    {
        _createFunc = createFunc;
    }

    public IClientContext CreateClientContext(string writesTo)
    {
        return _createFunc(writesTo);
    }
}

并使用命名注册:

container.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString());
container.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString());

container.RegisterType<IFactory, Factory>(
    new ContainerControlledLifetimeManager(), // Or any other lifetimemanager.
    new InjectionConstructor(
        new Func<string, IClientContext>(
            context => container.Resolve<IClientContext>(context));

用法:

public class MyService
{
    public MyService(IClientContextFactory clientContextFactory)
    {
        _clientContextFactory = clientContextFactory;
    }

    public void DoStuff();
    {
        var myContext = SharePointClientContext.Online.ToString();
        IClientContextclientContext = _clientContextFactory.CreateClientContext(myContext);
    }
}