6

嗨,我正在使用 IoC 容器,我想在构造函数中初始化一个服务(其中一部分涉及与数据库的“繁重工作”)。

此特定服务存储注入IPluginToServiceProviderBridge服务找到的信息,此信息通过UnitOfWork.

一旦一切都被引导,带有命令的控制器和带有处理程序的服务将用于所有其他交互。所有命令都包装在生命周期范围内,因此保存和处理UnitOfWork是由处理程序而不是服务完成的(这对于干净的代码非常有用)。

保存和事务的相同整洁和关注点分离不适用于Initializer服务内部,因为一切都发生在构造函数中:

public PluginManagerService(
    IPluginToServiceProviderBridge serviceProvider,
    IUnitOfWork unitOfWork)
{     
    this.unitOfWork = unitOfWork;
    this.serviceProvider = serviceProvider;

    lock (threadLock)
    {
        if (initialised == false)
        {
            LinkPluginsWithDatabase();
            initialised = true;
        }

        // I don't like this next line, but 
        // not sure what else to do
        this.UnitOfWork.Save(); 
    }
}

protected void LinkPluginsWithDatabase()
{
    var plugins =
        this.serviceProvider.GetAllPlugins();

    foreach (var plugin in plugins)
    {
        var db = new PluginRecord
        {
            interfaceType = plugin.InterfaceType;
            var id = plugin.Id;
            var version = plugin.Version;
        }
        // store in db via unit of work repository
        this.unitOfWork.PluginsRepository.Add(db);
    }
}

几点:

理想情况下,我想避免使用工厂,因为它会使作用域生命周期的处理复杂化,如果我知道如何进行重构以实现更好的分离,我会很乐意。

我真的想避免Init()为服务使用单独的方法,虽然它允许通过命令/处理程序进行事务和保存,但需要大量检查代码,我相信这也会引入时间问题。

鉴于上述情况,UnitOfWork.Save()在我的构造函数中调用是否可以接受,或者我可以重构更清晰的代码和更好的分离?

4

1 回答 1

6

在应用依赖注入时,让服务的构造函数做的不仅仅是将其依赖项存储在私有字段中被认为是不好的做法,因为这会导致对象图的构建失败,减慢图的构建速度,并使单元测试复杂化。

我从您的问题中了解到的是,您需要在应用程序启动时进行一些初始化。这很好,因为有一些初始化阶段是很正常的,但不要在构造函数中这样做。只需在配置容器之后(以及在您选择验证配置之后)将此初始化移动到应用程序启动代码的末尾。

我想你的代码看起来像这样:

public void Application_Start(object s, EventArgs e)
{
    Container container = new Container();

    Bootstrap(container);

    InitializeApplication(container);
}

private void InitializeApplication(
    Container container)
{
    using (this.container.BeginLifetimeScope())
    {
        var pluginManager = this.container
            .GetInstance<PluginManagerService>();

        pluginManager.LinkPluginsWithDatabase();

        var unitOfWork =
            container.GetInstance<IUnitOfWork>();

        unitOfWork.Save();
    }
}

你甚至可以为你的PluginManagerService.

public class InitializingPluginManagerServiceDecorator
    : IPluginManagerService
{
    private static readonly object syncRoot = new object();
    private static bool initialized;

    private IPluginManagerService decorated;
    private Container container;

    public InitializingPluginManagerServiceDecorator(
        IPluginManagerService decorated,
        Container container,
        IPluginToServiceProviderBridge serviceProvider)
    {
        this.pluginManagerService = pluginManagerService;
        this.container = container;
        this.serviceProvider = serviceProvider;
    }

    public void PluginManagerServiceMethod()
    {
        this.InitializeInLock();        

        this.decorated.PluginManagerServiceMethod();
    }

    private void InitializeInLock()
    {
        if (!initialized)
        {
            lock (syncRoot)
            {
                if (!initialized)
                {
                    this.InitializeInScope();
                }
            }

            initialized = true;    
        }
    }

    private void InitializeInScope()
    {
        using (this.container.BeginLifetimeScope())
        {
            this.InitializeWithSave();
        }
    }

    private void InitializeWithSave()
    {
        var uow =
            this.container.GetInstance<IUnitOfWork>()

        var initializer = this.container
            .GetInstance<PluginManagerServiceInitializer>();

        initializer.Initialize();

        uow.Save();    
    }
}

这个装饰器可以包裹在一个IPluginManagerService, 并确保系统在IPluginManagerService我们第一次使用之前被初始化,并确保它只初始化一次。实际的初始化逻辑被移动到一个单独的类(SRP),装饰器依赖于它:

public class PluginManagerServiceInitializer
{
    private IUnitOfWork unitOfWork;
    private IPluginToServiceProviderBridge serviceProvider;

    public PluginManagerServiceInitializer(
        IUnitOfWork unitOfWork,
        IPluginToServiceProviderBridge serviceProvider)
    {
        this.unitOfWork = unitOfWork;
        this.serviceProvider = serviceProvider;
    }

    public void Initialize()
    {
        var plugins =
            from plugin in this.serviceProvider.GetAllPlugins()
            select new PluginRecord
            {
                interfaceType = plugin.InterfaceType;
                var id = plugin.Id;
                var version = plugin.Version;
            };

        unitOfWork.PluginsRepository.AddRange(plugins);
    }
}
于 2012-06-22T17:17:59.997 回答