Autofac:没有办法解决最里面的范围是什么? [英] Autofac: any way to resolve the innermost scope?

查看:378
本文介绍了Autofac:没有办法解决最里面的范围是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我正在尝试Autofac在新的ASP.NET MVC项目有使用Ninject,温莎城堡等IoC容器中,在过去的几年之后。因此,虽然我知道一般的IoC容器中,我是相当新的Autofac和我仍然在寻找一些最佳实践。

I'm currently trying out Autofac in a new ASP.NET MVC project after having used Ninject, Castle Windsor and other IoC containers in the last years. So while I know about IoC containers in general, I'm fairly new to Autofac and I'm still looking for some best practices.

目前我正在试图找出是否有解决内部嵌套范围的一种方式。

Currently I'm trying to find out if there is a way to resolve the innermost nested scope.

我有以下情况:注册为SingleInstance()有一个用于创建嵌套的一生范围的方法,提供了配置操作配置一些组件作为InstancePerLifetimeScope一个组成部分,并在此嵌套的作用域解析注册组件做一些有用的东西,像这样:

I have the following situation: a component that is registered as SingleInstance() has a method that creates a nested lifetime scope, providing a configuration action to configure some components as InstancePerLifetimeScope, and within this nested scope resolves the registered components to do something useful, like so:

ILifetimeScope currentScope = ???;

using (var scope = currentScope.BeginLifetimeScope(cb => {
  cb.RegisterType<X>().InstancePerLifetimeScope();
  // ...
}))
{
    var comp = scope.Resolve<X>();
    // ...
}

问题是,我想currentScope是最里面的生命周期范围内,因为我知道X依赖于最里面域内的组件。在最简单的情况,这将是例如当前请求的寿命范围。我当然可以用AutofacDependencyResolver.Current.RequestLifetimeScope得到它,但我不希望使用,因为它是不是真的很好测试。同样,寿命范围不一定是最内层。

The issue is that I would like currentScope to be the innermost lifetime scope, because I know that X depends on components inside the innermost scope. In the simplest case that would be e.g. the current request lifetime scope. I can of course get it with AutofacDependencyResolver.Current.RequestLifetimeScope but I don't want to use that as it isn't really well testable. Also, that lifetime scope isn't necessarily the innermost.

那么,有没有办法找到如给予最里面的生命周期范围根容器或不同ILifetimeScope?

So, is there a way to find the innermost lifetime scope given e.g. the root container or a different ILifetimeScope?

推荐答案

在Autofac,最里面的范围始终容器。使用AutofacDependencyResolver,它会是
AutofacDependencyResolver.Current.ApplicationContainer

In Autofac, the innermost scope is always the container. Using the AutofacDependencyResolver, it'd be AutofacDependencyResolver.Current.ApplicationContainer

有没有从嵌套的作用域的方式(如果你所有的是一个 ILifetimeScope )以落后走去的容器。我并不确定要做到这一点,无论如何。

There is no way from a nested scope (if all you have is an ILifetimeScope) to "walk backward" to get to the container. I'm not necessarily sure you want to do that, anyway.

这听起来像你SingleInstance组件是做某种服务的位置,基本与手动注册/分辨率某些组件。如果设定的类型被注册是固定的,我可能会建议(如果可能的话)你的系统的一些重新设计,所以SingleInstance组件不再被注册为SingleInstance,而是被注册为InstancePerD​​ependency,然后有采取这些其他项目构造函数的参数。

It sounds like your SingleInstance component is doing some sort of service location, basically, with manual registration/resolution of certain components. If the set of types being registered is fixed, I might recommend (if possible) some redesign of your system, so the SingleInstance component isn't registered as SingleInstance anymore and instead gets registered as InstancePerDependency, then have that take these other items in as constructor parameters.

而不是...

// Consuming class like this...
public class BigComponent
{
  public void DoSomethingCool()
  {
    using(var scope = ...)
    {
      var c = scope.Resolve<SubComponent>();
      c.DoWork();
    }
  }
}

// ...and container registrations like this...
builder.RegisterType<BigComponent>().SingleInstance();

您可以尝试反转了一点:

You might try inverting it a bit:

// Consuming class like this...
public class BigComponent
{
  private SubComponent _c;
  public BigComponent(SubComponent c)
  {
    _c = c;
  }
  public void DoSomethingCool()
  {
    _c.DoWork();
  }
}

// ...and container registrations like this...
builder.RegisterType<BigComponent>().InstancePerDependency();
builder.RegisterType<SubComponent>().InstancePerLifetimeScope();

的想法是不必须做的即时登记和 - 直接分辨率事

The idea is to not have to do the on-the-fly registration-and-immediate-resolution thing.

如果你坚持做服务的位置,你需要使用 AutofacDependencyResolver.Current.ApplicationContainer 如果你需要绝对的最里面的范围,但要记住任何物体您注册作用域为 InstancePerHtt prequest 如果你这样做会不会分辨,所以你可以惹上麻烦。这真的是推荐使用 AutofacDependencyResolver.Current.RequestLifetimeScope 来代替。这将使你的方法:

If you're stuck doing service location, you'll need to use AutofacDependencyResolver.Current.ApplicationContainer if you need the absolute innermost scope, but keep in mind any objects you register scoped to InstancePerHttpRequest will not be resolvable if you do that, so you could get into trouble. It really is recommended to use the AutofacDependencyResolver.Current.RequestLifetimeScope instead. That would make your method:

var requestScope = AutofacDependencyResolver.Current.RequestLifetimeScope;
using (var scope = requestScope.BeginLifetimeScope(cb => {
  cb.RegisterType<X>().InstancePerLifetimeScope();
  // ...
}))
{
    var comp = scope.Resolve<X>();
    // ...
}

在一个测试环境,在 AutofacDependencyResolver ,您可以在规定的使用寿命要求得到如何生成的提供者交换。您可以实现一个简单的/存根一个像这样的:

In a testing environment, the AutofacDependencyResolver lets you swap in the provider that dictates how request lifetimes get generated. You can implement a simple/stub one like this:

public class TestLifetimeScopeProvider : ILifetimeScopeProvider
{
    readonly ILifetimeScope _container;
    private ILifetimeScope _lifetimeScope = null;

    public TestLifetimeScopeProvider(ILifetimeScope container)
    {
        if (container == null) throw new ArgumentNullException("container");
        _container = container;
    }

    public ILifetimeScope ApplicationContainer
    {
        get { return _container; }
    }

    public ILifetimeScope GetLifetimeScope()
    {
        if (_lifetimeScope == null)
        {
            _lifetimeScope = ApplicationContainer.BeginLifetimeScope("httpRequest")
        }
        return _lifetimeScope;
    }

    public void EndLifetimeScope()
    {
        if (_lifetimeScope != null)
            _lifetimeScope.Dispose();
    }
}

再次只进行单元测试存根,不是你的永远生产使用的东西。

Again, just a stub for unit testing, not something you'd ever use in production.

在线了那么 DependencyResolver 在您的测试,你提供你的一生范围提供商:

Then when you wire up the DependencyResolver in your test, you provide your lifetime scope provider:

var lsProvider = new TestLifetimeScopeProvider(container);
var resolver = new AutofacDependencyResolver(container, lsProvider);
DependencyResolver.SetResolver(resolver);

这可让您使用 InstancePerHtt prequest 和这样的里面的单元测试,而不必实际真正的请求上下文。这也意味着你应该能够使用请求范围一辈子在你的注册/解决方法,而不是有回落应用程序容器上。

This lets you use InstancePerHttpRequest and such inside unit tests without actually having a real request context. It also means you should be able to use the request lifetime scope in your registration/resolution method and not have to fall back on the application container.

这篇关于Autofac:没有办法解决最里面的范围是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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