c# - ASP.NET HttpContext 缓存在插入后立即删除

标签 c# asp.net asp.net-mvc csv caching

我有一个 ASP.NET 4 网络服务。
它在 ModuleController Controller 中有一个 ImportModule 操作。

这就是它的工作原理:

  1. 用户将模块上传为 CSV 文件。
  2. 正在使用 HttpPostedFileBase.InputStream 和自定义 CSV 读取类读取此文件。
  3. 根据某些规则和验证,此文件正在转换为 C# 对象。如果文件有效,则它转换为 C# 对象,存储在具有唯一 GUID 名称的缓存中,用户被重定向到 CompleteImportModule 操作。
  4. 用户检查数据是否正确并确认上传。

长话短说,有一个代码可以告诉你更多:
ImportModule 操作。

public ActionResult ImportModule(HttpPostedFileBase file)
{
    if (!ModelState.IsValid) 
    {
        return RedirectToAction("Index");
    }

    ModuleQuestion[] questions;
    ModuleInfo moduleInfo;
    string uploadId = Guid.NewGuid().ToString();

    // It is my custom CSV-reader and it works. Values are assigned
    FormDataCsvReader csvReader = new FormDataCsvReader(file.InputStream);
    if (!csvReader.Process(out questions, out moduleInfo))
    {
        // File is invalid
        return RedirectToAction("Index");
    }

    ViewBag.UploadId = uploadId;
    ViewBag.ModuleInfo = moduleInfo;
    ViewBag.Questions = questions;

    HttpContext.Cache.Add("UploadModule_" + uploadId,
        new Tuple<ModuleInfo, ModuleQuestion[]>(moduleInfo, questions),
        null,
        Cache.NoAbsoluteExpiration,
        TimeSpan.FromMinutes(30),
        CacheItemPriority.NotRemovable,
        (k, v, r) => 
        {
            LoggingFactory.GetLogger().Debug("Removed from cache: {0}. Reason: {1}", k, r);
        });     

    return View();   
}

在 View ImportModule 中:

// Output data from ViewBag.ModuleInfo and ViewBag.Questions

<form method="POST" action="@Url.Action("CompleteImportModule")">
    <input type="hidden" name="uploadId" value="@ViewBag.UploadId"/>
    <input type="submit" value="Send">
</form>

CompleteImportModule Action :

[HttpPost]
public ActionResult CompleteImportModule(string uploadId)
{
    var item = HttpContext.Cache["UploadModule_" + uploadId];
    if (item == null) RedirectToAction("Index");
    // upload module 
    HttpContext.Cache.Remove("UploadModule_" + uploadId);
    return RedirectToAction("Index");
}

但是,我遇到了一些问题。我无法上传模块,因为该值在插入后立即从缓存中删除。它只存储一秒钟:

DEBUG 2015-06-22 15:00:18,696 thread 85: Added to cache:
UploadModule_c843077d-21d0-4e9f-9e5e-3df82da4bac8

DEBUG 2015-06-22 15:00:19,935 thread 48: Removed from cache:
UploadModule_c843077d-21d0-4e9f-9e5e-3df82da4bac8. Reason: Removed

reason 是“Removed”,这意味着它没有过期并且 IIS 没有因为优化而删除它,但看起来我删除的是我自己。 我很确定在 CompleteImportModule 之前我什至没有访问这个缓存记录。

我尝试将 new StackTrace().ToString() 放入 CacheItemRemovedCallback 中。就是这样,如果它能以某种方式提供帮助:

at CPMAdministrator.Controllers.ModulesReferenceController.<ImportModule>b__9(String key, Object value, CacheItemRemovedReason reason)
   at System.Web.Caching.CacheEntry.CallCacheItemRemovedCallback(CacheItemRemovedCallback callback, CacheItemRemovedReason reason)
   at System.Web.Caching.CacheEntry.Close(CacheItemRemovedReason reason)
   at System.Web.Caching.CacheSingle.UpdateCache(CacheKey cacheKey, CacheEntry newEntry, Boolean replace, CacheItemRemovedReason removedReason, Object& valueOld)
   at System.Web.Caching.CacheSingle.Dispose(Boolean disposing)
   at System.Web.Caching.CacheMultiple.Dispose(Boolean disposing)
   at System.Web.HttpRuntime.Dispose()
   at System.Web.HttpRuntime.ReleaseResourcesAndUnloadAppDomain(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

为什么会这样?是某种 IIS 池回收吗?如何确保该文件未被删除?或者我怎样才能以其他方式有效地存储这些数据?

最佳答案

我花了几个小时寻找答案,并在发布问题后找到了答案!让我与您分享我的经验。

根据我的StackTrace,我了解到缓存已经被清除,因为应用程序已经结束并被释放:

at System.Web.HttpRuntime.Dispose()
at System.Web.HttpRuntime.ReleaseResourcesAndUnloadAppDomain(Object state)

我所需要的只是找到它的原因。

我打开了我的 Global.asax 文件并添加了一个 Application_End 方法。

public class MvcApplication : HttpApplication
{
    protected void Application_End()
    {
    }
}

它在 View 渲染成功之后和缓存清除之前被触发。成功!现在我需要知道申请结束的原因。

This post帮助我:

There's System.Web.Hosting.HostingEnvironment.ShutdownReason property that indicates why the application is being terminated. Its value can be retrieved from inside Application_End().

我在 Application_End 的开头添加了一个断点,并添加了 System.Web.Hosting.HostingEnvironment.ShutdownReason 来观看。

这就是它存储的内容:BinDirChangeOrDirectoryRename

之后,我明白了原因是我的log4net 正在BinDirectory 中写入日志。我只是不知道如果 bin 目录已更改,IIS 正在完成 Web 应用程序。

我已将我的日志移至父(应用程序本身)文件夹,现在可以使用了。
看来我需要阅读更多有关 ASP.NET 的内容。
我希望它能帮助别人。感谢所有试图提供帮助的人。

关于c# - ASP.NET HttpContext 缓存在插入后立即删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30976854/

相关文章:

c# - 未处理C#NullReferenceException-未将对象引用设置为对象的实例

c# - 通过 C# 缩小 JavaScript 代码 - ASP.NET

javascript - asp.net 如何在点击文本框时显示一个div。使用 jquery

c# - JavaScript 模态弹出窗口 - 用自定义按钮替换 OK 按钮

asp.net-mvc - MVC 按钮单击在新窗口中打开

c# - WPF/C# : Connect shapes dynamically with lines

c# - Selenium C# Firefox 22 - 来自网络的 "silent save file"不再工作

c# - 为什么 ReSharper 在将属性转换为自动属性时需要扫描所有文件?

c# - 在单独的帮助程序类中访问 Controller 外部的 HttpContext session 的最佳实践

c# - 图像调整大小 asp.net mvc 应用程序