加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

ASP.NET OutputCache和Cookies

发布时间:2020-12-16 04:35:15 所属栏目:asp.Net 来源:网络整理
导读:有谁知道为什么如果我的页面上有cookie,输出缓存不起作用! 示例页面 %@ Page Language="VB" AutoEventWireup="false" CodeFile="ct.aspx.vb" Inherits="ct" %%@ OutputCache Duration="600" Location="Server" VaryByParam="none" %!DOCTYPE html PUBLIC "-
有谁知道为什么如果我的页面上有cookie,输出缓存不起作用!

示例页面

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="ct.aspx.vb" Inherits="ct" %>
<%@ OutputCache Duration="600" Location="Server" VaryByParam="none" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <h1>Cache test</h1>
      <p id="rndout" runat="server"></p>
    </div>
    </form>
</body>
</html>

后面的示例代码:

Partial Class ct
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(sender As Object,e As System.EventArgs) Handles Me.Load
        Dim rc As New Random()
        Dim rn As Integer
        rn = rc.Next()
        rndout.InnerHtml = rn.ToString

        Response.Cookies("sym")("hello") = "world"
        Response.Cookies("sym").Expires = DateTime.Now.AddDays(370)
        Response.Cookies("sym").Domain = Application.Get("cookieurl")

    End Sub
End Class

当部署到iis 6或7时,这不会缓存,但是如果我注释掉它的3个Response.Cookies行.

在VS中运行时,它可以正常工作.

在我设置response.cookies时,iis / web.config等中是否有一些设置允许outputcache.我理解cookie内容将被缓存,它只是缓存的http响应的一部分.

解决方法

在对这个问题进行了一些研究之后,我逐渐理解并解决了这个问题.

输出缓存与cookie不兼容的原因

因此,输出缓存不会使用cookie缓存响应的原因是cookie可能是特定于用户的(例如,身份验证,分析跟踪等).如果一个或多个具有属性HttpCookie.Shareable = false的cookie,则输出缓存会认为响应不可缓存.

包含带缓存响应的cookie

这是它变得棘手的地方.输出缓存将响应头和内容缓存在一起,并且在将它们发送回用户之前不提供任何钩子来修改它们.
但是,我编写了以下自定义输出缓存提供程序,以便在将缓存响应的标头发送回用户之前修改它(需要Fasterflect nuget包):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Web;
using System.Web.Caching;
using Fasterflect;

namespace CustomOutputCache
{
    /// <summary>
    /// An output cache provider that has ability to modify the http header collection before a cached response is served back to the user.
    /// </summary>
    public class HeaderModOutputCacheProvider : OutputCacheProvider
    {
        private static readonly Type OutputCacheEntryType,HttpCachePolicySettingsType;
        private static readonly Type[] ParameterTypes;

        public static event EventHandler<CachedRequestEventArgs> RequestServedFromCache;

        static HeaderModOutputCacheProvider()
        {
            var systemWeb = typeof(HttpContext).Assembly;
            OutputCacheEntryType = systemWeb.GetType("System.Web.Caching.OutputCacheEntry");
            HttpCachePolicySettingsType = systemWeb.GetType("System.Web.HttpCachePolicySettings");
            ParameterTypes = new[]{
                typeof(Guid),HttpCachePolicySettingsType,typeof(string),typeof(string[]),typeof(int),typeof(List<HeaderElement>),typeof(List<ResponseElement>)
            };
        }

        private readonly ObjectCache _objectCache;

        public HeaderModOutputCacheProvider()
        {
            _objectCache = new MemoryCache("output-cache");
        }

        #region OutputCacheProvider implementation

        public override object Get(string key)
        {
            var cachedValue = _objectCache.Get(key);

            if (cachedValue == null)
                return null;

            if (cachedValue.GetType() != OutputCacheEntryType)
                return cachedValue;

            var cloned = CloneOutputCacheEntry(cachedValue);

            if (RequestServedFromCache != null)
            {
                var args = new CachedRequestEventArgs(cloned.HeaderElements);
                RequestServedFromCache(this,args);
            }

            return cloned;
        }

        public override object Add(string key,object entry,DateTime utcExpiry)
        {
            _objectCache.Set(key,entry,new CacheItemPolicy { AbsoluteExpiration = utcExpiry });
            return entry;
        }

        public override void Set(string key,new CacheItemPolicy { AbsoluteExpiration = utcExpiry });
        }

        public override void Remove(string key)
        {
            _objectCache.Remove(key);
        }

        #endregion

        private IOutputCacheEntry CloneOutputCacheEntry(object toClone)
        {
            var parameterValues = new[]
            {
                toClone.GetFieldValue("_cachedVaryId",Flags.InstancePrivate),toClone.GetFieldValue("_settings",toClone.GetFieldValue("_kernelCacheUrl",toClone.GetFieldValue("_dependenciesKey",toClone.GetFieldValue("_dependencies",toClone.GetFieldValue("_statusCode",toClone.GetFieldValue("_statusDescription",CloneHeaders((List<HeaderElement>)toClone.GetFieldValue("_headerElements",Flags.InstancePrivate)),toClone.GetFieldValue("_responseElements",Flags.InstancePrivate)
            };

            return (IOutputCacheEntry)OutputCacheEntryType.CreateInstance(
                parameterTypes: ParameterTypes,parameters: parameterValues
            );
        }

        private List<HeaderElement> CloneHeaders(List<HeaderElement> toClone)
        {
            return new List<HeaderElement>(toClone);
        }
    }

    public class CachedRequestEventArgs : EventArgs
    {
        public CachedRequestEventArgs(List<HeaderElement> headers)
        {
            Headers = headers;
        }
        public List<HeaderElement> Headers { get; private set; }

        public void AddCookies(HttpCookieCollection cookies)
        {
            foreach (var cookie in cookies.AllKeys.Select(c => cookies[c]))
            {
                //more reflection unpleasantness :(
                var header = cookie.CallMethod("GetSetCookieHeader",Flags.InstanceAnyVisibility,HttpContext.Current);
                Headers.Add(new HeaderElement((string)header.GetPropertyValue("Name"),(string)header.GetPropertyValue("Value")));
            }
        }
    }
}

你会像这样连线:

<system.web>
  <caching>
      <outputCache defaultProvider="HeaderModOutputCacheProvider">
        <providers>
          <add name="HeaderModOutputCacheProvider" type="CustomOutputCache.HeaderModOutputCacheProvider"/>
        </providers>
      </outputCache>
    </caching>
  </system.web>

并且可以像这样使用它来插入cookie:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache;

HeaderModOutputCacheProvider.RequestServedFromCache += (sender,e) =>
{
    e.AddCookies(new HttpCookieCollection
    {
        new HttpCookie("key","value")
    });
};

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读