I have a Hangfire job that tries to create Identity users based on an old database. Unfortunately it results in this error (coming from Hangfire):
Failed to process the job '24': an exception occurred. Retry attempt 6 of 10 will be performed in 00:12:04.
System.NullReferenceException: Object reference not set to an instance of an object.
at userpanel.BatchRegistration.CreateUser(String providedEmail, String providedPassword, String providedTraccarId, Nullable\`1 providedIsAdmin) in C:\Users\Vostro2017\source\repos\userpanel\Jobs.cs:line 83
at userpanel.Jobs.UpdateUsers() in C:\...\userpanel\Jobs.cs:line 40
at userpanel.Jobs.UpdateUsers() in C:\...\userpanel\Jobs.cs:line 42
at userpanel.Jobs.UpdateUsers() in C:\...\userpanel\Jobs.cs:line 42
at userpanel.Jobs.UpdateUsers() in C:\...\userpanel\Jobs.cs:line 44
at System.Runtime.CompilerServices.TaskAwaiter\`1.GetResult()
I expected it to create users instead.
Jobs.cs
:
namespace userpanel {
public class Jobs {
public static async Task<bool> UpdateUsers() {
await using var conn = new NpgsqlConnection("Server=localhost;Port=5432;Database=Old;Username=postgres;Password=123456");
await conn.OpenAsync();
//
// 1. Download old users and create Identity versions
//
await using (var cmd = new NpgsqlCommand("SELECT * FROM public.old_users ORDER BY id;", conn))
await using (var reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
string providedOldId = reader.GetInt32(0).ToString();
string providedEmail = reader.GetString(2);
bool? providedIsAdmin = reader.GetBoolean(6);
string providedPassword = "123456";
await BatchRegistration.CreateUser(providedEmail, providedPassword, providedOldId, providedIsAdmin);
}
}
await conn.CloseAsync();
return true;
}
}
public class BatchRegistration : PageModel {
public static SignInManager<ApplicationUser> _signInManager;
public static UserManager<ApplicationUser> _userManager;
public static ILogger<RegisterModel> _logger;
public BatchRegistration(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger) {
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
public static async Task CreateUser(string providedEmail, string providedPassword, string providedOldId, bool? providedIsAdmin) {
bool IsAdmin = providedIsAdmin.HasValue != false;
var user = new ApplicationUser {
UserName = providedEmail,
Email = providedEmail,
EmailConfirmed = true,
UserOldEmail = providedEmail,
UserOldId = providedOldId,
IsPaymentRequired = true,
IsAdministrator = IsAdmin,
Currency = 0.00
};
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(user)) {
string name = descriptor.Name;
object value = descriptor.GetValue(user);
Console.WriteLine("{0}={1}", name, value);
}
await _userManager.CreateAsync(user, providedPassword);
}
}
}
My model:
public class ApplicationUser : IdentityUser {
public string UserOldId { get; set; } // actually int, wouldn't let me migrate
public string UserOldEmail { get; set; }
public bool IsPaymentRequired { get; set; }
public bool IsAdministrator { get; set; }
public double Currency { get; set; }
public ICollection<UserDevice> Devices { get; } = new List<UserDevice>();
}
I couldn't find a way to create users like this, so I just copied registration form backend and modified it to my needs.
I already tried filling my new ApplicationUser
with IdentityUser
data, but it didn't work.
I also checked if any entry is empty/null - everything seems to be fine.
I do not believe it is similar to this question - I know what this exception means, but I'm completely green to ASP.NET and I assume it's related to binding to UserManager somehow, since all data provided to _userManager.CreateAsync
are valid.
Edit - I add my Hangfire job in Startup.cs
, at the end of Configure
method, like this:
BackgroundJob.Enqueue(() => Jobs.UpdateUsers());
I realized I tried doing this without understanding anything. By jbl's advice I changed my Jobs.cs
into this:
namespace userpanel {
public class Jobs : PageModel {
public UserManager<ApplicationUser> _userManager;
public Jobs(UserManager<ApplicationUser> userManager) {
_userManager = userManager;
}
public async Task<bool> UpdateUsers() {
await using var conn = new NpgsqlConnection("Server=localhost;Port=5432;Database=Old;Username=postgres;Password=123456");
await conn.OpenAsync();
//
// 1. Download old users and create Identity versions
//
await using (var cmd = new NpgsqlCommand("SELECT * FROM public.old_users ORDER BY id;", conn))
await using (var reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
string providedOldId = reader.GetInt32(0).ToString();
string providedEmail = reader.GetString(2);
bool? providedIsAdmin = reader.GetBoolean(6);
string providedPassword = "123456";
await CreateUser(providedEmail, providedPassword, providedOldId, providedIsAdmin);
}
}
await conn.CloseAsync();
return true;
// ...
}
public async Task CreateUser(string providedEmail, string providedPassword, string providedOldId, bool? providedIsAdmin) {
bool IsAdmin = providedIsAdmin.HasValue != false;
var user = new ApplicationUser {
UserName = providedEmail,
Email = providedEmail,
EmailConfirmed = true,
UserOldEmail = providedEmail,
UserOldId = providedOldId,
IsPaymentRequired = true,
IsAdministrator = IsAdmin,
Currency = 0.00
};
await _userManager.CreateAsync(user, providedPassword);
}
}
}
Also my Hangfire job is now executed using this line:
BackgroundJob.Enqueue<Jobs>(j => j.UpdateUsers());