How to Seed Roles in .NET Core 2.0?

1

At the moment I am trying to get Roles configured using the RoleManager<Identity>, built into .NET Core 2.0, mvc-framework.

However I am getting the following error:

System.ObjectDisposedException
HResult=0x80131622
Message=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. The error occured in line 20 of UserRoleSeed-class.

Is this because of the async-character of the Seed() method?

My Program.cs:

public class Program
{
    public static void Main(string[] args)
    {
        var host = BuildWebHost(args);

        using (var scope = host.Services.CreateScope())
        {
            var serviceProvider = scope.ServiceProvider;
            try
            {
                var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

                new UserRoleSeed(roleManager).Seed();
            }
            catch
            {
                throw new Exception();
            }
        }

        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

My UserRoleSeed.cs:

public class UserRoleSeed
{
    private readonly RoleManager<IdentityRole> _roleManager;

    public UserRoleSeed(RoleManager<IdentityRole> roleManager)
    {
        _roleManager = roleManager;
    }

    public async void Seed()
    {
        if ((await _roleManager.FindByNameAsync("Berijder")) == null)
        {
            await _roleManager.CreateAsync(new IdentityRole {Name = 
        "Berijder"});
        }
    }
}

This should create a new entry into the dbo.AspNetRoles table of my Context imo, but it doesn't. The problem could be something small, this is the first time I tried using roles in the Mvc-framework.

I tried to use the Startup.cs file at first, calling the Seed() method in the Configure() method of this file, that didn't work (probably because this is CORE 2.0 and not 1.0).

c#
asp.net-core
.net-core
asp.net-core-mvc
.net-core-2.0
asked on Stack Overflow May 3, 2018 by ramon abacherli • edited Jan 22, 2019 by ekad

1 Answer

1

An async void functions as a fire-and-forget method. The code will continue to run and dispose all objects before the async void is completed. Another way to handle this:

Make it an async Task and call Wait();

public async Task SeedAsync()
{
    ...
}

call it like so:

// Calling Wait in EFCore is not so much of a problem, since there is not
// really a main blocking thread like UI program's have in .NET framework.
new UserRoleSeed(roleManager).SeedAsync().Wait();

Another solution is to use a task runner:

public static void Main(string[] args)
{
    var host = BuildWebHost(args);
    Task.Run(() => InitializeAsync(host));
    host.Run();
}

private static async Task InitializeAsync(IWebHost host)
{
    using (var scope = host.Services.CreateScope())
    {
        var serviceProvider = scope.ServiceProvider;
        try
        {
            var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

            await new UserRoleSeed(roleManager).SeedAsync();
        }
        catch
        {
            // TODO: log the exception
            throw;
        }
    }
}

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .Build();
answered on Stack Overflow May 3, 2018 by Silvermind

User contributions licensed under CC BY-SA 3.0