Подтвердить что ты не робот

AsyncLocal Значение обновлено до null в ThreadContextChanged

Я пытаюсь понять, как AsyncLocal должен работать в .Net 4.6. Я помещаю некоторые данные в AsyncLocal... но при изменении ThreadContext он получает значение null. Вся причина, по которой я использую AsyncLocal, заключается в том, чтобы попытаться сохранить/кешировать это значение по потокам, поскольку я жду операций async. Любая идея, почему это было бы специально вызвано и установлено значение null при изменении контекста? Документация по AsyncLocal очень скудная... возможно, у меня все получилось неправильно.

public class RequestContextProvider : IRequestContextProvider
{
    private static readonly AsyncLocal<IRequestContext> _requestContext = new AsyncLocal<IRequestContext>(ValueChangedHandler);

    private static void ValueChangedHandler(AsyncLocalValueChangedArgs<IRequestContext> asyncLocalValueChangedArgs)
    {
        **//This is just here to observe changes...when I await a call that 
        //causes control to pass to a different thread..this is called 
        //with a current value of null.**
        var previousValue = asyncLocalValueChangedArgs.PreviousValue;
        var currentValue = asyncLocalValueChangedArgs.CurrentValue;
        var contextChanged = asyncLocalValueChangedArgs.ThreadContextChanged;
    }

    public void SetContext(IRequestContext requestContext)
    {
        _requestContext.Value = requestContext;
    }

    public IRequestContext GetContext()
    {
        return _requestContext.Value;
    }

}

Вот пример того, как он вызывается. Это асинхронный подписчик событий, который вызывается при использовании соединения EventStore (GetEventStore.com). Если две ожидаемые задачи здесь ничего не делают (если нет идентификаторов для поиска), у меня нет проблем, потому что предположительно задача выполняется синхронно. Но если у меня есть работа над этими задачами, я теряю свой контекст.

 private async Task PublishProduct(Guid productId, Guid productReferenceId, IEnumerable<Guid> disclosureIds,
        IEnumerable<Guid> addOnIds)
    {
        var disclosureReferenceIdsTask = _disclosureReferenceIdService.GetReferenceIdsAsync(disclosureIds);
        var addOnReferenceIdsTask = _addOnReferenceIdService.GetReferenceIdsAsync(addOnIds);
        await Task.WhenAll(disclosureReferenceIdsTask, addOnReferenceIdsTask);

        IEnumerable<Guid> disclosuresResult = await disclosureReferenceIdsTask;
        IEnumerable<Guid> addOnsResult = await addOnReferenceIdsTask;

        await _eventPublisher.PublishAsync(new ProductPublished(productId, productReferenceId,
            disclosuresResult.ToList(), addOnsResult.ToList()));
    }

И вот мое хакерское решение, которое, похоже, работает:

    private static void ValueChangedHandler(AsyncLocalValueChangedArgs<IRequestContext> asyncLocalValueChangedArgs)
    {
        var previousValue = asyncLocalValueChangedArgs.PreviousValue;
        var currentValue = asyncLocalValueChangedArgs.CurrentValue;
        var contextChanged = asyncLocalValueChangedArgs.ThreadContextChanged;
        if (contextChanged && currentValue == null && previousValue != null)
        {
            _requestContext.Value = previousValue;
        }
    }

FYI, это проект выполнения 4.6, работающий под DNX RC1 в качестве консольного приложения.

4b9b3361