简单注入器“在活动(异步作用域)作用域的上下文之外请求实例".当使用`ContinueWith`时 [英] Simple Injector "instance is requested outside the context of an active (Async Scoped) scope" when using `ContinueWith`

查看:84
本文介绍了简单注入器“在活动(异步作用域)作用域的上下文之外请求实例".当使用`ContinueWith`时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个抛出的代码块:

I have a block of code that throws:

使用异步作用域"生活方式进行注册,但是在活动(异步作用域)作用域的上下文之外请求实例.

is registered using the 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope`

  1. 当我将return用作Task时,会抛出上述错误(大容量时,但处理量较小时,可以)
  2. 但是当我await Task时,无论通过量请求量如何,它都可以正常工作,简单喷射器不会抛出.
  1. The above is thrown when I use return for the Task (at higher volumes, but ok at lower processing volumes)
  2. It however works OK regardless of thru-put request volume when I await the Task, Simple Injector does not throw.

我理解,与Simple Injector相比,这可能是一个更加关注异步的问题,但是有何见解为何将return替换为await 可以解决?

I appreciate this may be more of a async focused question as opposed to Simple Injector, but any insights why replacing return with await resolves this?

预先感谢我在工作"期间使用await是否可能会隐藏更大的问题.

Thanks in advance, I am concerned whilst "working" using await is it potentially hiding a larger issue.

背景:

我有以下循环,由工作队出队物品(要分派的任务):

I have the following loop that deques items (tasks to be dispatched) by a worker:

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行所调用的函数,因此以下内容(最终通过链)称为:

With InParallel containing the function which is called by the dispatchFunc line, the below is (eventually via a chain) called:

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

访问t.Result时,上述ContinueWith会发生异常:

The exception occurs on the above ContinueWith when the t.Result is accessed:

CommandHandler是使用异步作用域"生活方式注册的,但是在活动(异步作用域)作用域的上下文之外请求实例.有关如何应用生活方式和管理范围的更多信息,请参见 https://simpleinjector.org/scoped . >

推荐答案

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

By not awaiting a Task, you are executing the Task in parallel with the primary operation. Parallel means the code becomes multi threaded.

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

This means that the original Scope will likely get disposed before the Task finished executing. This causes the exception you are experiencing. But in other cases, the Scope might get disposed off during the execution of the Task. This will cause objects getting disposed of while the Task is running. This can cause weird multi-threading issues.

这意味着,根据您的情况,您应该绝对等待从dispatchFunc返回的Task.

What this means is that, in your case, you should absolutely await the Task that is returned from dispatchFunc.

这篇关于简单注入器“在活动(异步作用域)作用域的上下文之外请求实例".当使用`ContinueWith`时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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