【问题标题】:Simple Injector "instance is requested outside the context of an active (Async Scoped) scope" when using `ContinueWith`使用`ContinueWith`时,简单注入器“在活动(异步作用域)范围的上下文之外请求实例”
【发布时间】:2020-08-25 17:19:35
【问题描述】:

我有一段代码会抛出:

使用“异步作用域”生活方式注册,但在活动(异步作用域)作用域的上下文之外请求实例`

  1. 当我将return 用于Task 时,会抛出上述问题(处理量较高,但处理量较低时还可以)
  2. 但是,当我 await Task 时,无论通过请求量如何,它都能正常工作,Simple Injector 不会抛出。

我很欣赏与 Simple Injector 相比,这可能更多地是一个以异步为中心的问题,但有任何见解为什么用 await 替换 return 可以解决这个问题?

在此先感谢,我担心在“工作”时使用 await 是否可能隐藏更大的问题。

背景:

我有以下循环,由工作人员将项目(要分派的任务)从队列中取出:

void Loop()
{
    while (cancellationToken.IsCancellationRequested == false)
    {
        item = await this.queue.Reader.ReadAsync(cancellationToken);
        
        await DispatchItemAsync(item, (item, dispatcher) =>
        {
            return dispatcher
                .SendAsync(((ISendItem)item).GetHandler, item.Message, item.CancellationToken)
                .ContinueWith(t => item.TaskCompletionSourceWrapper.SetResult(t.Result), TaskContinuationOptions.RunContinuationsAsynchronously);
        });
    }
}

上述循环中的DispatchItemAsync 如下:

protected override async Task DispatchItemAsync(
    IQueueItem item, Func<IQueueItem, IThreadStrategy, Task> dispatchFunc)
{
    // cast the passed item from channel queue
    var queueItemWithStack = item as IQueueItemWithStack;

    using (AsyncScopedLifestyle.BeginScope(this.container))
    {
        var dispatcher = container.GetInstance<InParallel>();
        // the above is an interface of delegates that is used to call functions
        
        // return throws SimpleInjector outside of scope exception (intermittent,
        // always for high request volume)
        return dispatchFunc(queueItemWithStack, dispatcher);

        // using await no exception is thrown
        // await dispatchFunc(queueItemWithStack, dispatcher);
    }
}

InParallel 包含由dispatchFunc 行调用的函数,下面是(最终通过链)调用:

public Task<object> SendAsync(
    Func<SendFunction> getHandler,
    object request,
    CancellationToken cancellationToken = default)
{
    return this
        .inCaller
        .SendAsync(getHandler, request, cancellationToken)
        .ContinueWith(t =>
        { 
            // snip some code
            // the below throws if DispatchItemAsync call us with return
            // but is OK if DispatchItemAsync called us with await instead
            return t.Result;
        });
}

上述ContinueWith在访问t.Result时出现异常:

CommandHandler 是使用“Async Scoped”生活方式注册的,但该实例是在活动(Async Scoped)范围的上下文之外请求的。有关如何应用生活方式和管理范围的更多信息,请参阅https://simpleinjector.org/scoped

【问题讨论】:

    标签: c# multithreading async-await simple-injector


    【解决方案1】:

    通过等待Task,您正在执行Task 与主要操作并行。并行意味着代码变为多线程。

    这意味着原始的Scope 可能会在Task 完成执行之前被释放。这会导致您遇到的异常。但在其他情况下,Scope 可能会在执行Task 期间被丢弃。这将导致对象在Task 运行时被丢弃。这可能会导致奇怪的多线程问题。

    这意味着,就您而言,您应该绝对等待从dispatchFunc 返回的Task

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2020-11-01
      • 2015-08-15
      • 2013-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-18
      • 1970-01-01
      相关资源
      最近更新 更多