用户收藏商品功能触发500错误:System.FormatException问题求助
电商收藏功能500错误排查与修复方案
一、核心异常根源:Claim转换不安全
你遇到的System.FormatException直接出在GetUserId方法里,问题在于直接用int.Parse处理可能为null或非数字的Claim值:
- 当
user.FindFirst(ClaimTypes.NameIdentifier)返回null(比如身份验证Token未正确携带该Claim,或Claim名称不匹配),?.Value会是null,int.Parse(null)直接抛出格式异常。 - 即使Claim存在,若值不是合法整数,也会触发同样异常。
修复ClaimPrincipleExtensions类
把GetUserId改成安全转换逻辑,避免直接抛出异常,同时返回可空类型方便后续校验:
public static class ClaimPrincipleExtensions { public static string GetUsername(this ClaimsPrincipal user) { return user.FindFirst(ClaimTypes.Name)?.Value; } public static int? GetUserId(this ClaimsPrincipal user) { var idStr = user.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (int.TryParse(idStr, out int userId)) { return userId; } // 转换失败返回null return null; } }
二、控制器逻辑优化:增加前置校验
当前控制器未对用户身份合法性、用户/商品存在性做完整校验,导致后续出现userId=0、product=null的异常场景。修改控制器代码,提前拦截无效请求并返回明确响应:
[HttpPost("add-to-favorites/{productId}")] public async Task<ActionResult> AddToFavorites(int productId) { // 1. 校验用户身份合法性 var userId = User.GetUserId(); if (!userId.HasValue) { return Unauthorized("用户身份验证失败,请重新登录"); } // 2. 校验商品是否存在 var product = await _productRepository.GetProductById(productId); if (product == null) { return NotFound("指定商品不存在"); } // 3. 校验当前用户是否存在 var user = await _userRepository.GetUser(userId.Value); if (user == null) { return NotFound("当前用户不存在"); } // 4. 校验是否收藏自己的商品 if (product.UserId == userId.Value) { return BadRequest("无法收藏自己发布的商品"); } // 5. 避免重复收藏(可选,根据需求添加) if (user.LikedProducts.Any(p => p.Id == productId)) { return BadRequest("该商品已在你的收藏列表中"); } // 6. 添加收藏并保存 user.LikedProducts.Add(product); await _context.SaveChangesAsync(); return Ok("收藏成功"); }
三、实体关系配置错误:多对多关系未正确定义
你的需求是用户可收藏多个商品,单个商品可被多个用户收藏,这是典型的多对多关系,但当前实体设计存在混淆:
Product类中的UserId和User导航属性是一对多关系(用户发布商品),而User.LikedProducts是收藏的多对多关系,EF Core会默认混淆这两个关系,导致关联表生成错误或无法正确添加收藏。
修复多对多关系配置
在你的DbContext的OnModelCreating方法中,显式配置用户与收藏商品的多对多关系:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置用户发布商品的一对多关系(保留原有逻辑) modelBuilder.Entity<Product>() .HasOne(p => p.User) .WithMany(u => u.Products) .HasForeignKey(p => p.UserId) .OnDelete(DeleteBehavior.Cascade); // 配置用户收藏商品的多对多关系 modelBuilder.Entity<User>() .HasMany(u => u.LikedProducts) .WithMany() // 若不需要在Product中添加反向导航,使用空的WithMany() .UsingEntity(j => j.ToTable("UserLikedProducts")); // 指定中间表名称 }
如果需要在Product中查看哪些用户收藏了它,可给Product添加反向导航属性:
public class Product { // ... 原有属性 public List<User> LikedByUsers { get; set; } = new List<User>(); }
然后修改多对多配置:
modelBuilder.Entity<User>() .HasMany(u => u.LikedProducts) .WithMany(p => p.LikedByUsers) .UsingEntity(j => j.ToTable("UserLikedProducts"));
四、调试建议
- 检查身份验证Token中的Claim:在Postman中发送请求时,确保携带的Token包含
NameIdentifierClaim,且值为合法的整数用户ID。 - 验证
GetProductById方法:确认该方法正确查询数据库,没有因逻辑错误返回null(比如是否涉及软删除、查询条件错误)。 - 查看数据库中间表:多对多关系配置后,EF会自动生成
UserLikedProducts表,确认添加收藏后该表是否插入了正确的用户ID和商品ID记录。
内容的提问来源于stack exchange,提问作者szymix1322
相关产品推荐
相关产品推荐

