UOW - 在上一次异步操作完成之前,在此上下文中启动了第二个操作

时间:2015-02-04 20:55:19

标签: c# async-await entity-framework-6

我正在尝试使用代码,它有两个部分,一个是通过棱镜导航。 当允许导航时,我以异步方式开始深度加载,但每次都使用新的上下文。在以后的代码中,我想要取消未完成此加载的挂起导航,但下面的代码甚至不起作用,因此取消是稍后的事情; - )

导航逻辑:这里没问题

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

我不断得到例外,好像我忘了等待,但事实并非如此。 每当我想在GUI线程上继续时,我也正确使用configureawait(true)。但我一直在深度加载逻辑中得到这个错误。工作单元和存储库类也使用异步等待机制,但我正在等待正确。

在上一次异步操作完成之前,在此上下文中启动了第二个操作。使用&#39;等待&#39;确保在调用此上下文中的另一个方法之前已完成任何异步操作。不保证任何实例成员都是线程安全的。

修改(删除记录器代码以减少代码大小)

2 个答案:

答案 0 :(得分:16)

问题是这段代码:

_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而不是它自己的,因为它被覆盖了。 不是那么容易发现,而是简单的竞争条件。 我通过用局部变量替换所有实例变量来找到它,然后问题就消失了。

答案 1 :(得分:1)

这可能不是答案,而是对代码的一般看法。

async / await的主要目的是保持当前线程可用。这有助于阻止UI线程并使您的应用程序保持响应。

您已经确定深度加载发生在ThreadPool线程上,因为您完全使用 Task.Run()启动它。您可以通过在加载机制中使用EntityFramework的默认同步方法来解决大多数问题。

初看起来,您的代码在异步调用中看起来正常。也许您的深度加载会被多次触发?