无法访问已释放的上下文实例 – 在首次运行时

huangapple go评论81阅读模式
英文:

Cannot access a disposed context instance - on the first run

问题

这是一个常见的异常,当尝试访问已释放的上下文时会出现。但是,我在第一次访问上下文时就遇到了这个异常,无法弄清楚为什么会发生这种情况。

这是我用来将上下文注册为“Transient”的代码:

public static IServiceCollection AddSQLContext<TContext>(this IServiceCollection services, string connectionString, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    where TContext : DbContext => services
    .AddDbContext<TContext>(options => options.UseSqlServer(
        connectionString,
        actions => actions.MigrationsAssembly("Discounted.Data")
                          .EnableRetryOnFailure()
    ), serviceLifetime);

这是在“Blazor Server”前端中调用服务引发异常的代码:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        using (var source = new CancellationTokenSource())
        {
            version = VersionService.Version;
            ProtectedBrowserStorageResult<string> customer = await ProtectedSessionStore.GetAsync<string>("customer");
            DashboardDto.LocalUser = customer.Value;

            if (DashboardDto.LocalUser == null) return;

            // 获取订阅状态
            // ==> 不访问上下文
            DashboardDto.LocalStatus = await SubscriptionService.GetSubscriptionStatusAsync(DashboardDto.LocalUser, source.Token);

            // 加载图像
            // ==> 第一次访问上下文
            // ==> 从 GetQRCodeAsync 引发异常
            DashboardDto.StoreId = await QRCodeService.GetQRCodeAsync(DashboardDto.LocalUser, source.Token);

            // 获取奖励
            DashboardDto.Rewards = await RewardService.GetRewardAsync(DashboardDto.StoreId, source.Token);
        }

        StateHasChanged();
    }
}

这是“GetQRCodeAsync”函数和“RewardService”:

public class QRCodeService : IQRCodeService
{
    private IAccountRepository _accountRepository;

    public QRCodeService(IAccountRepository accountRepository)
    {
        _accountRepository = accountRepository;
    }

    public async Task<string?> GetQRCodeAsync(string customerId, CancellationToken cancellationToken)
    {
        // 在这里引发异常
        Account store = await _accountRepository.FirstOrDefaultAsync(x => x.StripeId == customerId, cancellationToken);

        return store.StoreCode.ToString();
    }
}

我将所有服务和存储库都注册为“Transient”。我不确定是什么原因导致了这个问题,因为这是我能想到的第一次调用后端的地方。

英文:

This is a common exception when one tries to access a disposed context. However, I get this exception the first time I access the context and can't figure out why it would happen.

This is the code I use to register my context as a Transient

public static IServiceCollection AddSQLContext&lt;TContext&gt;(this IServiceCollection services, string connectionString, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
            where TContext : DbContext =&gt; services
            .AddDbContext&lt;TContext&gt;(options =&gt; options.UseSqlServer(
               connectionString,
               actions =&gt; actions.MigrationsAssembly(&quot;Discounted.Data&quot;)
                                 .EnableRetryOnFailure()
               ), serviceLifetime);

This is the code in Blazor Server front end that calls the service throwing the exception:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        using (var source = new CancellationTokenSource())
        {
            version = VersionService.Version;
            ProtectedBrowserStorageResult&lt;string&gt; customer = await ProtectedSessionStore.GetAsync&lt;string&gt;(&quot;customer&quot;);
            DashboardDto.LocalUser = customer.Value;

            if (DashboardDto.LocalUser == null) return;

            // Get the subscription status
            // ===&gt; Does not access the context
            DashboardDto.LocalStatus = await SubscriptionService.GetSubscriptionStatusAsync(DashboardDto.LocalUser, source.Token);

            // Load the image
            // ===&gt; Accesses the context for the first time
            // ===&gt; Throws Exception from GetQRCodeAsync
            DashboardDto.StoreId = await QRCodeService.GetQRCodeAsync(DashboardDto.LocalUser, source.Token);

            // Get the rewards
            DashboardDto.Rewards = await RewardService.GetRewardAsync(DashboardDto.StoreId, source.Token);
        }

        StateHasChanged();
    }
}

This is the GetQRCodeAsync function and the RewardService:

public class QRCodeService : IQRCodeService
{
    private IAccountRepository _accountRepository;

    public QRCodeService(IAccountRepository accountRepository)
    {
        _accountRepository = accountRepository;
    }

    public async Task&lt;string?&gt; GetQRCodeAsync(string customerId, CancellationToken cancellationToken)
    {
        // Throws Exception here
        Account store = await _accountRepository.FirstOrDefaultAsync(x =&gt; x.StripeId == customerId, cancellationToken);

        return store.StoreCode.ToString();
    }
}

I am registering all my services and repositories as Transient as well. I am unsure what is causing the issue since this is the first call to the back end that I can think of.

答案1

得分: 2

请使用方法OnAfterRenderAsync代替OnAfterRender

您之所以出现错误是因为您在void函数中执行了异步操作。这意味着主线程不会等待OnAfterRender函数,而是认为请求已完成,因此会释放dbcontext

英文:

Use the method OnAfterRenderAsync instead of OnAfterRender.

You are getting an error because you are doing async operation in void function. This means that the main thread will not wait for the function OnAfterRender and is considering the request completed, therefore disposing the dbcontext.

huangapple
  • 本文由 发表于 2023年6月29日 21:11:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581409.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定