PetShop之ASP.NET缓存

By admin in mobile.365-838.com on 2019年1月15日

“你就只会平生抱怨工作、低待遇和首席执行官娘,你终其一生希望有个大机会可以把你持有的钱的题目都解决。”

学学怎么样让钱为你工作是一个不止终生的经过。

《解剖PetShop》连串之四

一、你精晓过财商教育这门学科吗?

自幼学到高中,老师上课教的都是何等必考知识,如何将考试战表提升多少分,家长念叨的都是在母校听先生来说,专心读书。读大学时,除了讲解,参与社团等,我顶多做做全职赚钱零花钱,闲暇时间在宿舍煲剧,和情侣吃吃逛逛。等到插手工作几年后才意识,我们的母校和家庭教育严重缺失人生中很要紧的一课-财商教育。

在工作四年后自己才察觉到,存钱和理财不是富人才做的业务,也不是等成家立业才起头做的事务。

在看完罗伯特(Robert)(Bert)*清崎的名作《富岳父穷五叔》后,我的资财观彻底改变了。往日的自我崇尚稳定,对于炒股和理财以及任何投资持怀疑态度,觉得做好本职工作,专心进步自己的干活技巧才是必不可缺,我们不应该耗费精力在任何的“旁门左道”。而富二叔穷二伯这本书告诉大家

钱是一种力量,但更有能力的事财商教育。钱来了又会去,但假设您了然钱是何等运动的,你就获取了驾驶它的力量,就能初叶积累财富了。大多数人光想不干,原因是她们在经受学校带领时并从未控制钱的移位规律,所以她们终生都在为钱办事。

就像我们父母辈的人,大多数都有存钱的价值观,可是又不够运作钱的价值观及能力,所以他们一生都在存钱,很难有大富大贵的火候。由于此前从未接触过股票、理财,这一个概念仿佛只设有于电视节目或杂志上,离自己很遥远。可当你接触到的人越多,你越发现光靠每个月的工资收入是很难较大程度上改进自己的活着或者实现自己的钱财目的。

四 PetShop之ASP.NET缓存

二、你“开源节流”了啊?

在北上广深这样的大城市,一个惯常白领的薪资在扣除房租水电费以及最焦点的平凡支付后也所剩寥寥。前两天和共事聊天,以过来人的地方告诉她存钱要趁早,然后她告知我多年来交了女对象,开销大,完全没有设想过存钱这回事。像她这么的有那个人,觉得每个月存不下钱,而存几百块没有很大的意义,因为在大城市都买不起一块砖。这种看法就是不对的。在那种情状下也急需去培训一种存钱的习惯,学习咋样去管理自己的资财。

大家得以从节俭这4个字去出手。

第一,节流意味着大家需要节约一些不必要的开发,你以为你胡吃海喝,不加节制的购物等是过得潇洒,其实只是是在挥霍你本能够创造的美好未来。当你忍不住想喝一杯几十块的奈雪、喜茶或星Buck时,想想你少喝一杯就可以为你的储蓄目标进献一部分。

Compound interest is the eighth wonder of the world
复合利息简直是世界的第八大奇迹。

开源则告诉我们,要想实现财富自由,光靠工资是几乎不可行的。身边的人有投资虚拟币的,有写小说的,有做自媒体的,还有一道开旅馆的。大家一概寻求多种门道开源从而拿到更多入账。死死的守住一份工资收入已经完全落伍了。

从现行先河,好好分析自己可以从哪些方面拓宽收入渠道,其次每个月稳定从友好的工薪中存下一笔钱,不论多少。只有当您跨出了存钱的率先步,你才能有接下去的第二步,第三步。

若果对微型电脑硬件系统有丰硕的垂询,那么大家对此Cache这么些名词一定是驾轻就熟的。在CPU以及主板的芯片中,都引入了这种名为高速缓冲存储器(Cache)的技艺。因为Cache的存取速度比内存快,由此引入Cache可以有效的化解CPU与内存之间的进度不兼容问题。硬件系统能够运用Cache存储CPU访问概率高的这么些数据,当CPU需要拜访这多少个数量时,可以直接从Cache中读取,而毋庸访问存取速度绝对较慢的内存,从而提升了CPU的工作功用。软件设计借鉴了硬件设计中引入缓存的建制以革新整个系统的属性,尤其是对此一个数据库驱动的Web应用程序而言,缓存的施用是必要的,毕竟,数据库查询可能是百分之百Web站点中调用最频繁但同时又是履行最缓慢的操作之一,我们不可以被它老迈的双腿拖缓我们前行的征途。缓存机制正是解决这一欠缺的加速器。

三、你还地处“老鼠赛跑”阶段呢?

这里我一向引用富公公的一段很经典的话

大多数人都希望有一份工资收入,因为他俩都有恐怖和贪欲之心。一开始,没钱的恐惧会促使他们奋力干活,拿到酬金后,贪婪或私欲又让他们想拥有用钱能买到的好东西。于是就形成了一种情势。起床,上班,付账,再起床,再上班,再付账。他们的生存被这三种感觉所主宰:恐惧和贪婪。给他俩跟多的钱,他们就会以更高的开发重复这种循。这就是自己所说的“老鼠赛跑”。

职场上的人还会幻想跳槽能迎刃而解一切金钱问题。他们会辞职,然后找份新工作,期望获取更好的火候和待遇。不过跳槽并不一定能给你带来更多的进项,而且伴随着更多低收入,假若你没有作育好的财商,你的获益最后依然流出了账户,未能形成良性循环,带来更多的财力入账。

投资理财这一个娱乐,假若您还未初始,就表示明天的你已经落伍于外人了。

4.1  ASP.NET缓存概述

小结:富二叔给大家的提议

  • 始于关注您自己的事业,在连续工作的同时购买部分房地产,而毫不买负债或是一旦被你带回家就从未有过价值的个人用品。在您把一辆新车开出停车场的还要,它已经贬值25%了。

  • 从理财的角度来说,我们每挣到一港币,就赢得了三次选拔自己是变成有钱人、穷人依旧中产阶级的机会。我们花钱的习惯反映了大家是哪些的人,穷人之所以贫穷是因为他们有不行的消费习惯。

  • 罗伯特(Robert)(Bert)想告知人们的是,任何人都能学有所成-只要他们采取这样做。明日及时你是一个花匠或是看门人居然是失业者,你仍有能力自我教育和教您所爱的人关注他们本身的财务境况。要铭记,财商是在解决财务问题的长河中磨砺出来的。

作为.Net框架下支付Web应用程序的主打产品,ASP.NET丰裕考虑了缓存机制。通过某种格局,将系统需要的数额对象、Web页面存储在内存中,使得Web站点在急需拿到这多少个多少时,不需要通过繁琐的数据库连接、查询和复杂性的逻辑运算,就可以“触手可及”,如“不费吹灰之力”般容易而高速,从而加强整个Web系统的特性。

ASP.NET提供了二种为主的缓存机制来提供缓存效率。一种是应用程序缓存,它同意开发者将先后生成的数码或报表工作对象放入缓存中。另外一种缓存机制是页输出缓存,利用它,能够平昔拿到存放在缓存中的页面,而不需要通过繁杂的对该页面的重新拍卖。

应用程序缓存其促成原理说来平淡无奇,仅仅是由此ASP.NET管理内存中的缓存空间。放入缓存中的应用程序数据对象,以键/值对的措施存储,这便于用户在访问缓存中的数据项时,可以遵照key值判断该项是否留存缓存中。

放入在缓存中的数据对象其生命周期是遭受限制的,即使在全方位应用程序的生命周期里,也无法确保该多少对象一向有效。ASP.NET可以对应用程序缓存举办田间管理,例如当数码项无效、过期或内存不足时移除它们。其它,调用者还足以经过CacheItemRemovedCallback委托,定义回调方法使得数据项被移除时可以通告用户。

在.Net
Framework中,应用程序缓存通过System.Web.Caching.Cache类实现。它是一个密封类,无法被连续。对于每一个行使程序域,都要开创一个Cache类的实例,其生命周期与使用程序域的生命周期保持一致。我们得以接纳Add或Insert方法,将数据项添加到应用程序缓存中,如下所示:
Cache[“First”] = “First Item”;
Cache.Insert(“Second”, “Second Item”);

咱俩还足以为应用程序缓存添加倚重项,使得看重项发生改变时,该数量项可以从缓存中移除:
string[] dependencies = {“Second”};
Cache.Insert(“Third”, “Third Item”,
new System.Web.Caching.CacheDependency(null, dependencies));

与之对应的是缓存中数据项的移除。后边提到ASP.NET可以自动管理缓存中项的移除,但我们也得以透过代码编写的艺术显式的移除相关的多少项:
Cache.Remove(“First”);

相对于应用程序缓存而言,页输出缓存的接纳越来越普遍。它能够通过内存将处理后的ASP.NET页面存储起来,当客户端再两遍访问该页面时,可以节省页面处理的长河,从而加强页面访问的性质,以及Web服务器的吞吐量。例如,在一个电子商务网站里,用户需要平常查询商品消息,那些进程会波及到数据库访问以及查找条件的非凡,在数据量较大的图景下,如此的寻找过程是相比耗时的。此时,利用页输出缓存就足以将第一次搜索得到的询问结果页存储在缓存中。当用户第二次询问时,就足以节约数据查询的长河,收缩页面的响应时间。

页输出缓存分为整页缓存和一些页缓存。我们可以透过@OutputCache指令完成对Web页面的出口缓存。它至关紧要包含两个参数:Duration和VaryByParam。Duration参数用于安装页面或控件举办缓存的时光,其单位为秒。如下的安装表示缓存在60秒内有效:
<%@ OutputCache Duration=“60“ VaryByParam=“none“ %>

如若没有超过Duration设置的年限值,当用户访问同一的页面或控件时,就足以一贯在缓存中拿走。
接纳VaryByParam参数可以依照设置的参数值建立不同的缓存。例如在一个出口天气预报结果的页面中,假诺急需为一个ID为txtCity的TextBox控件建立缓存,其值将突显某都会的气温,那么我们得以拓展如下的设置:
<%@ OutputCache Duration=”60” VaryByParam=”txtCity” %>

如此一来,ASP.NET会对txtCity控件的值举办判断,唯有输入的值与缓存值相同,才从缓存中取出相应的值。这就立竿见影地避免了因为值的例外而造成出口错误的数量。

利用缓存的编制对性能的升迁相当引人注目。通过ACT(Application Center
Test)的测试,可以发现安装缓存后实施的性能比未设置缓存时的习性足足增强三倍多。

引入缓存看来是增长性能的“完美”解决方案,可是“金无足赤,人无完人”,缓存机制也有欠缺,这就是数码过期的题目。一旦应用程序数据或者页面结果值暴发的变更,那么在缓存有效期范围内,你所收获的结果将是逾期的、不可靠的数据。大家得以想一想股票系统使用缓存所带动的灾难,当您利用错误过期的数目去分析股市的变幻莫测时,你会意识赢得的结果真可以说是“失之毫厘,谬以千里”,看似大好的局面就会像漂亮的泡泡一样,用针一戳,转眼就消失得没有。

那么我们是不是应该为了追求高性能,而不顾所谓“数据过期”所带动的隐患呢?显著,在相近于股票系统这种数量更新往往的特定情景下,数据过期的不佳表现依然比低效的属性更让人难以接受。故而,大家需要在性质与数码科学性间作出权衡。所幸的是,.Net
Framework
2.0引入了一种新的缓存机制,它为我们的“鱼与熊掌兼得”带来了技能上的取向。

.Net 2.0引入的自定义缓存倚重项,特别是依据MS-SQL
Server的SqlCacheDependency特性,使得我们可以避免“数据过期”的题目,它亦可基于数据库中相应数据的生成,通知缓存,并移除这个过期的数码。事实上,在PetShop
4.0中,就充分地运用了SqlCacheDependency特性。

4.2 SqlCacheDependency特性

SqlCacheDependency特性实际上是经过System.Web.Caching.SqlCacheDependency类来反映的。通过此类,可以在具备帮忙的SQL
Server版本(7.0,2000,2005)上监视特定的SQL
Server数据库表,并成立依赖于该表以及表中数据行的缓存项。当数据表或表中特定行的数据发生变更时,具有倚重项的数量项就会失效,并自行从Cache中删去该项,从而确保了缓存中不再保留过期的数码。
出于版本的案由,SQL Server 2005全然扶助SqlCacheDependency特性,但对此SQL
Server 7.0和SQL Server
2000而言,就从未有过这么幸运了。毕竟这多少个产品出现在.Net Framework
2.0事先,因而它并从未实现活动监视数据表数据变化,通告ASP.NET的效应。解决的主意就是接纳轮询机制,通过ASP.NET进程内的一个线程以指定的年华间隔轮询SQL
Server数据库,以跟踪数据的成形境况。

要使得7.0依然2000版本的SQL
Server襄助SqlCacheDependency特性,需要对数据库服务器执行有关的配置步骤。有二种形式配置SQL
Server:使用aspnet_regsql命令行工具,或者利用SqlCacheDependencyAdmin类。

4.2.1  利用aspnet_regsql工具

aspnet_regsql工具位于Windows\Microsoft.NET\Framework\[版本]文本夹中。假如直接双击该工具的举行文书,会弹出一个指导对话框,提醒我们做到相应的操作:

图片 1
图4-1 aspnet_regsql工具

如图4-1所示中的指示消息,表明该引路首要用来配置SQL
Server数据库,如membership,profiles等音讯,假诺要配备SqlCacheDependency,则需要以命令行的主意执行。以PetShop
4.0为例,数据库名为MSPetShop4,则下令为:
aspnet_regsql -S localhost -E -d MSPetShop4 -ed

以下是该工具的授命参数表明:
-?  展现该工具的帮扶意义;
-S  后接的参数为数据库服务器的名目或者IP地址;
-U  后接的参数为数据库的登陆用户名;
-P  后接的参数为数据库的登陆密码;
-E  当使用windows集成验证时,使用该意义;
-d  后接参数为对哪一个数据库接纳SqlCacheDependency功用;
-t  后接参数为对哪一个表采纳SqlCacheDependency效率;
-ed  允许对数据库使用SqlCacheDependency效率;
-dd  禁止对数据库采取SqlCacheDependency功能;
-et  允许对数据表采取SqlCacheDependency功用;
-dt  禁止对数据表采取SqlCacheDependency效能;
-lt  列出脚下数据库中有怎样表已经应用sqlcachedependency效能。

以地点的通令为例,表明将对名为MSPetShop4的数据库选取SqlCacheDependency效用,且SQL
Server选拔了windows集成验证措施。我们仍可以够对相关的数据表执行aspnet_regsql命令,如:
aspnet_regsql -S localhost -E -d MSPetShop4 -t Item -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Product -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Category -et

当执行上述的四条命令后,aspnet_regsql工具会在MSPetShop4数据库中确立一个名为AspNet_SqlCacheTablesForChangeNotification的新数据库表。该数据表包含两个字段。字段tableName记录要追踪的数据表的名称,例如在PetShop
4.0中,要记录的数据表就概括Category、Item和Product。notificationCreated字段记录最先追踪的时光。changeId作为一个档次为int的字段,用于记录数据表数据暴发变化的次数。如图4-2所示:

图片 2
图4-2 AspNet_SqlCacheTablesForChangeNotification数据表

除开,执行该命令还会为MSPetShop4数据库添加一组存储过程,为ASP.NET提供查询追踪的数据表的事态,同时还将为运用了SqlCacheDependency的表添加触发器,分别对应Insert、Update、Delete等与数量变动相关的操作。例如Product数据表的触发器:
CREATE TRIGGER dbo.[Product_AspNet_SqlCacheNotification_Trigger] ON
[Product]
    FOR INSERT, UPDATE, DELETE AS BEGIN
    SET NOCOUNT ON
    EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure N’Product’
END

其中,AspNet_SqlCacheUpdateChangeIdStoredProcedure即是工具添加的一组存储过程中的一个。当对Product数据表执行Insert、Update或Delete等操作时,就会激活触发器,然后实施AspNet_SqlCacheUpdateChangeIdStoredProcedure存储过程。其执行的经过就是修改AspNet_SqlCacheTablesForChangeNotification数据表的changeId字段值:
CREATE PROCEDURE dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure
             @tableName NVARCHAR(450)
         AS
         BEGIN
             UPDATE dbo.AspNet_SqlCacheTablesForChangeNotification WITH
(ROWLOCK) SET changeId = changeId + 1
             WHERE tableName = @tableName
         END  
GO

4.2.2  利用SqlCacheDependencyAdmin类

我们也得以行使编程的章程来来管理数据库对SqlCacheDependency特性的行使。该类包含了六个重大的艺术:

DisableNotifications 为特定数据库禁用 SqlCacheDependency对象更改通知
DisableTableForNotifications 为数据库中的特定表禁用SqlCacheDependency对象更改通知
EnableNotifications 为特定数据库启用SqlCacheDependency对象更改通知
EnableTableForNotifications 为数据库中的特定表启用SqlCacheDependency对象更改通知
GetTablesEnabledForNotifications 返回启用了SqlCacheDependency对象更改通知的所有表的列表

表4-1 SqlCacheDependencyAdmin类的要害情势

假如大家定义了如下的数据库连接字符串:
const string connectionStr = “Server=localhost;Database=MSPetShop4”;

那么为数据库MSPetShop4启用SqlCacheDependency对象更改文告的兑现为:
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
   {
       SqlCacheDependencyAdmin.EnableNotifications(connectionStr);
   }
}

为数据表Product启用SqlCacheDependency对象更改通告的落实则为:
SqlCacheDependencyAdmin.EnableTableForNotifications(connectionStr,
“Product”);

只要要调用表4-1中所示的相关方法,需要专注的是访问SQL
Server数据库的帐户必须怀有创造表和存储过程的权杖。假如要调用EnableTableForNotifications方法,还需要拥有在该表上创建SQL
Server触发器的权力。

即使说编程情势给予了程序员更大的油滑,但aspnet_regsql工具却提供了更简单的措施实现对SqlCacheDependency的布局与治本。PetShop
4.0应用的难为aspnet_regsql工具的方法,它编写了一个文本名为InstallDatabases.cmd的批处理公事,其中涵盖了对aspnet_regsql工具的推行,并通过安装程序去调用该公文,实现对SQL
Server的配置。

4.3 在PetShop 4.0中ASP.NET缓存的落实

PetShop作为一个B2C的宠物网上商店,需要丰裕考虑访客的用户体验,假诺因为数据量大而导致Web服务器的响应不立时,页面和查询数据迟迟得不到结果,会由此而损坏客户走访网站的心情,在耗尽耐心的等候后,可能会失掉这一部分客户。无疑,这是老大不佳的结果。由此在对其开展系统架构设计时,整个连串的性能就呈现殊为首要。不过,我们不可能因噎废食,因为在意于性能而忽视数据的不易。在PetShop
3.0本子以及从前的版本,因为ASP.NET缓存的局限性,这一题材并不曾到手很好的缓解。PetShop
4.0则引入了SqlCacheDependency特性,使得系统对缓存的拍卖相比较在此以前大为改观。

4.3.1  CacheDependency接口

PetShop
4.0引入了SqlCacheDependency特性,对Category、Product和Item数据表对应的缓存举行了SQL
Cache
Invalidation技术。当对应的数据表数据暴发变动后,该技术可以将有关项从缓存中移除。实现这一技术的基本是SqlCacheDependency类,它继续了CacheDependency类。可是为了保证一切架构的可扩充性,我们也允许设计者建立自定义的CacheDependency类,用以扩张缓存依赖。这就有必要为CacheDependency建立抽象接口,并在web.config文件中展开安排。

在PetShop
4.0的命名空间PetShop.ICacheDependency中,定义了名为IPetShopCacheDependency接口,它仅包含了一个接口方法:
public interface IPetShopCacheDependency
{      
    AggregateCacheDependency GetDependency();
}

AggregateCacheDependency是.Net Framework
2.0新增的一个类,它担负监视依赖项对象的联谊。当以此集合中的任意一个借助项对象爆发变动时,该依赖项对象对应的缓存对象都将被自动移除。
AggregateCacheDependency类起到了咬合CacheDependency对象的效能,它可以将多少个CacheDependency对象竟然不同类型的CacheDependency对象与缓存项建立关联。由于PetShop需要为Category、Product和Item数据表建立倚重项,由此IPetShopCacheDependency的接口方法GetDependency()其目的就是回去建立了这一个倚重项的AggregateCacheDependency对象。

4.3.2  CacheDependency实现

CacheDependency的落实正是为Category、Product和Item数据表建立了相应的SqlCacheDependency类型的依靠项,如代码所示:
public abstract class TableDependency : IPetShopCacheDependency
{
    // This is the separator that’s used in web.config
    protected char[] configurationSeparator = new char[] { ‘,’ };

    protected AggregateCacheDependency dependency = new
AggregateCacheDependency();
    protected TableDependency(string configKey)
    {
        string dbName =
ConfigurationManager.AppSettings[“CacheDatabaseName”];
        string tableConfig =
ConfigurationManager.AppSettings[configKey];
        string[] tables = tableConfig.Split(configurationSeparator);

        foreach (string tableName in tables)
            dependency.Add(new SqlCacheDependency(dbName, tableName));
    }
    public AggregateCacheDependency GetDependency()
   {
        return dependency;
    }
}

亟待树立倚重项的数据库与数量表都配置在web.config文件中,其安装如下:
<add key=”CacheDatabaseName” value=”MSPetShop4″/>
<add key=”CategoryTableDependency” value=”Category”/>
<add key=”ProductTableDependency” value=”Product,Category”/>
<add key=”ItemTableDependency” value=”Product,Category,Item”/>

按照各类数据表间的借助关系,由此不同的数据表需要建立的依赖性项也是不一样的,从部署文件中的value值可以见见。然则无论建立依赖项的数量,其创建的一言一行逻辑都是一般的,因此在统筹时,抽象了一个合办的类TableDependency,并由此确立带参数的构造函数,完成对依赖项的建立。由于接口方法GetDependency()的兑现中,重临的目标dependency是在受保障的构造函数创制的,由此这里的落实格局也可以看作是Template
Method模式的灵活运用。例如TableDependency的子类Product,就是使用父类的构造函数建立了Product、Category数据表的SqlCacheDependency依赖:
public class Product : TableDependency
{
    public Product() : base(“ProductTableDependency”) { }
}

假设需要自定义CacheDependency,那么创造看重项的主意又有不同。不过无论是创立SqlCacheDependency对象,仍然自定义的CacheDependency对象,都是将这一个倚重项添加到AggregateCacheDependency类中,因此我们也得以为自定义CacheDependency建立专门的类,只要实现IPetShopCacheDependency接口即可。

4.3.3  CacheDependency工厂

后续了抽象类TableDependency的Product、Category和Item类均需要在调用时创制各自的靶子。由于它们的父类TableDependency实现了接口IPetShopCacheDependency,由此它们也直接实现了IPetShopCacheDependency接口,这为兑现工厂形式提供了前提。

在PetShop
4.0中,如故选拔了布置文件和反光技术来贯彻工厂格局。命名空间PetShop.CacheDependencyFactory中,类DependencyAccess即为创制IPetShopCacheDependency对象的厂子类:
public static class DependencyAccess
{       
    public static IPetShopCacheDependency CreateCategoryDependency()
    {
        return LoadInstance(“Category”);
    }
    public static IPetShopCacheDependency CreateProductDependency()
    {
        return LoadInstance(“Product”);
    }
    public static IPetShopCacheDependency CreateItemDependency()
    {
        return LoadInstance(“Item”);
    }
    private static IPetShopCacheDependency LoadInstance(string
className)
    {
        string path =
ConfigurationManager.AppSettings[“CacheDependencyAssembly”];
        string fullyQualifiedClass = path + “.” + className;
        return
(IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
    }
}
成套工厂格局的实现如图4-3所示:

图片 3
 图4-3 CacheDependency工厂

即使DependencyAccess类成立了贯彻了IPetShopCacheDependency接口的类Category、Product、Item,可是我们由此引入IPetShopCacheDependency接口,其指标就在于获取创立了依靠项的AggregateCacheDependency类型的目标。我们可以调用对象的接口方法GetDependency(),如下所示:
AggregateCacheDependency dependency =
DependencyAccess.CreateCategoryDependency().GetDependency();

为了方便调用者,似乎我们得以对DependencyAccess类举行改良,将本来的CreateCategoryDependency()方法,修改为创制AggregateCacheDependency类型对象的格局。

不过这样的做法扰乱了作为工厂类的DependencyAccess的自我职责,且创立IPetShopCacheDependency接口对象的一言一行依旧有可能被调用者调用,所以保留原来的DependencyAccess类依然是有必不可少的。

在PetShop
4.0的统筹中,是透过引入Facade格局以方便调用者更加简便易行地收获AggregateCacheDependency类型对象。

4.3.4  引入Facade模式

接纳Facade情势可以将部分犬牙交错的逻辑举行打包,以福利调用者对这多少个扑朔迷离逻辑的调用。就接近提供一个合并的伪装一般,将内部的子系统封装起来,统一为一个高层次的接口。一个超人的Facade模式示意图如下所示:

图片 4
图4-4 Facade模式

Facade形式的目的决不要引入一个新的机能,而是在存活功效的基础上提供一个更高层次的悬空,使得调用者可以直接调用,而不用关爱内部的落实模式。以CacheDependency工厂为例,我们需要为调用者提供获得AggregateCacheDependency对象的便民方法,因此创设了DependencyFacade类:
public static class DependencyFacade
{
    private static readonly string path =
ConfigurationManager.AppSettings[“CacheDependencyAssembly”];
    public static AggregateCacheDependency GetCategoryDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateCategoryDependency().GetDependency();
        else
            return null;
    }
    public static AggregateCacheDependency GetProductDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateProductDependency().GetDependency();
        else
            return null;
        }
    public static AggregateCacheDependency GetItemDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateItemDependency().GetDependency();
        else
            return null;
    }
}

DependencyFacade类封装了收获AggregateCacheDependency类型对象的逻辑,如此一来,调用者可以调用相关方法赢得创立连锁依赖项的AggregateCacheDependency类型对象:
AggregateCacheDependency dependency =
DependencyFacade.GetCategoryDependency();

比起素来调用DependencyAccess类的GetDependency()方法而言,除了艺术更简短之外,同时它还对CacheDependencyAssembly配置节举办了判断,假诺其值为空,则赶回null对象。

在PetShop.Web的App_Code文件夹下,静态类WebUtility的GetCategoryName()和GetProductName()方法调用了DependencyFacade类。例如GetCategoryName()方法:
public static string GetCategoryName(string categoryId)
{
     Category category = new Category();
     if (!enableCaching)
            return category.GetCategory(categoryId).Name;

     string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);

     // 检查缓存中是不是存在该多少项;
     string data = (string)HttpRuntime.Cache[cacheKey];
     if (data == null)
     {
           // 通过web.config的布置获取duration值;
           int cacheDuration =
int.Parse(ConfigurationManager.AppSettings[“CategoryCacheDuration”]);
           //
假如缓存中不设有该数据项,则通过工作逻辑层访问数据库获取;
           data = category.GetCategory(categoryId).Name;
           // 通过Facade类创建AggregateCacheDependency对象;
           AggregateCacheDependency cd =
DependencyFacade.GetCategoryDependency();
           // 将数据项以及AggregateCacheDependency 对象存储到缓存中;
           HttpRuntime.Cache.Add(cacheKey, data, cd,
DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration,
CacheItemPriority.High, null);
      }
      return data;
}

GetCategoryName()方法首先会检讨缓存中是不是已经存在CategoryName数据项,假如已经存在,就透过缓存间接获取数据;否则将因此业务逻辑层调用数据访问层访问数据库拿到CategoryName,在取得了CategoryName后,会将新得到的数额及其DependencyFacade类创造的AggregateCacheDependency对象添加到缓存中。

WebUtility静态类被表示层的众多页面所调用,例如Product页面:
public partial class Products : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Page.Title =
WebUtility.GetCategoryName(Request.QueryString[“categoryId”]);
    }
}

来得页面title的逻辑是置身Page_Load事件措施中,由此每一趟打开该页面都要举办获取CategoryName的章程。假使没有应用缓存机制,当Category数据较多时,页面的来得就会特别缓慢。

4.3.5  引入Proxy模式

事务逻辑层BLL中与Product、Category、Item有关的事务方法,其落实逻辑是调用数据访问层(DAL)对象访问数据库,以获取相关数据。为了改进系统性能,我们就需要为这些实现情势扩张缓存机制的逻辑。当我们操作扩展了缓存机制的业务对象时,对于调用者而言,应与BLL业务对象的调用保持一致。也即是说,大家需要引入一个新的目的去控制原来的BLL业务对象,这一个新的靶子就是Proxy形式中的代理对象。

以PetShop.BLL.Product业务对象为例,PetShop为其创制了代理对象ProductDataProxy,并在GetProductByCategory()等措施中,引入了缓存机制,例如:
public static class ProductDataProxy
{

    private static readonly int productTimeout =
int.Parse(ConfigurationManager.AppSettings[“ProductCacheDuration”]);
    private static readonly bool enableCaching =
bool.Parse(ConfigurationManager.AppSettings[“EnableCaching”]);
       
    public static IList
GetProductsByCategory(string category)
    {
        Product product = new Product();

        if (!enableCaching)
            return product.GetProductsByCategory(category);

        string key = “product_by_category_” + category;
        IList data = (IList )HttpRuntime.Cache[key];

        // Check if the data exists in the data cache
        if (data == null)
        {
            data = product.GetProductsByCategory(category);

            // Create a AggregateCacheDependency object from the
factory
            AggregateCacheDependency cd =
DependencyFacade.GetProductDependency();

            // Store the output in the data cache, and Add the necessary
AggregateCacheDependency object
            HttpRuntime.Cache.Add(key, data, cd,
DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration,
CacheItemPriority.High, null);
        }
        return data;
    }
}

与事务逻辑层Product对象的GetProductsByCategory()方法相相比较,扩张了缓存机制。当缓存内不设有相关数据项时,则间接调用业务逻辑层Product的GetProductsByCategory()方法来获取数据,并将其与相应的AggregateCacheDependency对象一起存储在缓存中。

引入Proxy格局,实现了在缓存级别上对业务对象的包裹,增强了对事情对象的操纵。由于显露在目的外的章程是一模一样的,因此对于调用方而言,调用代理对象与诚实对象并不曾精神的分别。

从职责分开与分支设计的角度解析,我更期待这一个Proxy对象是被定义在事情逻辑层中,而不像在PetShop的计划性这样,被分割到表示层UI中。此外,倘若急需考虑程序的可扩张性与可替换性,大家仍可以为实在对象与代理对象建立联合的接口或抽象类。但是,单以PetShop的表示层调用来看,选用静态类与静态方法的法子,或许更加合理。我们需要谨记,“过度设计”是软件设计的警戒线。

假若急需对UI层接纳缓存机制,将应用程序数据存放到缓存中,就足以调用这多少个代理对象。以ProductsControl用户控件为例,调用形式如下:
productsList.DataSource =
ProductDataProxy.GetProductsByCategory(categoryKey);

productsList对象属于自定义的CustomList类型,这是一个派生自System.Web.UI.WebControls.DataList控件的类,它的DataSource属性可以承受IList集合对象。
只是在PetShop
4.0的筹划中,对于类似于ProductsControl类型的控件而言,接纳的缓存机制是页输出缓存。大家能够从ProductsControl.ascx页面的Source代码中发觉线索:
<%@ OutputCache Duration=”100000″ VaryByParam=”page;categoryId” %>

与ASP.NET 1.x的页输出缓存不同的是,在ASP.NET
2.0中,为ASP.NET用户控件新引入了CachePolicy属性,该属性的档次为ControlCachePolicy类,它以编程模式贯彻了对ASP.NET用户控件的输出缓存设置。大家得以因此设置ControlCachePolicy类的Dependency属性,来安装与该用户控件相关的借助项,例如在ProductsControl用户控件中,举办如下的装置:
protected void Page_Load(object sender, EventArgs e)
{
    this.CachePolicy.Dependency =
DependencyFacade.GetProductDependency();
}

运用页输出缓存,并且拔取ControlCachePolicy设置输出缓存,可以将工作数据与所有页面放入到缓存中。这种格局比起应用程序缓存而言,在性质上有很大的增强。同时,它又经过引入的SqlCacheDependency特性有效地避免了“数据过期”的缺点,由此在PetShop
4.0中被广泛使用。相反,在此以前为Product、Category、Item业务对象建立的代理对象则被“投闲散置”,仅仅作为一种设计方法的显示而“幸存”与总序列统的源代码中。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 mobile.365-838.com 版权所有