• 使用自定义文件缓存提升ASP.NET项目性能 西安


    前言

      众所周知,各个大型网站为了提升网站访问性能或多或少的都有用一些缓存来提升应用性能,其中最为常用的可能就是生成HTMl页面了,这种方法从某种意义上来说,可以纳入文件缓存的范围里。不过这种做法有一些弊端(对我来说),没有一套完整的HTML文件管理机制,导致大量的HTML代码的管理是件非常头痛的事情。

      我们今天就来讲讲另外一种我们很常用并且很简单的做法,那就是 ASP.NET 的输出缓存 OutputCache

    OutputCache

      对于各位做WEB开发的 Neter 来说,想必OutputCache一定不会陌生了,在 WebForm 中,我们在aspx页面顶端包含 OutputCache 设置 : <%@OutputCache VaryByParam="none"  Duration="10" %>,在 ASP.NET MVC 中,我们在 Controller/ Action 上添加该属性来缓存数据来提升程序性能:

    public class HomeController : Controller
        {
            public ActionResult Index()
            {
                ViewBag.Message = "Welcome to ASP.NET MVC!";
    
                return View();
            }
    
            [OutputCache(Duration = 10, VaryByParam = "none")]
            public ActionResult About()
            {
                return View();
            }
        }

    OutputCache 的缺点

      那么 OutputCache 到底有什么缺点呢?我们都知道 OutputCache 输出缓存是存储在内存中的,也就是说这种做法就已经限定只能用在小型网站中,因为如果我们的网站中包含大量的基于内存的缓存,恐怕会非常消耗主机内存的。

    OutputCache 完善

      鉴于OutputCache 基于内存保存这一问题,我们对 OutputCache 来进行扩展解决这一问题,此时就要用到 .net framework 4 中的 OutputCacheProvider,借助OutputCacheProvider,我们可以有多种选择创建自己的缓存,本节我就来扩展下 OutputCache 来创建自定义文件缓存。

    借助OutputCacheProvider扩展OutputCache创建自定义文件缓存

       创建类:FileCacheProvider,引入 using System.Web.Caching; 命名空间,继承自 OutputCacheProvider 抽象类,重写 四个方法 :

    Add 方法,将指定项插入输出缓存中。
    Get 方法,返回对输出缓存中指定项的引用。
    Remove 方法,从输出缓存中移除指定项。
    Set 方法,将指定项插入输出缓存中,如果该项已缓存,则覆盖该项。

    public class FileCacheProvider : OutputCacheProvider
        {
            public string CachePath { get; set; }
    
            private string ConvertKeyToPath(string key)
            {
                string file = key.Replace('/', '-');
                file += ".txt";
                return Path.Combine(CachePath, file);
            }
    
            public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
            {
                base.Initialize(name, config);
                //读取
                CachePath = HttpContext.Current.Server.MapPath(config["cachePath"]);
            }
    
            public override object Add(string key, object entry, DateTime utcExpiry)
            {
                object obj = Get(key);
                if (obj != null)
                {
                    return obj;
                }
                Set(key, entry, utcExpiry);
                return entry;
            }
    
            public override object Get(string key)
            {
                string path = ConvertKeyToPath(key);
                if (!File.Exists(path))
                {
                    return null;
                }
    
                CacheItem item = null;
                using (FileStream file = File.OpenRead(path))
                {
                    var formatter = new BinaryFormatter();
                    item = (CacheItem)formatter.Deserialize(file);
                }
    
                if (item.ExpiryDate <= DateTime.Now.ToUniversalTime())
                {
                    //log
                    Remove(key);
                    return null;
                }
    
                return item.Item;
            }
    
            public override void Set(string key, object entry, DateTime utcExpiry)
            {
                CacheItem item = new CacheItem(entry, utcExpiry);
    
                string path = ConvertKeyToPath(key);
    
                using (FileStream file = File.OpenWrite(path))
                {
                    BinaryFormatter formatter = new BinaryFormatter();
    
                    formatter.Serialize(file, item);
                }
            }
    
            public override void Remove(string key)
            {
                string path = ConvertKeyToPath(key);
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
            }
        }
    
        [Serializable]
        public class CacheItem
        {
            public DateTime ExpiryDate;
            public object Item;
    
            public CacheItem(object entry, DateTime utcExpiry)
            {
                Item = entry;
                ExpiryDate = utcExpiry;
            }
        }

      实例程序中,我将缓存放在 Config 文件配置的 cachePath 目录中,具体请看 Initialize 方法。

    配置文件

    需要在Web.Config 文件中配置缓存处理程序驱动

     <system.web>
        <caching>
          <outputCache defaultProvider="FileCache">
            <providers>
              <add name="FileCache" type="FileCache.Provider.FileCacheProvider" cachePath="~/Cache"/>
            </providers>
          </outputCache>
        </caching>

    如何使用?

      以上配置好之后,使用就很容易了,因为是对 Asp.NET 输出缓存 OutputCache 进行了扩展,所以使用方式 和之前的用法一样,我在MVC中使用如下:

    namespace FileCache.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                ViewBag.Message = "Welcome to ASP.NET MVC!";
    
                return View();
            }
    
            [OutputCache(Duration = 10, VaryByParam = "none")]
            public ActionResult About()
            {
                return View();
            }
        }
    }

    可以看到,我在 About Action 上打缓存标记 [OutputCache(Duration = 10, VaryByParam = "none")] ,设置缓存时间10分钟,并且不根据任何参数重新缓存,运行,可以再配置好的 Cache 文件下看到缓存文件:

      运行程序后,访问 About 页面,将会看到在Cache文件夹产生了缓存文件。

    注意事项

      我是在项目中提前创建好了 Cache 文件夹,当然这个文件夹名称可以随便取了,只需要在 Web.Config 映射正确即可,如果您运行报错,可能是由于该文件夹不存在,或者您可以再 缓存扩代码中判断一下是否存在 Cache 文件夹,没有则程序创建即可。

    遗留问题

      以上我们可以看到是将缓存文件保存成 txt 文本,那么我们是否可以将其保存为xml 格式文件以及哪种格式性能好呢?如果选用 xml ,可以进一步修改使用泛型类来解决 不同对象的xml序列化问题。若您有更好的建议,不妨提出。

  • 相关阅读:
    牛客网 剑指Offer JZ16 合并两个排序的链表
    牛客网 剑指Offer JZ15 反转链表
    牛客网 剑指Offer JZ14 链表中倒数最后k个结点
    牛客网 剑指Offer JZ12 数值的整数次方 经典快速幂
    牛客网 剑指offer-JZ10 矩形覆盖
    牛客网 剑指offer-JZ9 跳台阶扩展问题
    牛客网 剑指offer-JZ8 跳台阶
    牛客网 剑指offer-JZ7 斐波那契数列
    牛客网 剑指offer-JZ6 旋转数组的最小数字
    codility_ BinaryGap
  • 原文地址:https://www.cnblogs.com/zhouzhaokun/p/3105504.html
Copyright © 2020-2023  润新知