Hi Folks I have a brainfart moment, I have been struggling for this for last week, and I think this is the time to ask for your opinion. So what I am trying to achieve here is to insert the record in AspNetUserRoles, but somehow I am getting an error saying UserId is null.
NOTE: I am able to store user in ASpNetUser, AspNetRole. So that means IdentityDbContext might not needed.
so this is the point where i am getting error
await multiTierDbContext1.AspNetUserRoles.AddAsync(userRole);
The error is shown below in screenshot I attached the screenshot below. Please help me to achieve this.
the code for Register a User
[HttpPost("register")]
public async Task<IActionResult> Register(UserRequest user)
{
//var userName= userManager.FindByNameAsync("[email protected]").Result;
if (ModelState.IsValid)
{
var users = new AspNetUser {Id= Guid.NewGuid().ToString(), Email =user.Email , UserName = user.Username, ConcurrencyStamp = Guid.NewGuid().ToString(), LockoutEnabled=false, NormalizedEmail =user.Email, NormalizedUserName =user.Username,Discriminator="abc"};
var result = await userManager.CreateAsync(users, user.Password);
if(!result.Succeeded)
{
return BadRequest(result);
}
if(user.Roles.Any())
{
foreach(var role in user.Roles)
{
var roleExist = _provider.GetService<IRoleStore<AspNetRole>>();
var resultRow = new AspNetRole()
{
Name = role
};
/*var resultS = await roleExist.CreateAsync(res, CancellationToken.None);*/
var roleExists = await roleManager.RoleExistsAsync("Admin");
if(!roleExists)
{
resultRow.Id= Guid.NewGuid().ToString();
resultRow.NormalizedName = role.ToUpper();
var roleResult = await roleExist.CreateAsync(resultRow, CancellationToken.None);
}
var userRequest = new AspNetUser()
{
UserName = user.Username,
};
var userss= await userManager.FindByNameAsync(user.Username);
var response=await roleExist.FindByNameAsync("Admin", CancellationToken.None);
if(userss.Id!=null! && response!=null)
{
var userRole = new AspNetUserRole()
{
UserId =userss.Id,
RoleId = response.Id,
};
await multiTierDbContext1.AspNetUserRoles.AddAsync(userRole);
multiTierDbContext1.SaveChanges();
}
//var userToRole = await userManager.AddToRoleAsync(userss, "ADMIN");
/* var userRole = await userManager.IsInRoleAsync(userss, role);
if (!userRole)
{
var userToRole = await userManager.AddToRoleAsync(userss, "Admin");
}*/
}
}
/* var ApplicationUsers = new ApplicationUser { Email = user.Email, UserName = user.UserName };
multiTierDbContext.ApplicationUsers.Add(ApplicationUsers);
multiTierDbContext.SaveChanges();*/
return Ok(result);
}
return Ok();
}
The Db context
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserRole<string>>()
.ToTable("AspNetUserRoles");
modelBuilder.Entity<IdentityUserRole<string>>()
.HasKey(ur => new { ur.UserId, ur.RoleId });
modelBuilder.Entity<AspNetUser>()
.HasMany(u => u.Roles)
.WithMany(r => r.Users)
.UsingEntity<IdentityUserRole<string>>(
ur => ur.HasOne<AspNetRole>().WithMany().HasForeignKey(ur => ur.RoleId).IsRequired(),
ur => ur.HasOne<AspNetUser>().WithMany().HasForeignKey(ur => ur.UserId).IsRequired() );
modelBuilder.Entity<AspNetRole>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_dbo.AspNetRoles");
entity.Property(e => e.Id).HasMaxLength(128);
});
modelBuilder.Entity<AspNetUser>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_dbo.AspNetUsers");
entity.Property(e => e.Id).HasMaxLength(128);
entity.Property(e => e.Discriminator).HasMaxLength(128);
entity.HasMany(d => d.Roles).WithMany(p => p.Users)
.UsingEntity<Dictionary<string, object>>(
"AspNetUserRole",
r => r.HasOne<AspNetRole>().WithMany().HasForeignKey("RoleId"),
l => l.HasOne<AspNetUser>().WithMany().HasForeignKey("UserId"),
j =>
{
j.HasKey("UserId", "RoleId");
j.HasIndex(new[] { "RoleId" }, "IX_AspNetUserRoles_RoleId");
});
});
modelBuilder.Entity<AspNetUserClaim>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_dbo.AspNetUserClaims");
entity.HasIndex(e => e.UserId, "IX_User_Id");
entity.Property(e => e.UserId)
.HasMaxLength(128)
.HasColumnName("User_Id");
entity.HasOne(d => d.User).WithMany(p => p.AspNetUserClaims)
.HasForeignKey(d => d.UserId)
.HasConstraintName("FK_dbo.AspNetUserClaims_dbo.AspNetUsers_User_Id");
});
modelBuilder.Entity<AspNetUserLogin>(entity =>
{
entity.HasKey(e => new { e.UserId, e.LoginProvider, e.ProviderKey }).HasName("PK_dbo.AspNetUserLogins");
entity.HasIndex(e => e.UserId, "IX_UserId");
entity.Property(e => e.UserId).HasMaxLength(128);
entity.Property(e => e.LoginProvider).HasMaxLength(128);
entity.Property(e => e.ProviderKey).HasMaxLength(128);
entity.HasOne(d => d.User).WithMany(p => p.AspNetUserLogins)
.HasForeignKey(d => d.UserId)
.HasConstraintName("FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId");
});
modelBuilder.Entity<MigrationHistory>(entity =>
{
entity.HasKey(e => new { e.MigrationId, e.ContextKey }).HasName("PK_dbo.__MigrationHistory");
entity.ToTable("__MigrationHistory");
entity.Property(e => e.MigrationId).HasMaxLength(150);
entity.Property(e => e.ContextKey).HasMaxLength(300);
entity.Property(e => e.ProductVersion).HasMaxLength(32);
});
OnModelCreatingPartial(modelBuilder);
}
these are extended classes created under same
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApi.Database.Models;
/* [Table("AspNetUsers")]*/
public partial class AspNetUser : IdentityUser
{
public ICollection<AspNetUserRole> UserRoles { get; set; }
}
using Microsoft.AspNetCore.Identity;
namespace WebApi.Database.Models;
public partial class AspNetUserRole : IdentityUserRole<string>
{
public override string RoleId { get; set; }
public override string UserId { get; set; }
public AspNetUser User { get; set; }
public AspNetRole Role { get; set; }
}
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApi.Database.Models;
/* [Table("AspNetRoles")]*/
public partial class AspNetRole : IdentityRole
{
public ICollection<AspNetUserRole> UserRoles { get; set; }
}
I tried different ways to achieve this, I used userManager.AddToRoles()
method but it is also throwing the same error then i tried to achieve this using direct saving the entries in the table, its showing the same error, I tried to use the Partial classes of same name and including the same namespace of Models original folder created by scaffold-database command, the reason why I selected partial classes of same name because I don’t want to make any change in original entity classesenter image description here
The error
System.InvalidOperationException: Unable to track an entity of type 'AspNetUserRole' because its primary key property 'UserId' is null.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NullableKeyIdentityMap`1.Add(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityStateAsync(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, Nullable`1 fallbackState, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintActionAsync(EntityEntryGraphNode`1 node, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraphAsync[TState](EntityEntryGraphNode`1 node, Func`3 handleNode, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraphAsync(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.AddAsync(TEntity entity, CancellationToken cancellationToken)
at WebApi.Controllers.PersonController.Register(UserRequest user)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
just check the if condition which might be wrong syntax might causing error.
if(userss.Id!=null! && response!=null)