I'm attempting to create an initial 'Super User' in an ASP.NET 5 application. Using the latest template files with MVC 6 / EF7.
I can follow the examples set out here:
http://wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7
This works fine - until I try to execute an async method. For example:
await _userManager.CreateAsync(user, "P@55w0rd!");
or even:
await _context.SaveChangesAsync();
Synchronous methods work without a problem and this code executes outside of the Startup.cs Configure{...}
as well.
I get the 'White Screen of Death' on application start. I would do it all without async but I don't think the UserManager has a Create()
in Identity 3.0.
Is this me not understanding asynchronous programming or should it be possible?
EDIT: Added the entire call:
Define a Seeder
class and a method to create the user:
public class Seeder
{
private ApplicationDbContext _context;
private UserManager<ApplicationUser> _userManager;
public Seeder(
ApplicationDbContext context,
UserManager<ApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task Seed()
{
await CreateUsersAsync();
}
public async Task CreateUsersAsync()
{
var user = await _userManager.FindByEmailAsync("[email protected]");
if (user == null)
{
var company = _context.Company.First(x => x.Name == "Acme Ltd");
user = new ApplicationUser
{
UserName = "[email protected]",
Email = "[email protected]",
CreatedDate = DateTime.Now,
IsActive = true,
CompanyID = company.CompanyId
};
await _userManager.CreateAsync(user, "P@55w0rd!!");
}
}
}
Configure the service:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<Seeder>();
...
}
Call it:
public async void Configure(Seeder seeder)
{
...
await seeder.Seed();
...
}
Funny thing is; it does actually create the User - it just doesn't continue. So the second time it executes user != null
and it executes fine.
I think the problem is because a deadlock is formed by the signature
public async void Configure(Seeder seeder).
Since it returns void, the awaited Task is never returned to the caller which creates a dead lock. Can you make it:
public async Task Configure(Seeder seeder).
I haven't gotten to work with MVC 6 yet, :( so I may be missing something. But that's why there is a deadlock.
Edit:
Since you can't change the signature of Configure, create a method called ConfigureAsync that returns type Task. Now await as per usual inside of it with your user manager code and call ConfigureAsync from Configure but wait on it.
ConfigureAsync.ConfigureAwait(false).Wait()
ConfigureAwait (false) is used to prevent potential dead locks of waiting on the async method to complete.
Full example:
public void Configure(Seeder seeder)
{
//Edited due to typo/bad syntax.
ConfigureAsync(seeder).Wait();
}
public async Task ConfigureAsync(Seeder seeder)
{
//Now treat this like true async/await.
await seeder.Seed().ConfigureAwait(false);
}
If you run into deadlocks here, perhaps your seeder should just be synchronous? I would avoid using Task.Run() in an ASP.NET context because that will totally defeat the purpose of async/await in the first place by taking up two request threads that would have just been done on one if done synchronously.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With