无法解析带有KeyFilterAttribute的AutoFac Keyed服务 [英] Unable to resolve AutoFac Keyed service with KeyFilterAttribute not working

查看:245
本文介绍了无法解析带有KeyFilterAttribute的AutoFac Keyed服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通用的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类型.考虑到我们的注册,这尤其奇怪.

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

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

解决方案

这种行为的原因是您将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)

I have a generic UnitOfWork pattern implementation and these UnitOfWork objects are dependencies to my service classes. Below snippets should help the reader understand my code setup:

IUnitOfWork interface

public interface IUnitOfWork<out TContext> where TContext : IDbContext

UnitOfWork class

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;
        }
    }

Container registrations:

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 classes:

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 class:

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

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

Resolving ICommentsService:

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

Now when I try to resolve the ICommentsService type, it instantiates the UnitOfWork dependency. However, the UnitOfWork._dbContext property evaluates to OpenStaarsDbContext type. This is particularly strange considering our registrations.

It becomes more strange if we re-order our IDbContext registrations by registering the GenevaDataDbContext after OpenStaarsDbContext. Now the _dbContext evaluates to GenevaDataDbContext instance.

How can I fix this to make the reconciliationUoW dependency of CommentsService to have the correct instance of ReconciliationDbContext ?

解决方案

The reason of such behaviour is the fact you inject IDbContext into your UnitOfWork constructor, instead of TContext - the container just ignores the type you provide as a generic parameter in you registration and takes the first IDbContext it finds in the container - which would be the last registered, no matter what key you would use.

To make it work, instead of using keyed registration, you could simply inject IUnitOfWork<ContextYouNeed> instead of IUnitOfWork<IDbContext> - it would simplify the code as well. First you need to fix your UnitOfWork class:

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

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

In your registration, you do not need to register specific unit of work types, standard generic registration would be sufficient. But you need to register your context types AsSelf as well, so Autofac would properly inject it for your unit of work instances:

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

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

Later on, in your service simply inject proper unit of work:

public CommentsService(IUnitOfWork<ReconciliationContext> reconciliationUoW)

这篇关于无法解析带有KeyFilterAttribute的AutoFac Keyed服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆