UOW - вторая операция началась в этом контексте до завершения предыдущей асинхронной операции

Я пытаюсь использовать следующий код, он состоит из двух частей, один - через призму. Когда разрешена навигация, я начинаю асинхронно, но каждый раз с новым контекстом. В более позднем коде я хотел бы отменить ожидающие навигационные операции, которые не были завершены этой загрузкой, но приведенный ниже код не работает, поэтому отмена - это вопрос позже; -)

логика навигации: здесь нет проблем.

public void OnNavigatedTo(NavigationContext navigationContext)
{
    int relatieId = (int)navigationContext.Parameters["RelatieId"];
    if (_relatie != null && _relatie.RelatieId == relatieId) return;

    loadRelatieAsync(relatieId);
}

public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
    bool navigationAllowed = true;
    continuationCallback(navigationAllowed);
}

логика глубокой загрузки:

private async Task loadRelatieAsync(int relatieId)
{
    try
    {
        await Task.Run(async () =>
        {

            _unitOfWork = _UnitOfWorkFactory.createUnitOfWorkAsync();

            IEnumerable<Relatie> relaties = await getRelatieAsync(_unitOfWork, relatieId).ConfigureAwait(true);

            _relatieTypeTypes = await getRelatieTypeTypesAsync(_unitOfWork, relatieId).ConfigureAwait(true);
            _relatie = relaties.FirstOrDefault();

            _unitOfWork.Dispose();
        }).ConfigureAwait(true);

        processRelatie(_relatie);

        processRelatieTypes(_relatie, _relatieTypeTypes);
    }
    catch (Exception Ex)
    {

        MessageBox.Show(Ex.Message);
        throw;
    }

}

private async Task<IEnumerable<Relatie>> getRelatieAsync(IUnitOfWorkAsync unitOfWork, int relatieId)
{

    IEnumerable<Relatie> relaties = null;
    try
    {
        IRepositoryAsync<Relatie> relatieRepository = unitOfWork.RepositoryAsync<Relatie>();
        relaties = await relatieRepository
            .Query(r => r.RelatieId == relatieId)
            .Include(i => i.BegrafenisOndernemer)
            .SelectAsync()
            .ConfigureAwait(false);

        IRepositoryAsync<Adres> adresRepository = unitOfWork.RepositoryAsync<Adres>();
        //exception is thrown after executing following line
        var adressen = await adresRepository
            .Query(r => r.RelatieId == relatieId)
            .Include(i => i.AdresType)
            .SelectAsync()
            .ConfigureAwait(false);
        _relatieTypeRepository = unitOfWork.RepositoryAsync<RelatieType>();
        var relatieTypes = await _relatieTypeRepository
            .Query(r => r.RelatieId == relatieId)
            .SelectAsync()
            .ConfigureAwait(false);
    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);//exception is shown here
        throw;
    }
    return relaties;
}

private async Task<IEnumerable<RelatieTypeType>> getRelatieTypeTypesAsync(IUnitOfWorkAsync unitOfWork, int relatieId)
{

    IEnumerable<RelatieTypeType> relatieTypeTypes = null;
    try
    {
        IRepositoryAsync<RelatieTypeType> relatieTypeTypeRepository =
            unitOfWork.RepositoryAsync<RelatieTypeType>();

        relatieTypeTypes = await relatieTypeTypeRepository
            .Query()
            .SelectAsync()
            .ConfigureAwait(false);

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
        throw;
    }
    return relatieTypeTypes;
}

Я продолжаю получать исключения, как если бы я забыл подождать, но это никогда не бывает. Я также правильно использую configureawait (true), когда хочу продолжения в потоке графического интерфейса. Но я продолжаю получать эту ошибку в логике дезадаптации. В модуле классов работы и хранилища также используется механизм ожидания async, но также там, где я ожидаю должным образом.

Вторая операция началась в этом контексте до завершения предыдущей асинхронной операции. Используйте "ждут", чтобы убедиться, что какие-либо асинхронные операции были выполнены до вызова другого метода в этом контексте. Любые члены экземпляра не гарантируют безопасность потоков.

Изменить (удаленный код регистратора для уменьшения размера кода)

Ответ 1

Проблема в следующем коде:

_unitOfWork = _UnitOfWorkFactory.createUnitOfWorkAsync();

IEnumerable<Relatie> relaties = await getRelatieAsync(_unitOfWork, relatieId).ConfigureAwait(true);

_relatieTypeTypes = await getRelatieTypeTypesAsync(_unitOfWork, relatieId).ConfigureAwait(true);
_relatie = relaties.FirstOrDefault();

 _unitOfWork.Dispose();

UnitOfWork - это переменная экземпляра, когда сценарий запускается во второй раз, он перезаписывается новым экземпляром. Уже выполняющийся сценарий затем использует этот новый UnitOfWork вместо своего собственного, поскольку он перезаписывается. Не так легко определить, но простое состояние гонки. Я нашел это, заменив все переменные экземпляра локальными переменными, и тогда проблема исчезла.

Ответ 2

Это, вероятно, не ответ, а общий взгляд на ваш код.

Основная цель async/await - сохранить текущий поток доступным. Это помогает не блокировать поток пользовательского интерфейса и не реагировать на ваше приложение.

Вы уже убедились, что ваша глубокая загрузка происходит в потоке ThreadPool, потому что вы начинаете полностью использовать Task.Run(). Вероятно, вы можете обойти большинство своих проблем, используя синхронные методы EntityFramework по умолчанию в вашем механизме загрузки.

В первом образе ваш код выглядит отлично, как и для асинхронных вызовов. Может быть, ваша глубокая загрузка запускается несколько раз?