如何在保留Dispose支持的同时在外部组件的范围内在Autofac中注册依赖项?

时间:2013-07-04 17:39:54

标签: autofac dispose

我有非一次性类ReadModelRepository,它依赖于(但不拥有)一次性类ReadModelDbContext的实例。在Module内,我想配置我的Autofac 3.0.2容器,以便仅在创建ReadModelDbContext个对象时解析ReadModelRepository(每个依赖项一个实例)。

这就是我目前所拥有的:

builder.RegisterType<ReadModelRepository>().As<IReadModelRepository>();
builder.Register(c => new ReadModelDbContext(_connectionStringName)).AsSelf();

但是,我不希望任何任意类能够使用模块提供的注册来解析ReadModelDbContext。实际上,其他类可能需要解析不同的ReadModelDbContext个实例。

要解决此问题,我可以使用WithParameter,就像在此片段中一样:

builder
    .RegisterType<ReadModelRepository> ().As<IReadModelRepository> ()
    .WithParameter (
        (p, c) => p.ParameterType == typeof (ReadModelDbContext), 
        (p, c) => new ReadModelDbContext (_connectionStringName));

但是,当生命周期范围解析ReadModelDbContext(或实际解析组件的生命周期)结束时,我还需要Autofac自动处理ReadModelRepository。使用WithParameter,这似乎不起作用。

所以,实质上,我只想在外部组件的上下文中注册一个依赖项,当最外层组件的生命周期范围结束时调用Dispose。这可能吗?

3 个答案:

答案 0 :(得分:1)

也许,这会对你有帮助。

public class RepositoryManager : IDisposable
{
    private ILifetimeScope m_RootLifetimeScope;
    private ILifetimeScope m_RepositoryScope;
    private bool m_Disposed;

    public RepositoryManager(ILifetimeScope rootLifetimeScope)
    {
        m_RootLifetimeScope = rootLifetimeScope;
    }

    public IReadModelRepository CreateReadModelRepository()
    {
        m_RepositoryScope = m_RootLifetimeScope.BeginLifetimeScope(
                builder =>
                    {
                        builder.RegisterType<ReadModelRepository>().As<IReadModelRepository>();
                        builder.Register(c => new ReadModelDbContext(_connectionStringName)).AsSelf();
                    });
        return m_RepositoryScope.Resolve<IReadModelRepository>();
    }

    public void Dispose()
    {
        if (m_Disposed) return;

        m_RepositoryScope.Dispose(); //ReadModelDbContext will be disposed

        m_Disposed = true;
    }
}

//registration
builder.RegisterType<RepositoryManager>().InstancePerDependency();

//using
using (var repositoryManager = yourContainer.Resolve<RepositoryManager>())
{
    IReadModelRepository repository = repositoryManager.CreateReadModelRepository();
}

答案 1 :(得分:0)

我建议让ReadModelRepository依赖Func<Owned<ReadModelDBContext>>

类似的东西:

using Autofac.Features.OwnedInstances;

class ReadModelRepository : IReadModelRepository
{
    public ReadModelRepository(Func<Owned<ReadModelDBContext>> contextFactory)
    {
        _ctxFactory = contextFactory;
    }

    public DoSomethingUseful()
    {
        using (var context = _ctxFactory())
        {
            // use context.Value in here;
            // it will be disposed when exiting the block
            ...
        }
    }

    private readonly Func<Owned<ReadModelDBContext>> _ctxFactory;
}

然后你可以随意注册ReadModelRepository和ReadModelDBContext。

这种方法无法解决阻止其他类解析ReadModelDBContext的问题,但是您可以通过将所有这些类型内部添加到程序集来玩可见性游戏,除了IReadModelRepository。如果你无法进入该类型,你当然不能从容器中要求一个实例。

The Autofac Wiki has some documentation on this approach.

答案 2 :(得分:0)

过了一段时间,我实际上采用了不同的方法:我用私钥注册内部组件(ReadModelDbContext):

var privateKey = new object();
builder.Register(c => new ReadModelDbContext(_connectionStringName)).Keyed<ReadModelDbContext>(privateKey);
builder.Register(ctx => new ReadModelRepository(ctx.ResolveKeyed<ReadModelDbContext>(privateKey))).As<IReadModelRepository>();

由于没有其他人拥有密钥,这有效地使ReadModelDbContext注册成为ReadModelRepository的私密。