zoukankan      html  css  js  c++  java
  • Asp.Net 4.0 新特性之 使用自定义OutputCache Provider

    在Asp.Net 4.0 的web.config文件中添加了关于缓存的配置节,如下所示:

      <system.web>
        <compilation debug="true" targetFramework="4.0" />
        <caching>
          <outputCache defaultProvider="SmartOutputCache">
            <providers>
              <add name="SmartOutputCache" type="OutputCacheTest.Caching.SmartOutputCacheProvider" 
                   memoryCacheLimit="00:30:00"
                   />
            </providers>
          </outputCache>
        </caching>
      </system.web>
    

    我们可以在Web.config中配置自定义的OutputCacheProvider,并将自定义Provider指定为默认的Provider。

    1.自定义OutputCacheProvider需要实现System.Web.Cacheing. OutputCacheProvider抽象类,网上有很多例子都用文件缓存做例子。这个例子太俗了,我写了一个新的例子,在设置的缓存时间小于指定阀值时,缓存到HttpRuntime.Cache中,否则缓存到文件中,如下代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Caching;
    using System.Xml.Serialization;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace OutputCacheTest.Caching
    {
        /// <summary>
        /// OutputCache精灵,如果缓存时间小于设置时间时则缓存到内存,否则缓存到文件
        /// </summary>
        public class SmartOutputCacheProvider : OutputCacheProvider
        {
            private const string KEY_PREFIX = "__outputCache_";
    
            /// <summary>
            /// 初始化SmartOutputCacheProvider,读取配置文件中配置的MemoryCacheLimit和FileCacheRoot的值
            /// </summary>
            /// <param name="name">provider名字</param>
            /// <param name="config">配置</param>
            public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
            {
                string memoryLimit = config["memoryCacheLimit"];
                if (memoryLimit == null)
                {
                    MemoryCacheLimit = new TimeSpan(0, 30, 0);
                }
                else
                {
                    MemoryCacheLimit = TimeSpan.Parse(memoryLimit);
                }
    
                string fileCacheRoot = config["fileCachRoot"];
                if (string.IsNullOrEmpty(fileCacheRoot))
                {
                    fileCacheRoot = AppDomain.CurrentDomain.BaseDirectory + "cache\\";
                }
                this.FileCacheRoot = fileCacheRoot;
                base.Initialize(name, config);
            }
    
            /// <summary>
            /// 添加缓存
            /// </summary>
            /// <param name="key">缓存的键,key的值是有asp.net内部生成的</param>
            /// <param name="entry">缓存的对象</param>
            /// <param name="utcExpiry">过期时间</param>
            /// <returns>返回缓存值</returns>
            public override object Add(string key, object entry, DateTime utcExpiry)
            {
                Set(key, entry, utcExpiry);
                return entry;
            }
    
            /// <summary>
            /// 处理缓存键值,防止在文件缓存时出现文件路径不允许的字符
            /// </summary>
            /// <param name="key">缓存键</param>
            /// <returns>处理后的键</returns>
            private string ProcessKey(string key)
            {
                return KEY_PREFIX + System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(key, "MD5");
            }
    
            /// <summary>
            /// 返回缓存文件的物理路径
            /// </summary>
            /// <param name="processedKey">处理后的键</param>
            /// <returns>物理路径</returns>
            private string GetFilePath(string processedKey)
            {
                return Path.Combine(FileCacheRoot, processedKey + ".data");
            }
    
            /// <summary>
            /// 获得缓存值,如果在HttpRuntime.Cache中有则直接读取内存中的值,否则从文件读取
            /// </summary>
            /// <param name="key">缓存键</param>
            /// <returns>缓存值</returns>
            public override object Get(string key)
            {
                string processedKey = ProcessKey(key);
    
                CacheDataWithExpiryTimeUtc result = HttpRuntime.Cache[processedKey] as CacheDataWithExpiryTimeUtc;
                if (result == null)
                {
                    string path = GetFilePath(processedKey);
                    if (!File.Exists(path))
                        return null;
    
                    using (FileStream file = File.OpenRead(path))
                    {
                        var formatter = new BinaryFormatter();
                        result = (CacheDataWithExpiryTimeUtc)formatter.Deserialize(file);
                    }
                }
    
                if (result == null || result.ExpiryTimeUtc <= DateTime.UtcNow)
                {
                    Remove(key);
                    return null;
                }
                return result.Data;
            }
    
            /// <summary>
            /// 根据键移除缓存
            /// </summary>
            /// <param name="key">缓存键</param>
            public override void Remove(string key)
            {
                string processedKey = ProcessKey(key);
                HttpRuntime.Cache.Remove(processedKey);
                string path = GetFilePath(processedKey);
                if (!File.Exists(path))
                    File.Delete(path);
            }
    
            /// <summary>
            /// 设置缓存
            /// </summary>
            /// <param name="key">缓存键</param>
            /// <param name="entry">缓存内容</param>
            /// <param name="utcExpiry">过期时间</param>
            public override void Set(string key, object entry, DateTime utcExpiry)
            {
                TimeSpan ts = utcExpiry - DateTime.UtcNow;
                string processedKey = ProcessKey(key);
    
                CacheDataWithExpiryTimeUtc cacheItem = new CacheDataWithExpiryTimeUtc
                {
                    Data = entry,
                    ExpiryTimeUtc = utcExpiry
                };
    
                if (ts <= MemoryCacheLimit)
                {
                    HttpRuntime.Cache.Insert(processedKey, cacheItem, null, utcExpiry.ToLocalTime(), TimeSpan.Zero);
                }
                else
                {
                    string cacheFilePath = GetFilePath(processedKey);
                    
                    using (var fs = new FileStream(cacheFilePath,FileMode.OpenOrCreate,FileAccess.ReadWrite))
                    {
                        var formatter = new BinaryFormatter();
                        formatter.Serialize(fs, cacheItem);
                    }
                }
            }
    
            /// <summary>
            /// 如果缓存设定的时间超过此值则缓存到文件中,否则在HttpRuntime.Cache中做缓存
            /// </summary>
            [XmlAttribute("memoryCacheLimit")]
            public TimeSpan MemoryCacheLimit { get; set; }
    
    
            /// <summary>
            /// 文件缓存的根目录,可以指定任何可访问目录
            /// </summary>
            [XmlAttribute("fileCacheRoot")]
            public string FileCacheRoot { get; set; }
        }
    
        /// <summary>
        /// 对缓存数据和缓存的过期时间的封装
        /// </summary>
        [Serializable]
        internal class CacheDataWithExpiryTimeUtc
        {
            public object Data { get; set; }
    
            public DateTime ExpiryTimeUtc { get; set; }
        }
    }
    

    2.如何使用自定义的OutputCacheProvider

      1)在配置文件中做配置,将自定义的实现作为默认输出缓存支持,请看文章开始的配置
      2)在UserControl中指定使用Provider的名字,改名字在web.config中定义,例如

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="IamUserControl.ascx.cs" Inherits="OutputCacheTest.IamUserControl" %>
    <%@ OutputCache Duration="3000" ProviderName="AspNetInternalProvider" VaryByParam="None" %>
    
    

      需要注意的是,只能在UserControl中指定Provider的名字,在Page的生明中是不允许的,在Page中默认情况会使用web.config中配置的defaultProvider,但是我们可以通过3)中介绍的方法给不同的页面使用不同的OutputCacheProvider实现。

      3)在Global.asax文件中重写GetOutputCacheProviderName(HttpContext context)方法,根据context返回不同的实现名字,如下例子

    public override string GetOutputCacheProviderName(HttpContext context)
    {
        if (context.Request.Path.StartsWith("/default.aspx",StringComparison.CurrentCultureIgnoreCase))
        {
            return "AspNetInternalProvider";
        }
                
        return base.GetOutputCacheProviderName(context);
    }
    

    总结:
    可扩展的OutputCache为我们提供了无限的可能,我们可以根据需要扩展OutputCache,例如把OutputCache存储到Memcached server或者其他键值对数据存储中,从而使程序的性能达到最优的情况。

    请注意:本文举例中的代码仅为示例代码,实际应用中需要考虑很多因素。

    示例代码下载

    Asp.net 新特性相关阅读:

    1. 从页面标记<%%>说起
    2. Asp.Net 4.0 中可以用自定义的Provider做OutputCache 了
    3. SEO增强支持MetaKeywords,和MetaDescription,RedirectPermanant
    4. SEO增强之URL Routing
    5. 输出更纯净的Html代码,ViewStateMode和ClientIDMode,CheckBoxList等

  • 相关阅读:
    04_web基础(六)之请求转发与重定向
    04_web基础(五)之cookie与session
    04_web基础(四)之servlet详解
    04_web基础(三)之进一步理解web
    04_web基础(二)之web构建
    本地密码提取工具-LAZAGNE
    免杀工具汇总
    流量取证-提取文件
    CA证书安装以及sslh协议转发
    ssh 端口转发
  • 原文地址:https://www.cnblogs.com/yukaizhao/p/asp_net_40_new_feature_outputcacheprovider.html
Copyright © 2011-2022 走看看