wil
wil

Reputation: 903

EF Core System.ObjectDisposedException

I am getting this error mentioned in the title. The same code works for the first API call, but not for the 2nd call. It fails on the 2nd SaveChangesAsync() call

await dbContext.SaveChangesAsync().ConfigureAwait(false);  

I am using

services.AddTransient<ProjectContext>(); 

in my startup.cs. I tried AddScope but it doesn't work.

Error:

System.ObjectDisposedException: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ProjectContext'.'

Code:

private readonly Action<InjectedControllerArgs, ProjectDto, NavigationElements> _postAfterSave = async (injectedControllerArgs, dto, nav) => {
var memberClient = new MemberClient { MemberId = member.MemberId, 
                                      InvitationEmail = member.Email, 
                                      ClientId = dto.ClientId, 
                                      LastModifierId = member.MemberId };   
await dbContext.MemberClient!.AddAsync(memberClient).ConfigureAwait(false);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
             
var role = await dbContext.Role.Where(r => "client-admin" == r.RoleCode)
                               .FirstOrDefaultAsync()
                               .ConfigureAwait(false);
await dbContext.MemberClientRole!.AddAsync(new MemberClientRole
                                               { LastModifierId = member.MemberId, 
                                                 MemberClientId = memberClient.MemberClientId, 
                                                 RoleId = role.RoleId })
                                 .ConfigureAwait(false);
await dbContext.SaveChangesAsync().ConfigureAwait(false); }


    public async Task<ActionResult<ProjectDto>> PostInsertAsync(int customerId, int clientId, ProjectDto dto)
    {
        if (dto == null) throw new ArgumentNullException(nameof(dto));
        dto.CustomerId = customerId;
        dto.ClientId = clientId;
        return await _pmBaseController.PostAsync(new NavigationElements(customerId, clientId, null), Topic, dto,
            _returnOne, _postBeforeSave, _postAfterSave).ConfigureAwait(false);
    }


    public async Task<IActionResult> PutAsync(NavigationElements nav,
        TopicName topic,
        int id,
        TDto dto,
        Func<InjectedControllerArgs, NavigationElements, int, Task<T>> returnOne,
        Func<TDto, int, TDto>? putBeforeSave = null,
        Action<InjectedControllerArgs, TDto, NavigationElements>? putAfterSave = null
    ) ...

Upvotes: 1

Views: 455

Answers (1)

Suchiman
Suchiman

Reputation: 1776

Your _postAfterSave delegate is asynchronous but does not return a Task which effectively means it is async void so your _pmBaseController is unable to await it which means execution will proceed before this Action is done. That the first SaveChanges works is timing / coincidence.

Try changing the type from Action<InjectedControllerArgs, ProjectDto, NavigationElements> to Func<InjectedControllerArgs, ProjectDto, NavigationElements, Task> and make sure to await it everywhere.

Upvotes: 2

Related Questions