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

.NET 6 Razor Pages中HttpContext.Session存储数据偶发失效问题

.NET 6 Razor Pages Session存储偶发失效问题

问题背景

我正在开发一个.NET 6 Razor Pages项目,使用Session存储变量。项目包含一个可编辑XML“文档”(即DespatchAdvise发货通知)的页面,我将模型对象存储在Session中,用于管理该文档子列表的增删改查操作。
注:数据的加载和保存方法均通过AJAX处理:加载由DataTables的ajax请求发起,保存通过普通AJAX请求发起

现有实现代码

Startup.cs Session配置

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => false;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    //*** Other settings omitted ***

    services.AddDistributedMemoryCache();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(Configuration.GetValue<int>("SessionTimeoutInMinutes"));
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.IsEssential = true;
        options.Cookie.Name = "_aspnetCoreSession";
    });
    services.AddHttpContextAccessor();

    //*** Other settings omitted ***
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment() || env.IsStaging())
    {
        app.UseDeveloperExceptionPage();
        RegisteredServicesPage(app); //create a custom page with every service registered
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios
        app.UseHsts();
    }

    app.UseHttpsRedirection();           
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseRouting();           
    app.UseAuthentication();            
    app.UseSession();             
    app.UseAuthorization();                       
    app.UseMvc();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Session扩展工具类

public static class SessionUtils
{
    public static void SetObjectAsJson(this ISession session, string key, object value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
        session.CommitAsync().Wait(); //added to see if something changed (no success)
    }

    public static T GetObjectFromJson<T>(this ISession session, string key)
    {
        session.LoadAsync().Wait();//added to see if something changed (no success)

        var value = session.GetString(key);
        return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace });            
    }
}

手动添加的CommitAsync和LoadAsync方法并没有起到作用

故障表现

在页面中编辑IdentityDocumentReference相关数据并存入Session时,偶尔会出现数据未保存的情况。该问题没有固定复现规律,属于偶发问题:有时数据能正常保存,有时则保存失败。
具体表现为:OnPostSaveDriveDA方法中从Session读取DespatchAdviceDettaglio对象时,偶尔会读到旧版本对象,此时IdentityDocumentReference列表会包含1个空元素。后续新增的司机会被追加到该列表中,但当重新加载列表时,由于首个元素是空对象,列表会被重置,导致所有已添加的数据丢失。从现象上看,SetObjectAsJson方法执行后,Session有时并没有真正完成数据存储。

业务接口代码

DataTables加载司机列表接口

public JsonResult OnPostLoadDriversDA()
{
    Utils_CommonResponse resp = new Utils_CommonResponse();
    List<DespatchAdviceAdditionaDocumentReference> ListIdDocumentRefDriver = new List<DespatchAdviceAdditionaDocumentReference>();

    try
    {
        DespatchAdviceDettaglio = HttpContext.Session.GetObjectFromJson<DespatchAdviceDettaglio>("DespatchAdviceDettaglio");
        List<DocumentReferenceType> IdDriver = DespatchAdviceDettaglio.DespatchAdvice.Shipment.Consignment[0].CarrierParty.Person[0].IdentityDocumentReference;

        if (IdDriver.Count > 0 && String.IsNullOrEmpty(IdDriver.First().ID.Value))
        { 
            //Here I reset the list because I have an empty object to create the interface but for datatables must be an empty list
            IdDriver = new List<DocumentReferenceType>();       
            DespatchAdviceDettaglio.DespatchAdvice.Shipment.Consignment[0].CarrierParty.Person[0].IdentityDocumentReference = IdDriver;
            
            //Here the object IdentityDocumentReference has 0 items (IdDriver is a new List - the problem is on save method)
            HttpContext.Session.SetObjectAsJson("DespatchAdviceDettaglio", DespatchAdviceDettaglio);            
        }

        foreach (DocumentReferenceType drf in IdDriver)
        {
            ListIdDocumentRefDriver.Add(new DespatchAdviceAdditionaDocumentReference()
            {
                ID = drf.ID.Value,
                TipoDocumento = drf.DocumentType.Value
            });
        }

        return new JsonResult(new
        {
            DataTablesRequest.Draw,
            recordsFiltered = ListIdDocumentRefDriver.Count,
            data = ListIdDocumentRefDriver
        });
    }
    catch (Exception exc)
    {
        _logger.LogError($"{exc.Message} - {exc.StackTrace}");
        resp.Esito = false;
        resp.Messaggio = exc.Message;
        return new JsonResult(resp);
    }
}

保存司机信息接口

public JsonResult OnPostSaveDriveDA([FromBody] SaveDriver IncomingData)
{
    Utils_CommonResponse resp = new Utils_CommonResponse();
    try
    {
        DespatchAdviceDettaglio = HttpContext.Session.GetObjectFromJson<DespatchAdviceDettaglio>("DespatchAdviceDettaglio");
        if (IncomingData.IdDriver == -1)
        {     
            //Here, after loading "DespatchAdviceDettaglio" from session, SOMETIMES the list IdentityDocumentReference has 1 element (the empty one)                              
            DespatchAdviceDettaglio.DespatchAdvice.Shipment.Consignment[0].CarrierParty.Person[0].IdentityDocumentReference.Add(IncomingData.DocRefDriver);
            
        }
        else
        { //edit
            DespatchAdviceDettaglio.DespatchAdvice.Shipment.Consignment[0].CarrierParty.Person[0].IdentityDocumentReference[IncomingData.IdDriver] = IncomingData.DocRefDriver;
        }
        HttpContext.Session.SetObjectAsJson("DespatchAdviceDettaglio", DespatchAdviceDettaglio);

        resp.Esito = true;
        resp.Messaggio = "";
    }
    catch (Exception exc)
    {
        resp.Esito = false;
        resp.Messaggio = exc.Message;
    }
    return new JsonResult(resp);
}

内容的提问来源于stack exchange,提问作者Niccolò Gazzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:45:36