I'm currently struggling creating my first Blazor project that is supposed to be a small CRUD application. I tried to follow some tutorials but most are outdated pre-relase tutorials and there are many differences that confuse me.
my problem is that I don't yet understand some of the basic concepts (especially the 'services'). When i start the app, I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Temporary local of type 'UserManagement.Models.Users[]> was null.
The error occurs at the line "@foreach (var user in users)" in the Index.razor. I would understand that there was no data retrieved. However, There is data in my Users table. So i really don't know that the error could be here.
What we have so far is:
Index.razor
@page "/"
@using Models
@using Data
@inject UserService us
<form method="post">
<input asp-page="/Create" type="button" value="Neuen Benutzer erstellen" />
</form>
<form method="post">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>UserID</th>
<th>Name</th>
<th>Supervisor</th>
<th>Ersteller</th>
<th>Erstelldatum</th>
<th>Optionen</th>
</tr>
</thead>
<tbody>
@foreach (var user in users)
{
<tr>
<td>@user.PkId</td>
<td>@user.UserId</td>
<td>@user.FirstName @user.LastName</td>
<td>@user.Supervisor</td>
<td>@user.CreationUser</td>
<td>@user.CreationDate</td>
<td>
<a>Delete Account</a><br />
<a asp-page="/Edit"> Edit Account</a>
</td>
</tr>
}
</tbody>
</table>
</form>
@code {
Users[] users;
protected override async Task OnInitializedAsync()
{
users = await us.GetUsersAsync();
}
}
}
UserService.cs
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using UserManagement.Models;
namespace UserManagement.Data
{
public class UserService
{
private static UserManagementContext _context;
public UserService (UserManagementContext context)
{
_context = context;
}
public async Task<Users[]> GetUsersAsync()
{
Users[] u;
u = await _context.Users.ToArrayAsync();
return u;
}
}
}
The model: Users.cs
using System;
using System.Collections.Generic;
namespace UserManagement.Models
{
public partial class Users
{
public int PkId { get; set; }
public int FkJobtitle { get; set; }
public int FkCostcenter { get; set; }
public int? FkLocation { get; set; }
public int? FkDepartment { get; set; }
public int? FkWorkplace { get; set; }
public int? FkLanguage { get; set; }
public string UserId { get; set; }
public string Salutation { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PersonalId { get; set; }
public string Supervisor { get; set; }
public string Telephone { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime CreationDate { get; set; }
public string CreationUser { get; set; }
public DateTime? ModificationDate { get; set; }
public string ModificationUser { get; set; }
public virtual CostCenter FkCostcenterNavigation { get; set; }
public virtual Department FkDepartmentNavigation { get; set; }
public virtual Jobtitle FkJobtitleNavigation { get; set; }
public virtual Language FkLanguageNavigation { get; set; }
public virtual Location FkLocationNavigation { get; set; }
}
}
And of course a scaffolded DbContext (excerpt):
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace UserManagement.Models
{
public partial class UserManagementContext : DbContext
{
public UserManagementContext()
{
}
public UserManagementContext(DbContextOptions<UserManagementContext> options)
: base(options)
{
}
public virtual DbSet<Approver> Approver { get; set; }
public virtual DbSet<Branche> Branche { get; set; }
public virtual DbSet<CostCenter> CostCenter { get; set; }
public virtual DbSet<DealerCompany> DealerCompany { get; set; }
public virtual DbSet<Department> Department { get; set; }
public virtual DbSet<Jobtitle> Jobtitle { get; set; }
public virtual DbSet<Language> Language { get; set; }
public virtual DbSet<Location> Location { get; set; }
public virtual DbSet<Request> Request { get; set; }
public virtual DbSet<RequestTypes> RequestTypes { get; set; }
public virtual DbSet<SystemRole> SystemRole { get; set; }
public virtual DbSet<SystemType> SystemType { get; set; }
public virtual DbSet<Systems> Systems { get; set; }
public virtual DbSet<Users> Users { get; set; }
public virtual DbSet<Workplace> Workplace { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
.....
In my startup, I had to load the UserService by using services.AddTransient instead of AddSingleton, because the latter would run into following error:
System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: UserManagement.Data.UserService Lifetime: Singleton ImplementationType: UserManagement.Data.UserService': Unable to resolve service for type 'UserManagement.Models.UserManagementContext' while attempting to activate 'UserManagement.Data.UserService'.)'
when a component gets rendered it tries to create the view before the OnInitializedAsync() is executed.
It gives you null ref exc because it tries to render the page and the for each calls the NextItem() of the iterator of the array but the array is null.
Solution in index.razor initialize the array in ctor or change the declaration to:
Users[] users = new Users[x]; Where x is the number of elements you want to store in the list.
For a flexible solution I recommend List instead of an array.
List<User> users = new List<User>();
The problem is in the below code line :
u = await _context.Users.ToArrayAsync();
When you use await in the above code , the method GetUsersAsync is suspended until the awaited task is complete ,then the method OnInitializedAsync will also be suspended .So the Users array is null when a component gets rendered
Change the above code to
u = _context.Users.ToArray();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With