微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用异步任务和拥有的实例升级 Autofac 时出现问题

如何解决使用异步任务和拥有的实例升级 Autofac 时出现问题

在我的 ASP.NET MVC 应用程序中从 4.9.2 升级到 5.2 后,我遇到了 Autofac 问题。 我在控制器中使用 Func<Owned<T>> 工厂模式,因为控制器操作启动一个长时间运行的任务,并且运行时间比请求存在的时间长。在该任务中,我正在解决其他实例。

这在 Autofac 4.9.2 中运行良好。但是在升级到 Autofac 5.2 后,父生命周期范围 (AutofacWebRequest) 被释放,并且无法再在拥有的实例中解析实例。

Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.

我可以做些什么来解决这个问题,或者有什么最佳实践吗?

控制器代码

private readonly Func<Owned<IBusinessLogic>> _businessLogicFactory;
public ActionResult Index()
{
    var businessLogic = _businessLogicFactory();

    var unitOfWorkFactory = _unitOfWorkFactory;
    Task.Run(() =>
    {
        System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
        using (businessLogic)
        {
            var task = businessLogic.Value.DoHardBusinessAsync();
            task.Wait();
        }
    });

    return View();
}

业务逻辑代码(也使用工厂):

public class BusinessLogic : IBusinessLogic
{
    private readonly Func<Owned<OtherBusinessLogic>> _otherBusinessLogicFactory;

    public BusinessLogic(Func<Owned<OtherBusinessLogic>> otherBusinessLogicFactory)
    {
        _otherBusinessLogicFactory = otherBusinessLogicFactory;
    }

    public async Task DoHardBusinessAsync()
    {
        using (var otherBusiness = _otherBusinessLogicFactory())
        {
            await otherBusiness.Value.DoHardBusinessAsync();
        }
    }
}

解决方法

您可以尝试创建一个新的生命周期范围,该范围独立于要用于长时间运行的任务的请求范围

    Task.Run(() =>
    {
        using (var scope = container.BeginLifetimeScope())
        {
            System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
            using (businessLogic)
            {
               var task = businessLogic.Value.DoHardBusinessAsync();
               task.Wait();
            }
        }
    });

查看此问题以了解有关如何获取容器的想法 Retrieving Autofac container to resolve services

,

@NataliaMuray 的方法很棒 - 缺点是它倾向于鼓励服务定位器样式解析而不是构造函数注入。这往往会“隐藏”依赖关系,从而更难识别给定类的依赖关系。

一种潜在的解决方案是引入依赖项的概念,该概念明确表示它包装了另一个依赖项,您希望在正常 Web 请求的生命周期范围之外解析该依赖项。

代码可能类似于:

public class AsyncRunner : IAsyncRunner
{
    public ExecutionResult TryExecute<TService>(Action<TService> toEvaluate,string @exceptionErrorMessage,int timeoutMilliseconds,string additionalErrorInformation = "")
    {
        try
        {
            var task = new Task(() =>
            {
                using (var scope = container.BeginLifetimeScope())
                {
                    var service = scope.Resolve<TService>();
                    toEvaluate(service);
                }
            });

            task.ContinueWith(t => { /* logging here */,TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously).SuppressExceptions();

            task.Start();
            var completedWithinTime = task.Wait(timeoutMilliseconds);
            return completedWithinTime ? ExecutionResult.Ok : ExecutionResult.TimedOut;
        }
        catch (Exception e)
        {
            /* logging here */
            return ExecutionResult.ThrewException;
        }
    }
}

同时向 Autofac 注册 IAsyncRunner。

然后是你的依赖,而不是

private readonly Func<Owned<IBusinessLogic>> _businessLogicFactory;

private readonly IAsyncRunner<IBusinessLogic>> _businessLogic;

而不是:

var businessLogic = _businessLogicFactory();
var unitOfWorkFactory = _unitOfWorkFactory;
Task.Run(() =>
{
    System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
    using (businessLogic)
    {
        var task = businessLogic.Value.DoHardBusinessAsync();
        task.Wait();
    }
});

应该是:

//var businessLogic = _businessLogicFactory();
var unitOfWorkFactory = _unitOfWorkFactory;
Task.Run(() =>
{
    System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved

    _businessLogic.TryExecute(z => {
        var task = z.Value.DoHardBusinessAsync();
        task.Wait();
    });
});

这种风格的优点是属性和构造函数注入明确了依赖是什么,以及它们是如何使用的(即声明明确它将在标准生命周期范围的上下文之外解析)。请注意,您不需要在我的建议中使用 Owned(处理手动构建的生命周期范围就足够了)。我已经删除了 Func 的使用,但如果您真的需要它和我的建议,您可以使用 FuncLazy

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?