如何在.ashx处理程序上使用输出缓存

26

我该如何在.ashx处理程序中使用输出缓存?在这种情况下,我正在进行一些重度图像处理,并希望处理程序被缓存约一分钟左右。

另外,有没有人有关于如何防止狗垛的建议?


非常相似的线程:https://dev59.com/NEfRa4cB1Zd3GeqP7DSA。 - hadi teo
另一个参考链接:http://forums.asp.net/t/1294848.aspx - hadi teo
5个回答

36

有一些好的资源,但你希望服务器端和客户端都进行缓存。

添加HTTP头可以帮助在客户端进行缓存。

以下是一些响应头以供参考。

你可以花费几个小时来调整它们,直到达到期望的性能。

//Adds document content type
context.Response.ContentType = currentDocument.MimeType;
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(10));
context.Response.Cache.SetMaxAge(new TimeSpan(0,10,0)); 
context.Response.AddHeader("Last-Modified", currentDocument.LastUpdated.ToLongDateString());

// Send back the file content
context.Response.BinaryWrite(currentDocument.Document);

至于服务器端缓存,那是一个不同的问题......而且有很多可用的缓存资源......


1
感谢您阅读上面留言,显然输出缓存在这种情况下也无法直接使用,因此我将采用手动服务器端解决方案和客户端解决方案。 - Kieran Benton
3
我曾从我们的数据库中大量提供缩略图服务。需要注意的是,要设定好最终用户的期望值...... 用户会更新一张图片,然后去查看网站实际情况......但由于浏览器被告知缓存了该图片并且不需要再次请求......他们无法看到更新......(然后他们会哭着回来找开发人员......而我们只能告诉他们清除浏览器缓存...) - BigBlondeViking
如果您希望确保用户在刷新页面时无法请求新的图像,请确保包括“Response.Cache.SetRevalidation(Web.HttpCacheRevalidation.None);”和“Response.Cache.SetValidUntilExpires(True);”。此外,如果您的处理程序应通过查询参数维护不同版本,请设置“Response.Cache.VaryByParams("*") = True;”。 - Carter Medlin
如果我通过按F5手动刷新页面,我的浏览器(Chrome)将忽略缓存并重新加载ashx。如果我通过超链接浏览到页面并重新加载,缓存的副本将被使用。奇怪的是,我的其他资源都从缓存中加载,只有ashx没有。 - Walter Stabosz
我只使用了 context.Response.Cache.* 部分,仅设置了一分钟。我使用异步图像处理(上传/更新)它们,一分钟后它们将从缓存中清除,新图像将显示。非常感谢 +99。 - Pierre
显示剩余2条评论

11

你可以像这样使用

public class CacheHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            OutputCachedPage page = new OutputCachedPage(new OutputCacheParameters
            {
                Duration = 60,
                Location = OutputCacheLocation.Server,
                VaryByParam = "v"
            });
            page.ProcessRequest(HttpContext.Current);
            context.Response.Write(DateTime.Now);
        }

        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()
            {
                // when you put the <%@ OutputCache %> directive on a page, the generated code calls InitOutputCache() from here
                base.FrameworkInitialize();
                InitOutputCache(_cacheSettings);
            }
        }
    }

7

虽然这是一个老问题,但答案并没有真正提到服务器端的处理。

就像获胜的答案一样,我会将这个用于客户端

context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(10));
context.Response.Cache.SetMaxAge(TimeSpan.FromMinutes(10)); 

对于服务器端,因为您正在使用ashx而不是网页,我假设您直接将输出写入Context.Response

在这种情况下,您可以像这样使用(在此示例中,我想根据参数“q”保存响应,并使用滑动窗口过期)。

using System.Web.Caching;

public void ProcessRequest(HttpContext context)
{
    string query = context.Request["q"];
    if (context.Cache[query] != null)
    {
        //server side caching using asp.net caching
        context.Response.Write(context.Cache[query]);
        return;
    }

    string response = GetResponse(query);   
    context.Cache.Insert(query, response, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10)); 
    context.Response.Write(response);
}

该死,我刚想点赞这个帖子,结果发现我之前一定来过这里,因为它已经被点赞了! - Matt

4
我用以下方法成功了,认为这很值得在这里发布。
手动控制ASP.NET页面输出缓存
来自http://dotnetperls.com/cache-examples-aspnet 在Handler.ashx文件中设置缓存选项
首先,您可以在ASP.NET中使用HTTP处理程序以比Web表单页面更快的方式提供动态内容。 Handler.ashx是ASP.NET通用处理程序的默认名称。 您需要使用HttpContext参数并通过那种方式访问Response。
示例代码摘录:
<%@ WebHandler Language="C#" Class="Handler" %>

C# 缓存响应 1 小时
using System;
using System.Web;

public class Handler : IHttpHandler {

    public void ProcessRequest (HttpContext context) {
        // Cache this handler response for 1 hour.
        HttpCachePolicy c = context.Response.Cache;
        c.SetCacheability(HttpCacheability.Public);
        c.SetMaxAge(new TimeSpan(1, 0, 0));
    }

    public bool IsReusable {
        get {
            return false;
        }
    }
}

5
如果我说错了,请纠正我,但是这些选项只影响浏览器缓存。我认为它们对IIS或ASP.NET输出缓存没有任何影响。 - RobSiklos

1
使用OutputCachedPage解决方案效果很好,但会牺牲性能,因为需要实例化一个派生自System.Web.UI.Page基类的对象。
一种简单的解决方案是使用Response.Cache.SetCacheability,正如上面的答案所建议的那样。但是,要将响应缓存到服务器(在输出缓存中),就需要使用HttpCacheability.Server,并设置VaryByParamsVaryByHeaders(请注意,当使用VaryByHeaders时,URL不能包含查询字符串,因为缓存将被跳过)。
以下是一个简单的示例(基于https://support.microsoft.com/en-us/kb/323290):
<%@ WebHandler Language="C#" Class="cacheTest" %>
using System;
using System.Web;
using System.Web.UI;

public class cacheTest : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        TimeSpan freshness = new TimeSpan(0, 0, 0, 10);
        DateTime now = DateTime.Now; 
        HttpCachePolicy cachePolicy = context.Response.Cache;

        cachePolicy.SetCacheability(HttpCacheability.Public);
        cachePolicy.SetExpires(now.Add(freshness));
        cachePolicy.SetMaxAge(freshness);
        cachePolicy.SetValidUntilExpires(true);
        cachePolicy.VaryByParams["id"] = true;

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

        context.Response.Write(context.Request.QueryString["id"]+"\n");
        context.Response.Write(DateTime.Now.ToString("s"));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

提示:您可以在性能计数器“ASP.NET应用程序__总计__\输出缓存总计”中监视缓存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接