1

我在我的 Web API 应用程序中使用AutoFac (使用发布此问题时可用的最新版本)。我的服务依赖项之一是AuditService使用按DbContext类型的实例(我们现在称之为MyDbContext)。我的大部分服务和MyDbContext类型都是使用InstancePerRequest注册的。对于我来说AuditService,我想破例,我总是想注入一个拥有的(的)我的MyDbContext.

问题:使用AutoFac注册,我如何注册我AuditService的,以便它总是获得一个拥有的(新的)实例MyDbContext


什么可以工作:

  • MyDbContext我可以在构造函数中硬编码创建,AuditService从而一起绕过 AutoFac。
  • 我可以使用PropertyInjection 或 MethodInjectionMyDbContext并在 Life Time 事件OnActivating中提供一个新实例
  • 我可以定义第二个接口MyDbContext并提供第二个注册和使用InstancePerOwned

我是否必须选择上述选项之一(如果是这样,我会倾向于 3)还是我错过了一些简单的东西?有没有办法在我的注册码中定义我想要的内容?


// registration called in web api startup code
public void RegisterAutofac(ContainerBuilder builder)
{
    builder.RegisterType<MyDbContext>()
        .As<IMyDbContext>()
        .InstancePerRequest();

    builder.RegisterType<BusinessService>()
        .As<IBusinessService>()
        .InstancePerRequest();

    builder.RegisterType<AuditService>()
        .As<IAuditService>()
        .InstancePerRequest();
}


public class AuditService
{
    // expects an isolated instance on this request
    private readonly IMyDbContext _dbContext;
    public AuditService(IMyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
}

public class BusinessService
{
    // expect a shared IMyDbContext instance across the request
    private readonly IMyDbContext _dbContext;
    public BusinessService(IMyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
}

使用 InstancePerOwned 的解决方案尝试

这会导致异常

builder.RegisterType<MyDbContext>()
    .As<IMyDbContext>()
    .InstancePerRequest()
    .InstancePerOwned<AuditService>();

Autofac.Core.DependencyResolutionException:“从请求实例的范围内看不到带有匹配'AuditService'标签的范围。如果您在执行Web应用程序期间看到这一点,通常表明组件注册为per-HTTP请求由 SingleInstance() 组件(或类似场景)请求。在 Web 集成下,始终从依赖解析器或请求生命周期范围请求依赖,而不是从容器本身。

at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)
at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameter

我尝试颠倒InstancePerOwnedandInstancePerRequest调用的顺序,但这似乎没有效果,同一个MyDbContext实例被重复用于同一个请求中的BusinessServiceandAuditService实例。这是用object.ReferenceEqualsfrom in an测试的,ApiController并在两个实例的_dbContext字段中传递。

builder.RegisterType<MyDbContext>()
    .As<IMyDbContext>()
    .InstancePerOwned<AuditService>()
    .InstancePerRequest();
4

1 回答 1

1

尝试从 切换InstancePerRequestInstancePerLifetimeScope。在大多数应用程序中,这通常表现相同,并且是在具有和不具有按请求语义的应用程序之间共享注册的方式。(也就是说,这很常见。)

一旦你有了InstancePerLifetimeScope你的上下文对象,你就可以Owned<T>你的AuditService构造函数中使用来获取一个新的副本。

所以...

builder.RegisterType<MyDbContext>()
    .As<IMyDbContext>()
    .InstancePerLifetimeScope();

然后...

public AuditService(Owned<IMyDbContext> dbContext)

请注意,您AuditService将负责处理dbContext完成后的处理,因此您必须手动处理(这是 using 的一部分Owned<T>)。但是,如果您已经有一些一次性的事情正在进行,那应该没什么大不了的。

于 2018-03-06T17:48:27.883 回答