插入后立即删除ASP.NET HttpContext缓存 [英] ASP.NET HttpContext Cache removes right after insertion

查看:63
本文介绍了插入后立即删除ASP.NET HttpContext缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ASP.NET 4 Web服务.
它在ModuleController控制器中具有ImportModule动作.

I have an ASP.NET 4 web-service.
It has an ImportModule action in a ModuleController controller.

这就是它的工作方式:

  1. 用户将模块上传为CSV文件.
  2. 正在使用HttpPostedFileBase.InputStream和自定义CSV读取类读取此文件.
  3. 根据一些规则和验证,此文件正在转换为C#对象.如果文件有效,则它将转换为C#对象,并以唯一的GUID名称存储在Cache中,并且将用户重定向到CompleteImportModule操作.
  4. 用户检查数据是否正确,并确认上传.
  1. The user uploads a module as a CSV-file.
  2. This file is being read using HttpPostedFileBase.InputStream and custom CSV-reading class.
  3. This file is being transformed to a C# object according to some rules and validations. If a file is valid, then it transforms to C# object, stores in a Cache with unique GUID name and a user is redirected to CompleteImportModule action.
  4. User checks if data is correct and he confirms uploading.

长话短说,有一个代码可以告诉您更多信息:
ImportModule操作.

Long story short, there is a code which tells you more:
ImportModule action.

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();   
}

在视图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操作:

[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");
}

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

However, I met some problems. I cannot upload the module because the value is removed from a Cache right after being inserted. It is stored only for a second:

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是已删除",这意味着它没有过期,并且由于优化,IIS尚未将其删除,但看来我删除的是我本人. 我很确定我什至没有在CompleteImportModule之前访问此缓存记录.

The reason is "Removed" meaning that it is not expired and IIS hasn't removed it due to optimization but it looks like I removed is myself. I am pretty sure that I am even not accessing this cache record before CompleteImportModule.

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

I have tried putting new StackTrace().ToString() in a CacheItemRemovedCallback. That's it, if it can help somehow:

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池回收吗?如何确保未删除文件?或者我该如何有效地以其他方式存储这些数据?

Why is it happening? Is it sort of IIS pool recycling? How can I ensure that the file is not being removed? Or how can I effictively store this data another way?

推荐答案

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

I have spent several hours finding an answer and found it right after posting a question! Let me share my experience with you.

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

According to my StackTrace, I understood that the cache has been cleared because the application has been ended and disposed:

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

我所需要的只是找到原因.

All I needed is to find a reason of it.

我已经打开Global.asax文件并添加了Application_End方法.

I have opened my Global.asax file and added a Application_End method.

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

它已在视图渲染成功之后以及清除缓存之前立即触发.成功!现在,我需要知道应用程序终止的原因.

It has been triggered right after view rendering success and right before cache clearing. Success! Now I needed to know the reason of application ending.

这篇文章帮助我:

System.Web.Hosting.HostingEnvironment.ShutdownReason 指示为什么终止应用程序的属性.它的 值可以从Application_End()内部检索.

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进行观看.

I added a breakpoint in a beginning of Application_End and added System.Web.Hosting.HostingEnvironment.ShutdownReason to watch.

这就是它存储的内容:BinDirChangeOrDirectoryRename.

That's what it stored: BinDirChangeOrDirectoryRename.

此后,我了解到原因是我的log4netBinDirectory中写了日志.我只是不知道,如果bin目录已更改,则IIS正在完成Web应用程序.

After that, I have understood that the reason is that my log4net is writing logs right in BinDirectory. I just never knew that IIS is finishing web applications if bin directory has been changed.

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

I have moved my logs to a parent (application itself) folder and now it works.
It looks like I need to read more about ASP.NET.
I hope that it will help someone. Thanks to everybody who tried to help.

这篇关于插入后立即删除ASP.NET HttpContext缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆