3

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

Cœur
  • 37,241
  • 25
  • 195
  • 267
Abhi.Net
  • 722
  • 3
  • 11
  • 37

1 Answers1

3

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);
}
moribvndvs
  • 42,191
  • 11
  • 135
  • 149
  • I had HttpRuntime.Cache.Insert inside the using block but i was still getting the error. I don't know why I moved i outside the using block. I think just got a bit frustrated. As for your second comment, I have my html files stored in Amazon s3, including my images stylesheets and Javascript files. Now I need to retrieve each one of them seperately.Thats how S3 works! Now what I am trying to achieve is add stream of each object in cache and when I click the link again I retrieve it from cache and not Amazon S3. – Abhi.Net Jun 07 '12 at 06:33
  • 1
    You can't use `using` at all if you want to be able to come back and use the stream from the cache. The moment the `using` block goes out of scope, the stream is disposed. – moribvndvs Jun 07 '12 at 06:35
  • The objects I am retrieving are not just images. they can be css files .js files, .html file or.gif files so I can't limit my function to just images or bitmap for that reason. – Abhi.Net Jun 07 '12 at 06:59
  • As per the requirement I can't store Images on disk. Also we will be using Memcached in production environment but since the synatx to add and retrieve is almost same and the Memcached server is not ready yet I have to use httpruntime.cache just to simulate memcached. – Abhi.Net Jun 07 '12 at 07:18
  • OK, you need to provide more of these details in the question next time. In this case, you could write the response.ResponseStream to a MemoryStream, then cache the byte buffer. Here comes another example. – moribvndvs Jun 07 '12 at 07:21
  • OK, phew. Take a look at the latest version. This should do what you need. – moribvndvs Jun 07 '12 at 07:45
  • You my friend are an asset to the stack overflow community. Not only were you patient and explained me the shortcomings in my code but you updated and re factored your solution multiple times and it's working beautifully. Thanks again, Much appreciated!! – Abhi.Net Jun 08 '12 at 01:10