如何在Razor C#中将读取的CSV列表设置为全局变量在Post请求中复用
问题根本原因
Razor Pages的PageModel实例是每请求创建一次的,你在OnGetAsync里给doc1赋值,POST请求触发时会新建IndexModel实例,之前的doc1值自然就丢失了,所以每次POST都要重读数据。
解决方案1:应用级内存缓存(所有用户共用同一份数据,推荐)
如果这份CSV数据是所有用户共享的无差异数据,用ASP.NET Core自带的内存缓存即可,只在首次访问时加载,后续所有请求直接读取缓存,性能最优。
步骤1:注册缓存服务
在Program.cs中添加配置:
// 服务注册区添加 builder.Services.AddMemoryCache();
步骤2:改造IndexModel代码
将重复的Blob读取逻辑抽为公共方法,优先从缓存取数据,缓存不存在时再从Blob加载:
using Microsoft.Extensions.Caching.Memory; // 新增引用 public class IndexModel : PageModel { private readonly ILogger<IndexModel> _logger; private readonly IMemoryCache _cache; // 缓存Key固定值,避免拼写错误 private const string DocCacheKey = "Global_Document_List_Cache"; public List<Documents> doc1 = new List<Documents>(); // 其余原有属性保持不变 // 构造函数注入缓存服务 public IndexModel(ILogger<IndexModel> logger, IMemoryCache cache) { _logger = logger; _cache = cache; } // 抽离公共的文档加载方法 private async Task<List<Documents>> LoadDocumentsAsync() { // 缓存存在直接返回 if (_cache.TryGetValue(DocCacheKey, out List<Documents> cachedDocs)) { return cachedDocs; } // 缓存不存在,走原有Blob加载逻辑 var accountName = ""; var accessKey = ""; var credential = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(accountName, accessKey); var storageAccount = new CloudStorageAccount(credential, true); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference(""); CloudBlockBlob blockBlob2 = container.GetBlockBlobReference("FILES-1000000.xml"); string files2; using (var memoryStream2 = new MemoryStream()) { await blockBlob2.DownloadToStreamAsync(memoryStream2); files2 = System.Text.Encoding.UTF8.GetString(memoryStream2.ToArray()); } byte[] byteArray2 = Encoding.UTF8.GetBytes(files2); MemoryStream stream2 = new MemoryStream(byteArray2); StreamReader reader2 = new StreamReader(stream2); XmlSerializer serializer = new XmlSerializer(typeof(filelists)); filelists result = (filelists)serializer.Deserialize(reader2); reader2.Close(); var docList = new List<Documents>(); CloudBlockBlob blockBlob3 = container.GetBlockBlobReference(result.list[0].file); using (var memoryStream3 = new MemoryStream()) { await blockBlob3.DownloadToStreamAsync(memoryStream3); var data = System.Text.Encoding.UTF8.GetString(memoryStream3.ToArray()); var doc = data.Split("<seprt>"); var counter = 0; string id = "", tytle = "", body = "", htmlbody = ""; foreach (string value in doc) { if (counter % 4 == 0) id = doc[counter]; else if (counter % 4 == 1) tytle = doc[counter]; else if (counter % 4 == 2) body = doc[counter]; else if (counter % 4 == 3) { htmlbody = doc[counter]; docList.Add(new Documents() { id = id, tytle = tytle, body = body, htmlbody = htmlbody }); } counter++; } } // 写入缓存,设置1小时过期,可根据数据更新频率调整 _cache.Set(DocCacheKey, docList, TimeSpan.FromHours(1)); return docList; } public async Task OnGetAsync() { doc1 = await LoadDocumentsAsync(); error = "open"; } public async Task<JsonResult> OnPost() { indx = Request.Form["indx"]; evnt = Request.Form["evnt"]; textdata = Request.Form["textbody"]; htmldata = Request.Form["htmlbody"]; // 直接调用公共方法拿数据,不用重复写加载逻辑 var docList = await LoadDocumentsAsync(); int index = Int32.Parse(indx); if (evnt == "listclick") { bodyelement = docList[index].htmlbody; } else if (evnt == "save") { // 更新本地对象,再组装保存到Blob docList[index].body = textdata; docList[index].htmlbody = htmldata; await saveDoc(docList); // 保存成功后清除缓存,下次加载就会拿到最新数据 _cache.Remove(DocCacheKey); bodyelement = "saved"; } await Task.Delay(100); if (!ModelState.IsValid) { return new JsonResult("JSONResponse: Error occurred. Please retry."); } return new JsonResult(bodyelement); } // 改造saveDoc方法参数,直接传处理好的文档列表 public async Task saveDoc(List<Documents> docList) { // 组装CSV逻辑保持不变,Blob上传逻辑也保持不变 // ......原有保存逻辑...... } // 其余原有类定义保持不变 }
解决方案2:用户会话级存储(每个用户独立数据)
如果数据是用户私有差异化数据,可使用Session存储:
- 在
Program.cs中注册Session服务并启用Session中间件 - 将
List<Documents>序列化后存入Session,请求时读取反序列化即可
注意:Session适合存储小体积数据,大体积数据仍建议走缓存+用户标识区分的方案
内容的提问来源于stack exchange,提问作者西浦直志
相关产品推荐
相关产品推荐

