Suggested Videos
Part 77 - Extend IdentityUser in ASP.NET Core | Text | Slides
Part 78 - Creating roles in asp.net core | Text | Slides
Part 79 - Get list of roles in asp.net core | Text | Slides
In this video we will discuss how to edit an existing role in asp.net core using the Identity API.
Navigating to Edit Role View
The following view displays the list of all roles.
When Edit button on one of the roles is clicked, we want to go to EditRole action in the AdministrationController. We are using asp-action and asp-controller tag helpers to do that. We also want to pass the ID of the role to edit. We pass the Role ID using asp-route-id tag helper.
asp-route-id tag helper includes the Role ID in the URL
Edit Role View
We want the Edit Role View to be as shown below.
The following EditRoleViewModel class carries the data EditRole view needs. Users property holds the list of Users in this role. The constructor initializes Users property so we do not get NULL reference exceptions.
Edit Role Action Methods
Edit Role View
Part 77 - Extend IdentityUser in ASP.NET Core | Text | Slides
Part 78 - Creating roles in asp.net core | Text | Slides
Part 79 - Get list of roles in asp.net core | Text | Slides
In this video we will discuss how to edit an existing role in asp.net core using the Identity API.
Navigating to Edit Role View
The following view displays the list of all roles.
When Edit button on one of the roles is clicked, we want to go to EditRole action in the AdministrationController. We are using asp-action and asp-controller tag helpers to do that. We also want to pass the ID of the role to edit. We pass the Role ID using asp-route-id tag helper.
<a asp-controller="Administration" asp-action="EditRole"
asp-route-id="@role.Id" class="btn btn-primary">
Edit
</a>
asp-route-id tag helper includes the Role ID in the URL
/Administration/EditRole/7360350f-2662-4842-8a78-58a308043477
Edit Role View
We want the Edit Role View to be as shown below.
- Role ID is non-editable, so keep the input element disabled
- Only Role Name is editable
- Display the list of Users in the Role
The following EditRoleViewModel class carries the data EditRole view needs. Users property holds the list of Users in this role. The constructor initializes Users property so we do not get NULL reference exceptions.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EmployeeManagement.ViewModels
{
public class EditRoleViewModel
{
public EditRoleViewModel()
{
Users = new List<string>();
}
public string Id { get; set; }
[Required(ErrorMessage = "Role Name is required")]
public string RoleName
{ get; set; }
public List<string>
Users { get; set; }
}
}
Edit Role Action Methods
// Role
ID is passed from the URL to the action
[HttpGet]
public async
Task<IActionResult> EditRole(string id)
{
// Find the
role by Role ID
var role = await
roleManager.FindByIdAsync(id);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {id} cannot be found";
return View("NotFound");
}
var model = new
EditRoleViewModel
{
Id = role.Id,
RoleName = role.Name
};
// Retrieve all
the Users
foreach (var user in
userManager.Users)
{
// If the user
is in this role, add the username to
// Users
property of EditRoleViewModel. This model
// object is
then passed to the view for display
if (await
userManager.IsInRoleAsync(user, role.Name))
{
model.Users.Add(user.UserName);
}
}
return View(model);
}
// This
action responds to HttpPost and receives EditRoleViewModel
[HttpPost]
public async Task<IActionResult>
EditRole(EditRoleViewModel model)
{
var role = await
roleManager.FindByIdAsync(model.Id);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {model.Id} cannot be found";
return View("NotFound");
}
else
{
role.Name = model.RoleName;
// Update the
Role using UpdateAsync
var result = await
roleManager.UpdateAsync(role);
if (result.Succeeded)
{
return RedirectToAction("ListRoles");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View(model);
}
}
Edit Role View
@model
EditRoleViewModel
@{
ViewBag.Title = "Edit Role";
}
<h1>Edit Role</h1>
<form method="post" class="mt-3">
<div class="form-group row">
<label asp-for="Id" class="col-sm-2
col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Id" disabled class="form-control">
</div>
</div>
<div class="form-group row">
<label asp-for="RoleName" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="RoleName" class="form-control">
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Update</button>
<a asp-action="ListRoles" class="btn btn-primary">Cancel</a>
</div>
</div>
<div class="card">
<div class="card-header">
<h3>Users in
this role</h3>
</div>
<div class="card-body">
@if (Model.Users.Any())
{
foreach (var user in Model.Users)
{
<h5 class="card-title">@user</h5>
}
}
else
{
<h5 class="card-title">None at the
moment</h5>
}
</div>
<div class="card-footer">
<a href="#" class="btn btn-primary" style="width:auto">Add Users</a>
<a href="#" class="btn btn-primary" style="width:auto">Remove Users</a>
</div>
</div>
</form>
/label asp-for="Id" class="col-sm-2 col-form-label"///label/
ReplyDelete/div class="col-sm-10"/
/input asp-for="Id" disabled class="form-control" //
/input hidden asp-for="Id" //
//div/
When using Core 3.0 I get an exception When I run EditRole(String Id) (video Number 80).
ReplyDeleteThis is the line that throws exception
if (await userManager.IsInRoleAsync(user, role.Name))
InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first
If any one has a fix, please leave a response.
Here is the whole method:
// Role ID is passed from the URL to the action
[HttpGet]
public async Task EditRole(string id)
{
// Find the role by Role ID
var role = await roleManager.FindByIdAsync(id);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {id} cannot be found";
return View("NotFound");
}
var model = new EditRoleViewModel
{
Id = role.Id,
RoleName = role.Name
};
// Retrieve all the Users
foreach (var user in userManager.Users)
{
// If the user is in this role, add the username to
// Users property of EditRoleViewModel. This model
// object is then passed to the view for display
if (await userManager.IsInRoleAsync(user, role.Name))
{
model.Users.Add(user.UserName);
}
}
return View(model);
}
In Core 3.0 , I finally found what to do:
Deletechange userManager.Users to userManager.Users.ToList().
userManager.Users used to work on 2.2
Thanks, now it work (userManager.Users.ToList())
DeleteThanks for bring this question up, I had exactly the same issue, fixed by adding .ToList()
DeleteOR
Deleteyou can add below option to connection string:
MultipleActiveResultSets=true;
MultipleActiveResultSets=true; is better solution.
Deleteand it worked for me.
Thanks ,I Had the Same Issue ,fixed by Adding ToList()
DeleteI am using .Net Core 3.1. Adding ToList() solved the error for me.
Deleteforeach (var user in userManager.Users.ToList())
I reckon MultipleActiveResultSets=true; and .ToList() are both better to apply the applications, first one enables the multiple DataReader, second one makes the IQueryable object to IEnumable object which is a good practice, IMHO, thanks for your sharing!
DeleteError:
ReplyDelete{
"resource": "/c:/Websites/EmployeeManagement/Controllers/EditRoleViewModel.cs",
"owner": "msCompile",
"code": "CS0103",
"severity": 8,
"message": "The name 'userManager' does not exist in the current context [C:\\Websites\\EmployeeManagement\\EmployeeManagement.csproj]",
"startLineNumber": 68,
"startColumn": 34,
"endLineNumber": 68,
"endColumn": 34
}
An unhandled exception occurred while processing the request.
ReplyDeleteNullReferenceException: Object reference not set to an instance of an object.
EpaMgt.Controllers.AdministrationController.EditRole(string id) in AdministrationController.cs, line 70
EpaMgt.Controllers.AdministrationController.EditRole(string id) in AdministrationController.cs
+
foreach (var user in userManager.Users)
anyone?
How do you display both User's name and email at the same time ?
ReplyDeleteI'd added model.Names.Add(user.Name). it worked actually ...
However, I need them to display in a single line ..
how do I do it ?
When I click edit button, this error message found.
ReplyDeleteAn unhandled exception occurred while processing the request.
InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
Microsoft.Data.SqlClient.SqlCommand+<>c.b__164_0(Task result)
Stack Query Cookies Headers Routing
InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
Microsoft.Data.SqlClient.SqlCommand+<>c.b__164_0(Task result)
System.Threading.Tasks.ContinuationResultTaskFromResultTask.InnerInvoke()
System.Threading.Tasks.Task+<>c.<.cctor>b__274_0(object obj)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, object state)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, object state)
System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot, Thread threadPoolThread)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable+AsyncEnumerator.InitializeReaderAsync(DbContext _, bool result, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync(TState state, Func> operation, Func>> verifySucceeded, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable+AsyncEnumerator.MoveNextAsync()
System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()
Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync(IAsyncEnumerable asyncEnumerable, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync(IAsyncEnumerable asyncEnumerable, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore.IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.UserManager.IsInRoleAsync(TUser user, string role)
EmployeeManagement.Controllers.AdminController.EditRole(string id) in AdminController.cs
+
if (await userManager.IsInRoleAsync(user, role.Name))
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()
Add MultipleActiveResultSets=true to the provider part of your connection string (where Data Source, Initial Catalog, etc. are specified).
Deletelike here in my example in the file appsettings.json
"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
you forget to add the action name and controller name for Update button
ReplyDeleteThis comment has been removed by the author.
ReplyDeletewhy used public EditRoleViewModel()
ReplyDelete{
Users = new List();
}
// The constructor initializes Users property so we do not get NULL reference exceptions. try to run your project without add this part. you can see that null reference exception.
DeleteI have tried all these solutions but still, i get this error
ReplyDeleteSystem.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=EmployeeManagement
StackTrace:
at EmployeeManagement.Controllers.AdministrationController.d__6.MoveNext() in C:\Projects\EmployeeManagement\Controllers\AdministrationController.cs:line 79
when i click on update button the not found page execute although role != null why this happen
ReplyDelete