Search code examples
c#asp.netasp.net-cache

Retrieving image from HTTPRuntime Cache


I am trying to save and retrieve an Image from HTTPRuntime Cache but I am getting an exception. I am able to save a stream to cache but when I try to retrieve it I get an exception saying:

the request was aborted. The connection was closed unexpectedly

Here is my code:

public void ProcessRequest(HttpContext context)
{   
    string courseKey = context.Request.QueryString["ck"];
    string objKey = context.Request.QueryString["file"];

    if(HttpRuntime.Cache[objKey] !=null)
    {
        using (Stream stream = (Stream)HttpRuntime.Cache[objKey]) // here is where I get an exception
        {
            var buffer = new byte[8000];
            var bytesRead = -1;
            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                context.Response.OutputStream.Write(buffer, 0, bytesRead);
            }
        }
        return;
    }
    var response = Gets3Response(objKey, courseKey, context);           

    if (response != null)
    {
        using (response)
        {
            var MIMEtype = response.ContentType;
            context.Response.ContentType = MIMEtype;
            var cacheControl = context.Response.CacheControl;
            HttpRuntime.Cache.Insert(objKey, response.ResponseStream, null, DateTime.UtcNow.AddMinutes(20), Cache.NoSlidingExpiration);
            using (Stream responseStream = response.ResponseStream)
            {
                var buffer = new byte[8000];
                var bytesRead = -1;
                while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                   context.Response.OutputStream.Write(buffer, 0, bytesRead);
                }
            }
        }
    }
}

And here is the exception I am getting

Exception


Solution

  • This code is pretty confusing. First, you are caching response.ResponseStream, but that has been wrapped in a using block. So by the time you get to HttpRuntime.Cache.Insert, response.ResponseStream is already disposed and closed. Hence the error.

    You should not be caching a stream. For one thing, once you put a distributed cache service in place, your approach will be impossible. You need to refactor this. Consider:

    public class CacheAsset
    {
       public string FileName { get; set; }
       public string ContentType { get; set; }
       public byte[] Content { get; set; }
    }
    
    CacheAsset GetAsset(HttpContext context)
    {
       string courseKey = context.Request.QueryString["ck"];
       string objKey = context.Request.QueryString["file"];
    
       var asset = context.Cache[objKey] as CacheAsset;
    
       if (asset != null) return asset;
    
       using (var response = Gets3Response(objKey, courseKey, context))
       using (var stream = new MemoryStream())
       { 
          var buffer = new byte[8000];
          var read = 0;
    
          while ((read = response.ReponseStream.Read(buffer, 0, buffer.Length)) > 0)
          {
             stream.Write(buffer, 0, read);
          }
    
          asset = new CacheAsset
                  {
                     FileName = objKey,
                     ContentType = reponse.ContentType,
                     Content = stream.ToArray()
                  };
           context.Cache.Insert(objKey, asset, null, DateTime.UtcNow.AddMinutes(20), Cache.NoSlidingExpiration);
       }
    
       return asset;
    }
    
    public void ProcessRequest(HttpContext context)
    {
       var asset = GetAsset(context);
    
       context.Response.ContentType = asset.ContentType;
       context.Response.BinaryWrite(asset.Content);
    }