You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用户收藏商品功能触发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"));

四、调试建议

  1. 检查身份验证Token中的Claim:在Postman中发送请求时,确保携带的Token包含NameIdentifierClaim,且值为合法的整数用户ID。
  2. 验证GetProductById方法:确认该方法正确查询数据库,没有因逻辑错误返回null(比如是否涉及软删除、查询条件错误)。
  3. 查看数据库中间表:多对多关系配置后,EF会自动生成UserLikedProducts表,确认添加收藏后该表是否插入了正确的用户ID和商品ID记录。

内容的提问来源于stack exchange,提问作者szymix1322

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 01:52:47