我对 ASP.NET Core 相当陌生。我正在开发一个简单的社交媒体网络应用程序,并决定将身份添加到我现有的用户中。我在登录用户时遇到问题。登录和注册方法都会出现此问题。在
Register
方法中,用户实际上被添加到数据库中。
但是当尝试使用相同的方法登录时,我得到以下信息:
ArgumentNullException: Value cannot be null. (Parameter 'value') System.ArgumentNullException.Throw(string paramName) System.ArgumentNullException.ThrowIfNull(object argument, string paramName) System.Security.Claims.Claim..ctor(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue) System.Security.Claims.Claim..ctor(string type, string value) Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser>.GenerateClaimsAsync(TUser user) Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser, TRole>.GenerateClaimsAsync(TUser user) Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser>.CreateAsync(TUser user) Microsoft.AspNetCore.Identity.SignInManager<TUser>.CreateUserPrincipalAsync(TUser user) Microsoft.AspNetCore.Identity.SignInManager<TUser>.SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable<Claim> additionalClaims) Microsoft.AspNetCore.Identity.SignInManager<TUser>.SignInOrTwoFactorAsync(TUser user, bool isPersistent, string loginProvider, bool bypassTwoFactor) Microsoft.AspNetCore.Identity.SignInManager<TUser>.PasswordSignInAsync(TUser user, string password, bool isPersistent, bool lockoutOnFailure) Microsoft.AspNetCore.Identity.SignInManager<TUser>.PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure) ImagiArtInfrastructure.Controllers.AccountController.Login(LoginViewModel model) in AccountController.cs
我的应用程序已经有
User
模型类,因此我将缺少的表添加到数据库中。
我当前的
User
模型,继承自IdentityUser
:
using Microsoft.AspNetCore.Identity;
namespace ImagiArtInfrastructure;
public partial class User : IdentityUser<int>
{
public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
public virtual ICollection<Like> Likes { get; set; } = new List<Like>();
public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
public virtual ICollection<UserFollower> UserFollowerFollowers { get; set; } = new List<UserFollower>();
public virtual ICollection<UserFollower> UserFollowerUsers { get; set; } = new List<UserFollower>();
}
注册及登录方法:
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
User user = new User
{
Email = model.Email,
UserName = model.Email
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// cookies
// This line causes the exception
await _signInManager.SignInAsync(user, false);
return RedirectToAction("Index", "Home");
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
return View(model);
}
[HttpGet]
public IActionResult Login(string? returnUrl = null)
{
returnUrl ??= "/";
return View(new LoginViewModel { ReturnUrl = returnUrl });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
// This line causes the exception too
var result =
await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, false);
if (result.Succeeded)
{
if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid login credentials");
}
}
return View(model);
}
Program.cs
using ImagiArtInfrastructure;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<CloneContext>(option => option.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
// Adding Identity
builder.Services.AddIdentity<User, IdentityRole<int>>().AddEntityFrameworkStores<CloneContext>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
数据库上下文:
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace ImagiArtInfrastructure;
public partial class CloneContext : IdentityDbContext<User, IdentityRole<int>, int>
{
public CloneContext()
{
}
public CloneContext(DbContextOptions<CloneContext> options)
: base(options)
{
Database.EnsureCreated();
}
public virtual DbSet<Comment> Comments { get; set; }
public virtual DbSet<Like> Likes { get; set; }
public virtual DbSet<Post> Posts { get; set; }
public virtual DbSet<UserFollower> UserFollowers { get; set; }
// Warning CS0114 'CloneContext.Users' hides inherited member 'IdentityUserContext<User, int, IdentityUserClaim<int>, IdentityUserLogin<int>, IdentityUserToken<int>>.Users'.
// if Users is uncommented
//public virtual DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer("Server=DESKTOP-6SAKF27\\SQLEXPRESS; Database=Clone; Trusted_Connection=True; TrustServerCertificate=True; ");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Comment>(entity =>
{
entity.HasKey(e => e.CommentId).HasName("PK__Comments__E7957687FE981422");
entity.Property(e => e.Caption)
.HasMaxLength(64)
.HasColumnName("caption");
entity.Property(e => e.PostId).HasColumnName("post_id");
entity.Property(e => e.UserId).HasColumnName("user_id");
entity.HasOne(d => d.Post).WithMany(p => p.Comments)
.HasForeignKey(d => d.PostId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("comments_post_id_foreign");
entity.HasOne(d => d.User).WithMany(p => p.Comments)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Comments_AspNetUsers");
});
modelBuilder.Entity<Like>(entity =>
{
entity.HasKey(e => e.LikeId).HasName("PK__Likes__992C79308223B6DD");
entity.Property(e => e.PostId).HasColumnName("post_id");
entity.Property(e => e.UserId).HasColumnName("user_id");
entity.HasOne(d => d.Post).WithMany(p => p.Likes)
.HasForeignKey(d => d.PostId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("likes_post_id_foreign");
entity.HasOne(d => d.User).WithMany(p => p.Likes)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Likes_AspNetUsers");
});
modelBuilder.Entity<Post>(entity =>
{
entity.HasKey(e => e.PostId).HasName("PK__Posts__3ED78766917B0BC9");
entity.Property(e => e.Caption)
.HasMaxLength(32)
.HasColumnName("caption");
entity.Property(e => e.Description)
.HasMaxLength(64)
.HasColumnName("description");
entity.Property(e => e.ImageUrl)
.HasMaxLength(50)
.IsUnicode(false)
.HasColumnName("image_url");
entity.Property(e => e.UserId).HasColumnName("user_id");
entity.HasOne(d => d.User).WithMany(p => p.Posts)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Posts_AspNetUsers");
});
modelBuilder.Entity<UserFollower>(entity =>
{
entity.HasKey(e => e.UserFollowId).HasName("PK__UserFoll__15A691442B4B1096");
entity.Property(e => e.FollowerId).HasColumnName("follower_id");
entity.Property(e => e.UserId).HasColumnName("user_id");
entity.HasOne(d => d.Follower).WithMany(p => p.UserFollowerFollowers)
.HasForeignKey(d => d.FollowerId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_UserFollowers_AspNetUsers1");
entity.HasOne(d => d.User).WithMany(p => p.UserFollowerUsers)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_UserFollowers_AspNetUsers");
});
modelBuilder.Entity<User>(entity =>
{
entity.Property(e => e.Id).ValueGeneratedNever();
entity.Property(e => e.Email).HasMaxLength(256);
entity.Property(e => e.NormalizedEmail).HasMaxLength(256);
entity.Property(e => e.NormalizedUserName).HasMaxLength(256);
entity.Property(e => e.UserName).HasMaxLength(256);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
我尝试调试以查看到底是什么原因造成的。
SignInManager class Microsoft.AspNetCore.Identity
:
/// <summary>
/// Creates a <see cref="ClaimsPrincipal"/> for the specified <paramref name="user"/>, as an asynchronous operation.
/// </summary>
/// <param name="user">The user to create a <see cref="ClaimsPrincipal"/> for.</param>
/// <returns>The task object representing the asynchronous operation, containing the ClaimsPrincipal for the specified user.</returns>
public virtual async Task<ClaimsPrincipal> CreateUserPrincipalAsync(TUser user) => await ClaimsFactory.CreateAsync(user); // ClaimsFactory.CreateAsync(user) causes the exception
我注意到用户参数在任何地方都正确传递,所以不知道是什么原因造成的。
安全地假设
Id
的 User
属性是主键,您将实例化新的 User
,而无需一个:
User user = new User
{
Email = model.Email,
UserName = model.Email
};
因为不会为该密钥自动生成任何值,并且您也没有在代码中设置值:
modelBuilder.Entity<User>(entity =>
{
entity.Property(e => e.Id).ValueGeneratedNever();
...
});
删除上述配置应该可以解决问题。
更新:另外,请将您的自定义类重命名为例如
ApplicationUser
或 AppUser
。