0

In the ASP.NET Core Web API project, I wrote the following interface. The first request is normal, and the second request will report an error. It should be that I don't know enough about asynchronous programming. I don't know why errors are reported. I hope a friend can give me some advice.

[HttpGet("role_claims")]
public async Task<IActionResult> role_claims()
{
    // var user = await userManager.GetUserAsync(User);
    // var roles = await userManager.GetRolesAsync(user);

    List<Claim> claims = new List<Claim>();
    var roles = this.User.FindAll(ClaimTypes.Role).ToList();

    roles.ForEach(async x => {
            MyRole role = await roleManager.FindByNameAsync(x.Value);
            IList<Claim> list = await roleManager.GetClaimsAsync(role);
            Console.WriteLine($"{x.ValueType} {x.Value} {list.Count}");
            list.ToList().ForEach(x => claims.Add(x));
    });

    return Ok(claims.Select(claim => new { claim.Type, claim.Value }).ToArray());
}

The error information is as follows

fail: Microsoft.EntityFrameworkCore.Query[10100]

An exception occurred while iterating over the results of a query for context type 'OnePlan.Conf.IdentityDb'.

System.ObjectDisposedException: Cannot access a disposed context instance. A common cause of this error is disposing a context instance 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 instance, or wrapping it 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: 'IdentityDb'.

at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Internal.IDbContextDependencies.get_StateManager()
at Microsoft.EntityFrameworkCore.Query.QueryContextDependencies.get_StateManager()
at Microsoft.EntityFrameworkCore.Query.QueryContext.InitializeStateManager(Boolean standAlone)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken) at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.AsyncEnumerator.MoveNextAsync()

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
桑榆肖物
  • 73
  • 2
  • 8

1 Answers1

1

You have an impressive amount of problems for such few lines of code.

Starting with calling ToList() on an EF.Core (probably?) context, which you should literally never do. The async version takes care of any multi-threaded synchronization between worker threads.

Then that ForEach function you're using doesn't support async calls, or you'd be awaiting it. What it does instead is run literally nothing, then return your Ok() result, then disposes of your context and lastly actually runs your code inside that ForEach, way after the context is disposes, hence your problem.

Either use a regular foreach over your entity, or write a ForEachAsync extension function and await it in your call.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • Thank you. I understand. That's true. When I try to solve it myself, I use "foreach" instead, and it can work normally. `foreach (var role in roles) { var myrole = await roleManager.FindByNameAsync(role.Value); var list = await roleManager.GetClaimsAsync(myrole); Console.WriteLine($"{role.ValueType} {role.Value} {list.Count}"); list.ToList().ForEach(x => claims.Add(x)); }` – 桑榆肖物 Jun 01 '22 at 16:46