加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – Autofac:解决最内层范围的任何方法?

发布时间:2020-12-16 10:01:48 所属栏目:asp.Net 来源:网络整理
导读:在过去几年中使用过Ninject,Castle Windsor和其他IoC容器之后,我正在尝试使用新的ASP.NET MVC项目中的Autofac.因此,虽然我一般都了解IoC容器,但我对Autofac还不熟悉,而且我仍然在寻找一些最佳实践. 目前我正在试图找出是否有办法解决最里面的嵌套范围. 我有
在过去几年中使用过Ninject,Castle Windsor和其他IoC容器之后,我正在尝试使用新的ASP.NET MVC项目中的Autofac.因此,虽然我一般都了解IoC容器,但我对Autofac还不熟悉,而且我仍然在寻找一些最佳实践.

目前我正在试图找出是否有办法解决最里面的嵌套范围.

我有以下情况:注册为SingleInstance()的组件具有创建嵌套生命周期范围的方法,提供配置操作以将某些组件配置为InstancePerLifetimeScope,并且在此嵌套范围内解析已注册的组件以执行有用的操作,像这样:

ILifetimeScope currentScope = ???;

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

问题是我希望currentScope成为最里面的生命周期范围,因为我知道X依赖于最里面范围内的组件.在最简单的情况下,例如当前请求的生命周期范围.我当然可以使用AutofacDependencyResolver.Current.RequestLifetimeScope来获取它,但我不想使用它,因为它不是真的可以测试.而且,寿命范围不一定是最里面的.

那么,有没有办法找到最里面的寿命范围,例如根容器还是不同的ILifetimeScope?

解决方法

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

嵌套范围(如果你只有一个ILifetimeScope)无法“向后走”以到达容器.无论如何,我不一定确定你想这样做.

听起来你的SingleInstance组件正在做某种服务定位,基本上是通过手动注册/解析某些组件.如果注册的类型集是固定的,我可能会建议(如果可能的话)对系统进行一些重新设计,因此SingleInstance组件不再被注册为SingleInstance,而是被注册为InstancePerDependency,然后将这些其他项目作为构造函数参数.

代替…

// 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();

您可能会尝试反转一下:

// 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();

我们的想法是不必进行动态注册和即时解决的事情.

如果您遇到服务定位,如果您需要绝对最内层范围,则需要使用AutofacDependencyResolver.Current.ApplicationContainer,但请记住,如果您这样做,那么您注册为InstancePerHttpRequest的任何对象将无法解析,因此您可能会遇到麻烦.建议使用AutofacDependencyResolver.Current.RequestLifetimeScope.这会使你的方法:

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

在测试环境中,AutofacDependencyResolver允许您交换指示如何生成请求生存期的提供程序.您可以实现这样的简单/存根:

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

同样,只是用于单元测试的存根,而不是您在生产中使用的存根.

然后,当您在测试中连接DependencyResolver时,您将提供您的生命周期范围提供者:

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

这使您可以使用InstancePerHttpRequest和此类内部单元测试,而无需实际具有实际请求上下文.这也意味着您应该能够在注册/解决方法中使用请求生命周期范围,而不必依赖于应用程序容器.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读