I'm trying to copy the cs code used within the Identity
scaffold Pages (like Register.cshtml.cs
) but to be used in the context of Roles
and RoleManager
.
I simply want to create a page which creates an "Administrator" role and assigns it to the active logged in user with this page code that executes OnGet()
:
namespace Scratch.Pages
{
public class AdminUserModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly IUserStore<IdentityUser> _userStore;
private readonly RoleManager<IdentityRole> _roleManager;
private readonly IRoleStore<IdentityRole> _roleStore;
private readonly ILogger<AdminUserModel> _logger;
public AdminUserModel(ILogger<AdminUserModel> logger,
UserManager<IdentityUser> userManager,
IUserStore<IdentityUser> userStore,
RoleManager<IdentityRole> roleManager,
IRoleStore<IdentityRole> roleStore)
{
_logger = logger;
_userManager = userManager;
_userStore = userStore;
_roleManager = roleManager;
_roleStore = roleStore;
}
public async void OnGet(bool setAdmin)
{
bool _setAdmin = setAdmin;
if (setAdmin)
{
await AdminUser();
}
RedirectToPage("/Index");
}
public async Task<IActionResult> AdminUser()
{
if (ModelState.IsValid)
{
IdentityRole adminRole;
bool roleExists = await _roleManager.RoleExistsAsync("Administrators");
if (!roleExists)
{
adminRole = CreateRole();
adminRole.Name = "Administrators";
adminRole.NormalizedName = "Administrators";
adminRole.ConcurrencyStamp = "x";
await _roleManager.CreateAsync(adminRole);
}
else
{
var _adminRole = await _roleManager.FindByNameAsync("Administrators");
adminRole = _adminRole;
}
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
var userName = User.Identity.Name;
IdentityUser user = await _userManager.FindByNameAsync(userName);
await _userManager.AddToRoleAsync(user, adminRole.Name);
}
TempData["success"] = "User added to admin role";
}
return Page();
}
private IdentityRole CreateRole()
{
try
{
return Activator.CreateInstance<IdentityRole>();
}
catch
{
throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityRole)}'. "
$"Ensure that '{nameof(IdentityRole)}' is not an abstract class and has a parameterless constructor");
}
}
}
}
But I'm encountering this error on this (await _userManager.AddToRoleAsync(user, adminRole.Name);
) line.
System.ObjectDisposedException
HResult=0x80131622
Message=Cannot access a disposed object.
Object name: 'UserManager`1'.
Source=Microsoft.Extensions.Identity.Core
StackTrace:
at Microsoft.AspNetCore.Identity.UserManager`1.ThrowIfDisposed()
at Microsoft.AspNetCore.Identity.UserManager`1.<AddToRoleAsync>d__105.MoveNext()
at Scratch.Pages.AdminUserModel.<AdminUser>d__7.MoveNext() in C:\Users\Alex\Desktop\PMP\Scratch\Scratch\Pages\AdminUser.cshtml.cs:line 90
at Scratch.Pages.AdminUserModel.<OnGet>d__6.MoveNext() in C:\Users\Alex\Desktop\PMP\Scratch\Scratch\Pages\AdminUser.cshtml.cs:line 53
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi)
at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action`1 callback, TState& state)
at System.Threading.QueueUserWorkItemCallback.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
at System.Threading.Thread.StartCallback()
that is if I can even get past the error at the bool roleExists = await _roleManager.RoleExistsAsync("Administrators");
line which shows:
System.Threading.Tasks.TaskCanceledException
HResult=0x8013153B
Message=A task was canceled.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenInternalAsync>d__70.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenInternalAsync>d__70.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenAsync>d__66.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__19.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__19.MoveNext()
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__18.MoveNext()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__15`1.MoveNext()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__15`1.MoveNext()
at Microsoft.AspNetCore.Identity.RoleManager`1.<RoleExistsAsync>d__33.MoveNext()
at Scratch.Pages.AdminUserModel.<AdminUser>d__7.MoveNext() in C:\Users\Alex\Desktop\PMP\Scratch\Scratch\Pages\AdminUser.cshtml.cs:line 68
at Scratch.Pages.AdminUserModel.<OnGet>d__6.MoveNext() in C:\Users\Alex\Desktop\PMP\Scratch\Scratch\Pages\AdminUser.cshtml.cs:line 53
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi)
at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action`1 callback, TState& state)
at System.Threading.QueueUserWorkItemCallback.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
at System.Threading.Thread.StartCallback()
70% of the time.
So either I'm missing something or I'm going about this incorrectly somehow. pls help.
CodePudding user response:
I just needed to use public async Task OnGetAsync()
and not public async void OnGet()
. I didn't realize that Task
operates like a function modifier (even though it is a class, which is somewhat confusing) that makes the function asynchronous.