Tom Gullen
Tom Gullen

Reputation: 61775

ASP.net cache ASHX file server-side

Given the generic handler:

<%@ WebHandler Language="C#" Class="autocomp" %>

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;

public class autocomp : IHttpHandler {

    public void ProcessRequest (HttpContext context) {

        context.Response.ContentType = "application/json";
        context.Response.BufferOutput = true;

        var searchTerm = (context.Request.QueryString["name_startsWith"] + "").Trim();

        context.Response.Write(searchTerm);
        context.Response.Write(DateTime.Now.ToString("s"));

        context.Response.Flush();
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

How would I server side cache this file for 1 hour based on the name_startsWith query string parameter? With web user controls it's easy:

<%@ OutputCache Duration="120" VaryByParam="paramName" %>

But I've been looking around for a while to do the same with a generic handler (ashx) file and can't find any solutions.

Upvotes: 2

Views: 4319

Answers (4)

ATRedline
ATRedline

Reputation: 1

To cache file, such as .js, .css or other you need to put it to the context.cache. Example:

    public void ProcessRequest(HttpContext context)
    {
        var cachedResult = context.Cache.Get(context.Request.Path);

        if (cachedResult != null && cachedResult.GetType() == typeof(VueFileRequestResult))
        {
            RequestedFileResponce(context, cachedResult as VueFileRequestResult);
            return;
        }
        
        // SOME ACTIONS WITH NON-CACHED FILE

        var fileContent = System.IO.File.ReadAllBytes(filePath);
        var result = new VueFileRequestResult(contentType.GetDescription(), fileContent);

        RequestedFileResponce(context, result);

        var expirationDate = DateTime.Now.AddYears(1);
        var dependency = new CacheDependency(filePath);
        context.Cache.Add(context.Request.Path, result, dependency, expirationDate, TimeSpan.Zero, CacheItemPriority.Low, null);

        return;
    }

Upvotes: 0

Raoof Arakkal
Raoof Arakkal

Reputation: 65

For multiple query string parameters

public class test : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        OutputCachedPage page = new OutputCachedPage(new OutputCacheParameters
        {
            Duration = 120,
            Location = OutputCacheLocation.Server,
            VaryByParam = "name;city"
        });

        page.ProcessRequest(HttpContext.Current);

        context.Response.ContentType = "application/json";
        context.Response.BufferOutput = true;

        var searchTerm = (context.Request.QueryString["name"] + "").Trim();
        var searchTerm2 = (context.Request.QueryString["city"] + "").Trim();

        context.Response.Write(searchTerm+" "+searchTerm2+" ");
        context.Response.Write(DateTime.Now.ToString("s"));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
    private sealed class OutputCachedPage : Page
    {
        private OutputCacheParameters _cacheSettings;

        public OutputCachedPage(OutputCacheParameters cacheSettings)
        {
            // Tracing requires Page IDs to be unique.
            ID = Guid.NewGuid().ToString();
            _cacheSettings = cacheSettings;
        }

        protected override void FrameworkInitialize()
        {
            base.FrameworkInitialize();
            InitOutputCache(_cacheSettings);
        }
    }
}

Upvotes: 1

Steven V
Steven V

Reputation: 16595

With the code you've provided you're telling the end user browser to cache the results for 30 minutes, so you aren't doing any server side caching.

If you want to cache the results server side you're probably looking for HttpRuntime.Cache. This would allow you to insert an item into a cache that is globally available. Then on the page load you would want to check the existence of the cached item, then if the item doesn't exist or is expired in the cache, go to the database and retrieve the objects.

EDIT

With your updated code sample, I found https://stackoverflow.com/a/6234787/254973 which worked in my tests. So in your case you could do:

public class autocomp : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        OutputCachedPage page = new OutputCachedPage(new OutputCacheParameters
        {
            Duration = 120,
            Location = OutputCacheLocation.Server,
            VaryByParam = "name_startsWith"
        });

        page.ProcessRequest(HttpContext.Current);

        context.Response.ContentType = "application/json";
        context.Response.BufferOutput = true;

        var searchTerm = (context.Request.QueryString["name_startsWith"] + "").Trim();

        context.Response.Write(searchTerm);
        context.Response.Write(DateTime.Now.ToString("s"));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
    private sealed class OutputCachedPage : Page
    {
        private OutputCacheParameters _cacheSettings;

        public OutputCachedPage(OutputCacheParameters cacheSettings)
        {
            // Tracing requires Page IDs to be unique.
            ID = Guid.NewGuid().ToString();
            _cacheSettings = cacheSettings;
        }

        protected override void FrameworkInitialize()
        {
            base.FrameworkInitialize();
            InitOutputCache(_cacheSettings);
        }
    }
}

Upvotes: 8

Akash Kava
Akash Kava

Reputation: 39956

IIS does not use Max Age to cache anything as it is not HTTP PROXY.

That is because you are not setting Last Modified Date Time of some dependent file. IIS needs a cache dependency (file dependency, so that it can check the last update time) and compare it with cache. IIS does not work as HTTP Proxy, so it will not cache items for 30 seconds, instead IIS only updates cache based on some sort of date time or some cache variable.

You can add cache dependency two says, File Dependency and Sql Cache Dependency.

How dynamic caching works in IIS, lets say you have an html file. IIS considers a static html text as cachable file and it will gzip it and put cached copy in its cache. If last update time for static html is older then cache time, then it will use cache. If the file was modified, IIS will find that last update time of html is greater then cache time, so it will reset the cache.

For dynamic content, you have to plan your caching accordingly. If you are serving a content based on some row stored in SQL table, then you should keep track of last update time on that row and add cache dependency on IIS along with SQL to query the last update time of item you are trying to cache.

Upvotes: 0

Related Questions