无法解析带有KeyFilterAttribute的AutoFac Keyed服务

时间:2018-10-22 11:52:48

标签: c# dependency-injection inversion-of-control autofac

我有一个通用的UnitOfWork模式实现,这些UnitOfWork对象是我的服务类的依赖项。以下代码片段应有助于读者理解我的代码设置:

IUnitOfWork接口

public interface IUnitOfWork<out TContext> where TContext : IDbContext

UnitOfWork类

public sealed class UnitOfWork<TContext> : IDisposable, IUnitOfWork<IDbContext> where TContext : IDbContext
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(UnitOfWork<TContext>));

        private readonly IDbContext _dbContext;
        private Dictionary<string, IRepository> _repositories;
        private IDbTransaction Transaction { get; set; }

        public UnitOfWork(IDbContext context)
        {
            _dbContext = context;
        }
    }

容器注册:

builder.RegisterGeneric(typeof(UnitOfWork<>)).As(typeof(IUnitOfWork<>));

builder.RegisterType<ReconciliationDbContext>().As<IDbContext>();
builder.RegisterType<GenevaDataDbContext>().As<IDbContext>();
builder.RegisterType<OpenStaarsDbContext>().As<IDbContext>();

builder.RegisterType<UnitOfWork<ReconciliationDbContext>>().Keyed<IUnitOfWork<IDbContext>>(ContextKey.Recon);
builder.RegisterType<UnitOfWork<OpenStaarsDbContext>>().Keyed<IUnitOfWork<IDbContext>>(ContextKey.OpenStaars);

builder.RegisterType<CommentsService>().As<ICommentsService>().WithAttributeFiltering();

DbContext类:

public class ReconciliationDbContext : BaseDbContext<ReconciliationDbContext>, IDbContext
    {
        private const string DbSchema = "BoxedPosition";

        public ReconciliationDbContext() : base("Reconciliation")
        {

        }
    }

public class OpenStaarsDbContext : BaseDbContext<OpenStaarsDbContext>, IDbContext
    {
        public OpenStaarsDbContext() : base("OpenStaars")
        {

        }
    }

CommentsService类:

public class CommentsService : ICommentsService
    {
        private readonly IUnitOfWork<IDbContext> _reconciliationUoW;

        public CommentsService([KeyFilter(ContextKey.Recon)] IUnitOfWork<IDbContext> reconciliationUoW)
        {
            _reconciliationUoW = reconciliationUoW;
        }
    }

正在解决ICommentsService:

var commentsService = container.Resolve<ICommentsService>();

现在,当我尝试解析ICommentsService类型时,它将实例化UnitOfWork依赖项。但是,UnitOfWork._dbContext属性的计算结果为OpenStaarsDbContext类型。考虑到我们的注册,这尤其奇怪。

enter image description here

如果我们通过在OpenStaarsDbContext之后注册GenevaDataDbContext来重新排序IDbContext注册,将变得更加奇怪。现在,_dbContext评估为GenevaDataDbContext实例。

如何解决此问题,以使CommentsService的reconciliationUoW依赖项具有ReconciliationDbContext的正确实例?

1 个答案:

答案 0 :(得分:1)

这种行为的原因是您将IDbContext注入UnitOfWork构造函数中,而不是TContext-容器只是忽略了您在注册时作为通用参数提供的类型并使用在容器中找到的第一个IDbContext-无论您使用什么密钥,它都是最后一个注册的容器。

要使其工作,而不是使用键注册,您可以简单地注入IUnitOfWork<ContextYouNeed>而不是IUnitOfWork<IDbContext>-它也可以简化代码。首先,您需要修复UnitOfWork类:

class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : IDbContext
{
    private readonly TContext _context;

    public UnitOfWork(TContext context)
    {
        _context = context;
    }
}

在注册时,您不需要注册特定的工作单元类型,标准的通用注册就足够了。但是您还需要注册上下文类型AsSelf,因此Autofac会为您的工作单元实例正确注入它:

builder.RegisterGeneric(typeof(UnitOfWork<>)).As(typeof(IUnitOfWork<>));

builder.RegisterType<ReconciliationContext>().As<IContext>().AsSelf();
builder.RegisterType<OpenStaarsContext>().As<IContext>().AsSelf();

以后,在您的服务中只需注入适当的工作单元:

public CommentsService(IUnitOfWork<ReconciliationContext> reconciliationUoW)