Hello,
I followed the link below and trying to get X.PagedList to work when assigning a role to user(s) via form submit but I couldn't get it to work with the error 'Object reference not set to an instance of an object.' in the view page. I have VS 2019 and using .Net 5.
https://stackoverflow.com/questions/14258212/mvc-posting-ipagedlist
View Model:
public class RoleUsersVM
{
public class RoleUsersViewModel
{
public string UserId { get; set; }
public string UserName { get; set; }
public bool IsSelected { get; set; }
public int? Page { get; set; }
public List<RoleUsersViewModel> Clients { get; set; }
public IPagedList PagingMetaData { get; set; }
}
}
Controller code:
[HttpGet]
public async Task<IActionResult> AssignRoleToUsers(int? page, string id)
{
int pageNumber = page ?? 1; // if no page is specified, default to the first page (1)
int pageSize = 3; // Get 3 for each requested page.
var role = await _roleManager.FindByIdAsync(id);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {id} cannot be found";
return View("~/Views/Shared/NotFound.cshtml");
}
ViewBag.roleId = role.Id;
ViewBag.roleName = role.Name;
RoleUsersViewModel pModel = new();
IList<RoleUsersViewModel> model = new List<RoleUsersViewModel>();
IQueryable<ApplicationUser> users = _userManager.Users.OrderBy(l => l.LastName);
int totalCount = users.Count();
var getUsers = users.Select(u => new { u.Id, u.FirstName, u.LastName }).Skip(pageSize * pageNumber).Take(pageSize).ToList();
for (int i = 0; i < getUsers.Count; i++) //.AsParallel().WithExecutionMode(ParallelExecutionMode.Default)
{
var roleUsersViewModel = new RoleUsersViewModel
{
UserId = getUsers[i].Id,
UserName = getUsers[i].FirstName + " " + getUsers[i].LastName
};
bool isInthisRole = GetUserRole(getUsers[i].Id, role.Id);
if (isInthisRole) //(await _userManager.IsInRoleAsync(user, role.Name))
{
roleUsersViewModel.IsSelected = true;
}
else
{
roleUsersViewModel.IsSelected = false;
}
model.Add(roleUsersViewModel);
}
pModel.Clients = (List<RoleUsersViewModel>)model;
IPagedList pMd = pModel.PagingMetaData;
pMd = new StaticPagedList<RoleUsersViewModel>(pModel.Clients, pageNumber, pageSize, totalCount);
return View("~/Areas/SiteAdmin/Views/RoleAdmin/AssignRoleToUsers.cshtml", pMd);
}
[HttpPost]
public async Task<IActionResult> AssignRoleToUsers(string roleId, IEnumerable<RoleUsersViewModel> model)
{
var role = await _roleManager.FindByIdAsync(roleId);
if (role == null)
{
ViewBag.ErrorMessage = $"Role with Id = {roleId} cannot be found";
return View("~/Views/Shared/NotFound.cshtml");
}
foreach (var user in await _userManager.GetUsersInRoleAsync(role.Name))
{
var remResult = await _userManager.RemoveFromRoleAsync(user, role.Name);
if (!remResult.Succeeded)
{
ModelState.AddModelError("", $"Cannot remove user '{user.FirstName + " " + user.LastName}' from existing role {role.Name}");
return View("~/Areas/SiteAdmin/Views/RoleAdmin/AssignRoleToUsers.cshtml", model);
}
}
var users = await _userManager.Users.OrderBy(l => l.LastName).ToListAsync();
foreach (var user in users)
{
if (model.Where(x => x.IsSelected && x.UserId == user.Id).Any())
{
var addResult = await _userManager.AddToRoleAsync(user, role.Name);
if (!addResult.Succeeded)
{
ModelState.AddModelError("", "Cannot add selected users to role");
return View("~/Areas/SiteAdmin/Views/RoleAdmin/AssignRoleToUsers.cshtml", model);
}
}
}
return RedirectToAction("ListRoles");
}
View:
using X.PagedList.Mvc.Core; <!--import to get HTML Helper-->
@using X.PagedList;
@using myAppCore.Areas.SiteAdmin.Models;
@model IPagedList<RoleUsersVM.RoleUsersViewModel>
@{
ViewBag.Title = "Grant Users";
var roleId = ViewBag.roleId;
var roleName = ViewBag.roleName;
}
<div class="container-fluid">
<br />
<h3 class="text-left colorTitle">@ViewBag.Title</h3><hr /><br />
<div class="row">
<div class="w-50 mx-auto">
<form method="post">
<div class="card">
<div class="card-header text-center">
<h4>Grant users with role: <b>@roleName</b></h4>
</div>
<table class="table" border="1">
<tbody>
@foreach (var user in Model)
{
<tr>
<td>
<div class="card-body">
<div class="mx-auto col-2">
<div class="form-check m-3 text-nowrap">
<input type="hidden" asp-for="@user.UserId" />
<input type="hidden" asp-for="@user.UserName" />
<input asp-for="@user.IsSelected" class="form-check-input" />
<label class="form-check-label" asp-for="@user.IsSelected">
<b>@user.UserName</b>
</label>
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
</div>
</td>
</tr>
}
</tbody>
</table>
<div class="row">
<div class="mx-auto float-right">
<!-- paging control for navigation to the previous page, next page, etc -->
@Html.PagedListPager(new StaticPagedList<RoleUsersVM.RoleUsersViewModel>((IEnumerable<RoleUsersVM.RoleUsersViewModel>)Model[0].Clients, (IPagedList)Model[0].PagingMetaData), page => Url.Action("AssignRoleToUsers", new { page = page, id = @roleId }),
new X.PagedList.Web.Common.PagedListRenderOptions
{
DisplayItemSliceAndTotal = true,
ContainerDivClasses = new[] { "navigation" },
LiElementClasses = new[] { "page-item" },
PageClasses = new[] { "page-link" }
})
</div>
</div><br />
<div class="card-footer">
<div class="float-right btn-group">
<input type="submit" value="Grant" asp-route-roleId="@roleId" class="btn btn-warning rounded" />
<a asp-action="ListRoles" class="btn btn-primary rounded ml-2">Cancel</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
@section Scripts{
<script>
$(document).ready(function () {
$('ul.pagination > li.disabled > a').addClass('page-link');
});
</script>
}
The view does receive the viewmodel data via HTTPGET; when I use VS debugger to examine the Model, I can see that it has 3 rows of users. However, I am getting the error 'Object reference not set to an instance of an object.' in the view page. I think the reason I get that error is because both Model[0].Clients and Model[0].PagingMetaData are null. I did check the controller code and it showed that both pModel.Clients and pModel.PagingMetaData do have user rows in them but in the view page, they are null.
Any ideas on how I can fix this null error?
Note: My main objective of this task is to have the viewmodel transfer rows of users with the assigned role upon a form submit (httppost) but I am not certain if I am using the right approach or not. The link at the top is for the old version of PagedList.
Thank you in advance.

