.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
相关产品推荐
相关产品推荐

