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

从Session获取发票单元列表异常:仅返回首个单元的问题排查

问题描述

我正在开发发票功能:已登录用户的发票及发票单元(一对多关系)存储至数据库,未登录用户的数据则存入Session。调试发现,Create方法中invoiceUnitsFromSession的单元数量正确,但在Edit控制器调用GetInvoiceUnitsFromSession()时,每个发票仅能获取到首个发票单元。

现有代码

Create方法

[HttpPost]
public ActionResult Create(Invoice invoice)
{
    var userId = User.Claims.FirstOrDefault(c => c.Type == "UserId")?.Value;
    if (userId is not null)
    {
        invoice.UserId = Guid.Parse(userId.ToString());
        DateTime dateTime = DateTime.Now;
        invoice.DateCreated = dateTime;
        foreach (var invoiceUnit in invoice.InvoiceUnits)
        {
            db.InvoiceUnits.Add(invoiceUnit);
        }
        db.Add(invoice);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    else
    {
        invoice.Id = Guid.NewGuid();
        var invoicesFromSession = GetInvoicesFromSession();
        var invoiceUnitsFromSession = GetInvoiceUnitsFromSession();

        DateTime dateTime = DateTime.Now;
        invoice.DateCreated = dateTime;

        if (invoice is not null)
        {
            invoicesFromSession.Add(invoice);

            HttpContext.Session.SetString("invoice", JsonSerializer.Serialize(invoicesFromSession));

            foreach(var invoiceUnit in invoice.InvoiceUnits)
            {
                invoiceUnit.Id = new Guid();
                invoiceUnit.InvoiceId = invoice.Id;
                HttpContext.Session.SetString("invoiceUnit", JsonSerializer.Serialize(invoiceUnitsFromSession));
                invoiceUnitsFromSession.Add(invoiceUnit);
            }

        }

        return RedirectToAction("Index");
    }

}

从Session获取发票单元的方法

private List<InvoiceUnit> GetInvoiceUnitsFromSession()
{
    HttpContext.Session.LoadAsync();
    var sessionString = HttpContext.Session.GetString("invoiceUnit");
    if (sessionString is not null)
    {
        return JsonSerializer.Deserialize<List<InvoiceUnit>>(sessionString);
    }

    return Enumerable.Empty<InvoiceUnit>().ToList();
}

Edit控制器相关代码

var sessionInvoices = GetInvoicesFromSession();
var sessionInvoiceUnits = GetInvoiceUnitsFromSession();
var invoiceFromDbSession = sessionInvoices.FirstOrDefault(i => i.Id == id);
List<InvoiceUnit> invoiceUnitsForInvoiceSession = new List<InvoiceUnit>();

foreach (var invoiceUnit in sessionInvoiceUnits)
{
    if (invoiceUnit.InvoiceId == id)
    {
        invoiceUnitsForInvoiceSession.Add(invoiceUnit);
    }
}
GenericModel sessionData = new GenericModel(invoiceUnitsForInvoiceSession, invoiceFromDbSession);
return View(sessionData);

问题原因

  1. Session存储顺序错误:Create方法中处理未登录用户发票单元时,先将未添加当前单元的旧列表序列化存入Session,再把当前单元加入列表。循环结束后,Session中存储的永远是缺少最后一个单元的列表,若发票只有多个单元,最终仅能保留前n-1个;若逻辑存在其他触发场景,会导致仅首个单元被正确存储。
  2. 异步方法未等待:GetInvoiceUnitsFromSession()中调用HttpContext.Session.LoadAsync()但未使用await,同步环境下会导致Session数据未正确加载,可能获取到旧数据。

修复方案

1. 修正Create方法的发票单元存储顺序

将添加单元到列表的操作放到存储Session之前,且优化为所有单元添加完成后统一存储,避免循环内重复操作:

// 未登录用户分支的发票单元处理逻辑
foreach(var invoiceUnit in invoice.InvoiceUnits)
{
    invoiceUnit.Id = Guid.NewGuid();
    invoiceUnit.InvoiceId = invoice.Id;
    // 先将单元加入列表
    invoiceUnitsFromSession.Add(invoiceUnit);
}
// 所有单元添加完成后,统一序列化存储到Session
HttpContext.Session.SetString("invoiceUnit", JsonSerializer.Serialize(invoiceUnitsFromSession));

2. 修复Session加载的异步调用问题

移除不必要的异步加载调用(ASP.NET Core中调用GetString时会自动加载Session),或改为异步方法并等待:

同步版本(推荐当前场景)

private List<InvoiceUnit> GetInvoiceUnitsFromSession()
{
    var sessionString = HttpContext.Session.GetString("invoiceUnit");
    if (!string.IsNullOrEmpty(sessionString))
    {
        return JsonSerializer.Deserialize<List<InvoiceUnit>>(sessionString);
    }

    return new List<InvoiceUnit>();
}

异步版本(若控制器方法改为异步)

private async Task<List<InvoiceUnit>> GetInvoiceUnitsFromSessionAsync()
{
    await HttpContext.Session.LoadAsync();
    var sessionString = HttpContext.Session.GetString("invoiceUnit");
    if (!string.IsNullOrEmpty(sessionString))
    {
        return JsonSerializer.Deserialize<List<InvoiceUnit>>(sessionString);
    }

    return new List<InvoiceUnit>();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:30:50