Search code examples
c#asp.net-coreasp.net-identityblazorblazor-server-side

GetRolesAsync exits without a trace


It is a Blazor Server app. I use Serilog but no info is shown. I would expect an exception somewhere, but the code just exists without a trace.

This is a simplified version of what I am trying to do. It exits randomly at any of the two GetRolesAsync:

// Both injected as Scoped at Startup.cs
private UserManager<IdentityUser> _userManager;
private RoleManager<IdentityRole> _roleManager;

public Task<IdentityUser> FetchIdentityUser()
{
    // Two users:
    var allUsers = _userManager.Users.ToList();
    
    // Two roles:
    var allRoles = _roleManager.Roles.ToList();
    
    // Each user is attached to a single role in the db
    // (checked via MysqlWorkbench)

    var roleNames1 = _userManager.GetRolesAsync(allUsers.First()).Result; // <-- sometimes it exits here (no exception is thrown, no trace of what's going on ...)
    var roleNames2 = _userManager.GetRolesAsync(allUsers.Last()).Result; // <-- ...and sometimes it exists here (no exception is thrown, no trace of what's goin on ...)
    
    return Task.FromResult(allUsers.First());
}

Solution

  • These are async methods and you need to await them.

    Edit (thanks to Mark Gravell for the comment): What you are likely seeing here is a sync-context deadlock as these try to return to the calling thread. This would also much better explain why you are having difficulty seeing the error!

    public **async** Task<IdentityUser> FetchIdentityUser()
    {
        // Two users:
        var allUsers = _userManager.Users.ToList();
        
        // Two roles:
        var allRoles = _roleManager.Roles.ToList();
        
        // Each user is attached to a single role in the db
        // (checked via MysqlWorkbench)
    
        var roleNames1 = await _userManager.GetRolesAsync(allUsers.First()); // <-- sometimes it exits here (no exception is thrown, no trace of what's going on ...)
        var roleNames2 = await _userManager.GetRolesAsync(allUsers.Last()); // <-- ...and sometimes it exists here (no exception is thrown, no trace of what's goin on ...)
        
        return Task.FromResult(allUsers.First());
    }
    

    You need the awaits and to mark the method itself as async (ensuring it is then awaited where it is called from).

    There are very few occasions when you should directly access the Result of a task like this and you would need your code structured explicitly to let this work.