无法解决 AutoFac Keyed 服务与 KeyFilterAttribute 不工作
Unable to resolve AutoFac Keyed service with KeyFilterAttribute not working
我有一个通用的 UnitOfWork 模式实现,这些 UnitOfWork 对象依赖于我的服务 classes。下面的片段应该有助于 reader 理解我的代码设置:
IUnitOfWork 接口
public interface IUnitOfWork<out TContext> where TContext : IDbContext
工作单位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;
}
}
容器注册:
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")
{
}
}
评论服务class:
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:
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)
我有一个通用的 UnitOfWork 模式实现,这些 UnitOfWork 对象依赖于我的服务 classes。下面的片段应该有助于 reader 理解我的代码设置:
IUnitOfWork 接口
public interface IUnitOfWork<out TContext> where TContext : IDbContext
工作单位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;
}
}
容器注册:
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")
{
}
}
评论服务class:
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:
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)