简体   繁体   中英

Why is Dispose called before its finishes async task?

I've recently stumbled on this strange error. It looks like one of my object is disposing before my method finish all async Task. But let's take a look.

I have that async method which seeds my database. It's called in Startup class in Configure method.

private void InitDatabase(IApplicationBuilder app) {
            using (var scope = app.ApplicationServices.CreateScope()) {
                var services = scope.ServiceProvider;
                try {
                    var context = services.GetRequiredService<GrabGoContext>();
                    new DatabaseInitializer().InitializeAsync(context,
                        services.GetService(typeof(UserManager<User>)) as UserManager<User>,
                        services.GetService(typeof(SignInManager<User>)) as SignInManager<User>,
                        services.GetService(typeof(RoleManager<IdentityRole<int>>)) as RoleManager<IdentityRole<int>>,
                        _logger).Wait();
                    _logger.LogDebug("Database initialization finished.");
                }
                catch (Exception ex) {
                    _logger.LogError(ex, "An error occurred while seeding the database.");
                    if (Debugger.IsAttached) Debugger.Break();
                }
            }
        }

And that method from DatabaseInitializer class:

    public async Task InitializeAsync(GrabGoContext context,
        UserManager<User> userManager,
        SignInManager<User> signInManager,
        RoleManager<IdentityRole<int>> roleManager,
        ILogger<Startup> logger) {

        if(IsDatabaseInialized) return;
        IsDatabaseInialized = true;
        await context.Database.EnsureCreatedAsync();
        await AddStores(context);
        await AddProducts(context);
        await AddRoles(roleManager)
            .ContinueWith(t => AddRolesToUsers(userManager)); // <- Here throws exception "System.ObjectDisposedException" for object `userManager`
        await AddUsers(userManager);
        await context.SaveChangesAsync();
    }

The thing is that if I use ContinueWith to chain Tasks, it throws System.ObjectDisposedException on userManager object. But I need to use ContinueWith , because I need Roles before I will assign users to that roles.

My methods responsible for adding roles

        private async Task AddRoles(RoleManager<IdentityRole<int>> roleManager) {
            if (await roleManager.Roles.AnyAsync()) return;

            var roles = (List<IdentityRole<int>>) new RolesListExample().GetExamples();
            foreach (var role in roles) {
                var result = await roleManager.CreateAsync(role);
                if(!result.Succeeded) throw new ApplicationException("Erros while adding roles: " +
                                                                     JsonConvert.SerializeObject(result.Errors));
            }
        }

        private async Task AddRolesToUsers(UserManager<User> userManager) {
            var registerModels = (List<RegisterModel>)new RegisterListRequestExample().GetExamples();
            foreach(var registerModel in registerModels) {
                var user = await userManager.FindByEmailAsync(registerModel.Email);
                var result = await userManager.AddToRoleAsync(user, registerModel.Role.ToString());
                if(!result.Succeeded)
                    throw new ApplicationException("Erros while adding roles to user: " +
                                                   JsonConvert.SerializeObject(result.Errors));
            }
        }

And also my RolesListExample class :

    public class RolesListExample : IExamplesProvider {
        /// <inheritdoc />
        public object GetExamples() {
            var roles = new List<IdentityRole<int>>();
            foreach (var availableRole in (AvailableRoles[]) Enum.GetValues(typeof(AvailableRoles))) {
                roles.Add(new IdentityRole<int>(availableRole.ToString()));
            }
            return roles;
        }
    }

My question is:

Why is my object disposing before all Tasks are finished?

I assume that's because of the using . Also I found that Question , but didn't clarify situation for me.

@Update

As suggested by @PanagiotisKanavos I removed using statement and it solved my disposing problem. Thanks!

You are awaiting only the continuation of the task. Instead of:

await AddRoles(roleManager).ContinueWith(t => AddRolesToUsers(userManager));

...try:

var task1 = AddRoles(roleManager);
var task2 = task1.ContinueWith(t => AddRolesToUsers(userManager));
await task1;
await task2;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM