Autofac为新线程创建子范围不能按预期工作“无法解析实例,无法创建嵌套生命周期......”

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Autofac为新线程创建子范围不能按预期工作“无法解析实例,无法创建嵌套生命周期......”相关的知识,希望对你有一定的参考价值。

当有人调用URL“/ index / 5”时,我想返回一个视图,并且我希望启动一个新线程,我想通过一些数据库调用和业务逻辑来判断我是否应该发送其他人一个通知。这是我的设置的简化表示,它给出了一个错误。

如何让我的子范围在并行线程中工作?

应用启动

var builder = new ContainerBuilder();
builder.RegisterType<MyRepository>().As<IMyRepository();
builder.RegisterType<Entities>().As<Entities>().InstancePerRequest();
var container = builder.Build();

调节器

    private readonly IMyRepository _myRepository ;

    public MyController(
        IMyRepository myRepository
       )
    {
        _myRepository = myRepository;
    }

    public async Task<ActionResult> Index(int id)
    {
        _myRepository.DoSomething(id);

        return View();
    }

库:

private ILifetimeScope _lifeTimeScopeChild = null;

public void DoSomething(int id){
            //start new thread with child scope
            using(var threadLifeTime = AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope())
            {
                _lifeTimeScopeChild = threadLifeTime;
                 Thread t = new Thread(new ParameterizedThreadStart(MySeparateThread));
                 t.Start(id);  
            }
        }

        private void MySeparateThread(object id) {
                    var _entities = _lifeTimeScopeChild.Resolve<Entities>(); //IT CRASHES HERE
        }

错误:

Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.

我想要实现的目标:https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html#thread-scope

答案

这部分的关键部分不是错误消息的第一部分,而是最后一部分:

它已经被处理掉了。

using(var threadLifeTime = AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope())
{
    _lifeTimeScopeChild = threadLifeTime;
    Thread t = new Thread(new ParameterizedThreadStart(MySeparateThread));
    t.Start(id);  
}

threadLifeTime是在你的using区块的声明中创建的。在那个街区的尽头,它被处理掉了。这是using区块的唯一目的。内置了一个假设,即对象可以在那一点处理。你完成了它。

您还要创建一个单独的线程并将threadLifeTime传递给它。代码中未发生的部分未显示,但这就是正在发生的事情。您可能没有明确地传递它,但它在ParameterizedThreadStartMySeparateThread中被引用。

该线程继续与最初调用它的方法分开执行。因此,在您移交该物体后,它立即被处理掉。无论该线程在做什么,它都试图用一个被处理的对象来做。那是错误。

通常在using区块的末尾,变量(threadLifeTime)将超出范围。没有任何参考,所以如果它被处置也没关系。但现在有一个对它的引用,这是一个问题,因为它是对已被处理的东西的引用。

短期解决方案不是创建单独的线程。如果有一个涉及多线程的正确答案,那就更复杂,超出了这个答案的范围。一个好的经验法则是首先在没有多线程的情况下使代码工作,然后在需要时添加它。否则你不知道问题是多线程还是其他问题。

另一个问题是:

_lifeTimeScopeChild = threadLifeTime;

它表明它不仅被传递给其他某个线程,它还被分配给该类中的一个字段。出于同样的原因,这也是一个问题。即使在放置对象后,您分配给该字段的引用仍将存在。如果在这个_lifeTimeScopeChild块完成之后有任何东西试图使用using它将会得到相同的错误。

要回答的问题是“我的方法需要这个对象还是我的类需要这个对象?”

如果你的方法需要它,那么在方法中声明并使用它,但不允许任何你无法控制的引用从方法“逃避”。如果你处理它,那么你将破坏任何试图使用它的东西。如果你不处理它,那么,它应该没有被处理掉。

如果您的类需要它,那么考虑在创建类时创建它,或者在需要时使用延迟实例化创建它。 (我从前者开始。)然后让你的班级实现IDisposable,当你的班级被处置时,那就是当你处理你班级使用的任何一次性资源时。

以上是关于Autofac为新线程创建子范围不能按预期工作“无法解析实例,无法创建嵌套生命周期......”的主要内容,如果未能解决你的问题,请参考以下文章

Handler系列之创建子线程Handler

如何在 .NET Core 中使用默认依赖注入从父级创建子范围?

具有特定条件计数的 Mongodb 聚合并按输出投影的日期范围过滤不能按预期工作

如何在 EPiServer 8.0 中以编程方式创建子页面

android创建子线程

无法为不同线程中的父级创建子级