将类型注册为InstancePerRequest with Exception(s)

时间:2018-03-05 16:03:51

标签: c# asp.net-web-api dependency-injection autofac autofac-configuration

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

问题:使用AutoFac注册,如何注册我的AuditService,使其始终获得MyDbContext的拥有(新)实例?

可以工作的内容:

  • 我可以在MyDbContext的构造函数中对AuditService的创建进行硬编码,从而一起绕过AutoFac。
  • 我可以使用PropertyInjection or MethodInjection并在终身事件OnActivating
  • 中提供MyDbContext的新实例
  • 我可以在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应用程序期间看到这一点,通常表示注册为的组件SingleInstance()组件(或类似场景)正在请求每HTTP请求。在Web集成下,始终从依赖项解析器或请求生存期范围请求依赖项,而不是从容器本身请求。

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

我尝试撤消InstancePerOwnedInstancePerRequest调用的顺序,但这似乎没有效果,MyDbContext实例同时重用BusinessService和{{1}同一请求中的实例。我们使用AuditService中的object.ReferenceEquals对此进行了测试,并在两个实例的ApiController字段中传递。

_dbContext

1 个答案:

答案 0 :(得分:1)

尝试从InstancePerRequest切换到InstancePerLifetimeScope。在大多数应用中,无论如何这通常都表现相同and is the way to share registrations across apps that both do and don't have per-request semantics。 (也就是说,这很常见。)

在您的上下文对象上有InstancePerLifetimeScope后,您可以use Owned<T> in your AuditService constructor获取新的副本。

因此...

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

...然后

public AuditService(Owned<IMyDbContext> dbContext)

请注意,AuditService将负责在dbContext完成后处理Owned<T>,因此您必须手动处理({1}} Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))" )。但如果你已经有一些一次性的事情发生,那不应该是一个大问题。