I have a view for changing the role of a user on an admin page. I pass the userId to get the user information like the name. Users can be admins, employees, customers, or a company. There are three different kinds of companies a user can be if they are a company.
I have a view model for this webpage called RoleManagement.cshtml:
@model RoleManagementVM
<div class="card shadow border-0 mt-4">
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h2 class="text-white py-2"> Manage User Role</h2>
</div>
</div>
</div>
<div class="card-body p-4">
<form method="post" class="row">
<input asp-formaction="ApplicationUser.Id" hidden />
@Model.ApplicationUser.Id
<div class="border p-3 ">
<div class="form-floating py-2 col-12">
<input asp-for="ApplicationUser.Name" readonly class="form-control border-0 shadow" />
<label asp-for="ApplicationUser.Name" class="ms-2"></label>
</div>
<div class="form-floating py-2 col-12">
<select asp-for="ApplicationUser.Role" asp-items="@Model.RolesList" class="form-select"></select>
</div>
@{
var companyVisible = "display:none;";
}
@if (Model.ApplicationUser.Role == SD.Role_Company)
{
companyVisible = "display:block;";
}
<div class="form-floating py-2 col-12">
<select asp-for="ApplicationUser.CompanyId" style="@companyVisible" asp-items="@Model.CompanyList" class="form-select"></select>
</div>
<div class="row pt-2">
<div class="col-6 col-md-3">
<button type="submit" class="btn btn-primary form-control">Update Role</button>
</div>
<div class="col-6 col-md-3">
<a asp-action="Index" class="btn btn-primary border form-control">
Back to List
</a>
</div>
</div>
</div>
</form>
</div>
</div>
@section Scripts {
@{
<partial name="_ValidationScriptsPartial" />
}
<script>
$(document).ready(function () {
$('#ApplicationUser_Role').change(function () {
var selection = $('#ApplicationUser_Role Option:Selected').text();
if (selection == 'Company') {
$('#ApplicationUser_CompanyId').show();
} else {
$('#ApplicationUser_CompanyId').hide();
}
})
})
</script>
}
My controller for this webpage is called UserController.cs. Here is the code:
using Ecommerce.DataAccess.Repository.IRepository;
using Ecommerce.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Ecommerce.Models.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Ecommerce.Utility;
using Ecommerce.DataAccess.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
namespace Ecommerce.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize(Roles =SD.Role_Admin)]
public class UserController : Controller
{
private readonly ApplicationDbContext _db;
private readonly UserManager<IdentityUser> _userManager;
public UserController(ApplicationDbContext db, UserManager<IdentityUser> userManager)
{
_db = db;
_userManager = userManager;
}
public IActionResult Index()
{
return View();
}
public IActionResult RoleManagment(string userId)
{
string RoleId = _db.UserRoles.FirstOrDefault(u=>u.UserId == userId).RoleId;
RoleManagementVM RoleVM = new RoleManagementVM()
{
ApplicationUser = _db.ApplicationUsers.Include(u => u.Company).FirstOrDefault(u => u.Id == userId),
RolesList = _db.Roles.Select(i => new SelectListItem
{
Text = i.Name,
Value = i.Name
}),
CompanyList = _db.Company.Select(i => new SelectListItem {
Text = i.Name,
Value = i.Id.ToString()
}),
};
RoleVM.ApplicationUser.Role = _db.Roles.FirstOrDefault(u => u.Id == RoleId).Name;
return View(RoleVM);
}
[HttpPost]
public IActionResult RoleManagment(RoleManagementVM roleManagementVM)
{
string RoleId = _db.UserRoles.FirstOrDefault(u => u.UserId == roleManagementVM.ApplicationUser.Id).RoleId;
string oldRole = _db.Roles.FirstOrDefault(u => u.Id == RoleId).Name;
if(!(roleManagementVM.ApplicationUser.Role == oldRole))
{
ApplicationUser applicationUser = _db.ApplicationUsers.FirstOrDefault(u => u.Id == roleManagementVM.ApplicationUser.Id);
if(roleManagementVM.ApplicationUser.Role == SD.Role_Company)
{
applicationUser.CompanyId = roleManagementVM.ApplicationUser.CompanyId;
}
if (oldRole == SD.Role_Company)
{
applicationUser.CompanyId = null;
}
_db.SaveChanges();
_userManager.RemoveFromRoleAsync(applicationUser, oldRole).GetAwaiter().GetResult();
_userManager.AddToRoleAsync(applicationUser, roleManagementVM.ApplicationUser.Role).GetAwaiter().GetResult();
}
return RedirectToAction("Index");
}
//[HttpPost, ActionName("Delete")]
//public IActionResult DeletePOST(int? id)
//{
// Company obj = _db.ApplicationUsers.Include(u=>u.Company).ToList();
// if (obj == null)
// {
// return NotFound();
// }
// _unitOfWork.Company.Remove(obj);
// _unitOfWork.Save();
// TempData["success"] = "Company deleted successfully";
// return RedirectToAction("Index");
//}
#region API CALLS
[HttpGet]
public IActionResult GetAll()
{
List<ApplicationUser> obj = _db.ApplicationUsers.Include(u => u.Company).ToList();
var userRoles = _db.UserRoles.ToList();
var roles = _db.Roles.ToList();
foreach(var user in obj)
{
var roleId = userRoles.FirstOrDefault(u => u.UserId == user.Id).RoleId;
user.Role = roles.FirstOrDefault(u => u.Id == roleId).Name;
if (user.Company == null)
{
user.Company = new() { Name = "" };
}
}
return Json(new { data = obj });
}
[HttpPost]
public IActionResult LockUnlock([FromBody] string id)
{
var objFromDb = _db.ApplicationUsers.FirstOrDefault(u => u.Id == id);
if (objFromDb == null)
{
return Json(new { success = false, message = "Error while Locking" });
}
if (objFromDb.LockoutEnd !=null && objFromDb.LockoutEnd > DateTime.Now)
{
objFromDb.LockoutEnd = DateTime.Now;
}
else
{
objFromDb.LockoutEnd = DateTime.Now.AddDays(30);
}
_db.SaveChanges();
return Json(new { success = true, message = "Operation successful" });
}
#endregion
}
}
When I try to change the role of a user, for example from company to employee, I get a an the following exception: Object reference not set to an instance of an object
. This is due to the Id of the user being incorrect. In the view, you will notice that I am displaying the UserId. The correct userId is being displayed. When I debug to check the UserId being passed from the RoleManagementVM to the post action controller method, I get a completely different Id field (its not even in my db).
I am using ASP.NET 8. here is my project file:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ecommerce.DataAccess\Ecommerce.DataAccess.csproj" />
<ProjectReference Include="..\Ecommerce.Models\Ecommerce.Models.csproj" />
<ProjectReference Include="..\Ecommerce.Utility\Ecommerce.Utility.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\images\product\" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Areas\Customer\Views\Home\Details.cshtml" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Areas\Customer\Views\Home\Details.cshtml" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.2.23480.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
<PackageReference Include="Stripe.net" Version="43.4.0" />
</ItemGroup>
</Project>
I'm not sure if I'm doing something wrong or if there is a bug that is beyond what I can fix.
Try to change:
<input asp-formaction="ApplicationUser.Id" hidden />
into:
<input asp-for="ApplicationUser.Id" hidden />