COM+ 组件中的一个非常简单的持久化缓存






3.64/5 (18投票s)
2004年4月19日
9分钟阅读

69062

830
本文介绍了如何使用 COM+ 组件作为持久化缓存。从此简单的基础出发,可以构建一个完整的缓存系统。
引言
好的,这是我第一篇 Code Project 文章,我将介绍如何创建一个 COM+ 组件,该组件将充当数据(在此情况下只是一个字符串)的持久化缓存。一旦 COM+ 缓存组件运行起来,它将保持其数据,直到托管它的计算机关闭或组件停止。几天后再回来,数据仍然在那里!注销并以其他用户身份登录;数据仍然在那里!
我敢肯定,这可以用于许多用途,或者其概念可以得到扩展。这可能是一种常见的做法,除了我之外,大家都知道!
背景
我为什么开发这个小例子?嗯,我想为多层应用程序创建一个缓存机制。想法是,一个缓存组件,类似于这里描述的,可以运行在每个前端服务器上(可能有很多台),缓存不经常更改的数据。任何服务器上的 .NET 应用程序都可以与同一台服务器上的缓存组件通信以获取缓存的数据。缓存组件本身将通过 .NET Remoting 从一个中央可远程组件获取数据(这可能位于数据库服务器上,或者靠近数据库服务器,甚至可以是一个缓存组件本身)。可以使用 Remoting Callbacks 构建一个缓存失效和刷新机制。一旦我实现了这一点,我可能会在未来的文章中进行描述。
目前,我将只描述简单的缓存机制。希望您觉得它有用。
环境
我使用 Visual Studio 2003 在 Windows 2000 上使用 .NET Framework 1.1 开发了这个例子。我无法在 1.0 Framework 上进行尝试,尽管我认为如果删除某些仅限 1.1 的属性并在 Component Services 管理工具中进行更多配置,它是可以正常工作的。
代码
此处提供的代码非常简单。但是,我发现有趣的是属性的使用方式,以及必须在 Windows 2000 Component Services 管理工具中执行的任务。
示例代码包含两个项目
- Cache - COM+ 组件库(.dll)。
- CacheClient - 控制台应用程序(.exe)。
Cache COM+ 组件
创建 COM+ 组件库很容易。步骤如下
- 使用 Visual Studio .NET,创建一个新的空白解决方案(我称之为 COMPlusCache)。
- 向此新解决方案添加一个类型为“Class Library”的新 C# 项目(我将其命名为 Cache)。
- 将 class1.cs 重命名为 Cache.cs。
- 在 Cache.cs 中,选择一个合适的命名空间并重命名类(我使用了命名空间
Imutome.COMPlusCache
,并将类命名为Cache
)。 - 要使
Cache
成为 COM+ 组件,您必须继承System.EnterpriseServices.ServicedComponent
。为此,首先添加对System.EnterpriseServices
的引用(右键单击项目中的 References 项,选择“Add Reference”,向下滚动并选择System.EnterpriseServices
)。 - 然后在 cache.cs 文件中,在顶部添加
using System.EnterpriseServices;
,并使您的Cache
类继承ServicedComponent
。
现在您拥有了一个基本的 COM+ 组件,它应该可以编译,但当然,它不会做任何事情。此时,您的代码应该看起来像这样
using System;
using System.EnterpriseServices;
namespace Cache
{
/// <summary>
/// Summary description for Class1.
/// <summary>
public class Cache : ServicedComponent
{
public Cache()
{
//
// TODO: Add constructor logic here
//
}
}
}
现在,要使其执行某些操作,请向类添加一个私有字符串和几个方法,一个用于检索字符串,一个用于设置字符串
public class Cache : ServicedComponent
{
private string _data;
...
public string GetData()
{
return _data;
}
public void SetData(string str)
{
_data = str;
}
}
当到达这一点时,我天真地认为,我只需要编译然后将生成的程序集安装为 Component Service。我尝试通过打开 .NET Command Prompt,导航到 Cache 项目的 bin/Debug 目录,然后运行命令 regsvcs Cache.dll 来安装类。遗憾的是,我收到了这个消息
D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug>regsvcs Cache.dll
Microsoft (R) .NET Framework Services Installation Utility Version 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
The following installation error occurred:
1: The assembly 'D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug\Cache.dll' does not
have a strong name.
D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug>
因此,如果您想将代码安装为 COM+ 服务,您必须确保它具有强名称。这意味着代码必须使用加密密钥进行签名。幸运的是,这很容易做到
- 在您的 .NET 命令窗口中,导航到解决方案的根目录。
- 运行命令 sn -k <keyname>。这将创建一个名为 <keyname>.snk 的密钥文件,其中包含一对加密密钥。
- 打开 AssemblyInfo.cs 文件,并在底部,将密钥的完整路径添加到
AssemblyKeyFile
条目中。
AssemblyInfo.cs 文件的底部应该与此类似
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile(@"d:\Temp\dotnet\COMPlusCache\Imutome.COMPlusCache.snk")]
[assembly: AssemblyKeyName("")]
现在,如果您再次尝试使用 regsvcs 安装 COM+ 组件,它将起作用,尽管会显示一个警告消息
D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug>regsvcs Cache.dll
Microsoft (R) .NET Framework Services Installation Utility Version 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
WARNING: The assembly does not declare an ApplicationAccessControl Attribute. A
pplication security will be enabled by default.
Installed Assembly:
Assembly: D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug\Cache.dll
Application: Cache
TypeLib: D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug\Cache.tlb
D:\Temp\dotnet\COMPlusCache\Cache\bin\Debug>
到底什么是 ApplicationAccessControl
属性?别担心,您稍后会读到。好吧,至少组件已安装,并且如果您打开 Component Services(开始 -> 设置 -> 控制面板 -> 管理工具 -> Component Services)并沿着树形结构向下导航到 COM+ Applications,您将看到您新安装的应用程序
恭喜您,您已经安装了一个 COM+ 应用程序。现在,我想,当然,我只需要创建一个与此组件通信的客户端应用程序,然后我就会看到它在缓存数据(当然,正如你们许多人所知,在此之前还需要做更多的工作!)。
客户端应用程序
要创建客户端应用程序,请向整个解决方案添加一个名为“CacheClient”的新 C# 项目,类型为“Console Application”。然后,确保 Cache 项目和 System.EnterpriseServices
都已注册为引用。最后,向允许您读取或替换 Cache 组件中存储的字符串的类添加一个 main()
方法。Class1.cs 文件的全部内容是这样的
using System;
using Imutome.COMPlusCache;
namespace Imutome.COMPlusCache
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
Cache c = new Cache();
string s = c.GetData();
if(s != null)
Console.WriteLine("Cached string is " + s);
if(args.Length > 0 && args[0].Length > 0)
{
c.SetData(args[0]);
Console.WriteLine("Cached string reset to " + args[0]);
}
}
}
}
在 main 方法中,创建了一个新的 Cache
对象。我不太确定真正发生了什么,但我认为 COM+ 应用程序将启动(如果尚未运行),并在其中创建一个 Cache
COM+ 对象。然后,在客户端应用程序中创建的是一个代理对象(或旧术语中的 stub)。代理对象处理与 COM+ 对象的通信,从客户端程序的角度来看,就好像 Cache
对象位于本地代码内部一样。
然后,在 Cache
对象上调用 GetData()
。如果它有一个值,则会将一条消息写入控制台。接下来,如果有一个命令行参数 arg[0]
,则将其传递给 Cache
对象的 SetData()
,并打印一条消息,说明缓存的字符串已被更改。
因此,如果您编译 CacheClient 并运行它(我倾向于在 CacheClient/bin/Debug 中打开命令提示符)......
......它将不起作用!!事实上,无论何时运行它,Cache COM+ 组件存储的值都将是 null。要解决这个问题,您需要添加一些代码并配置更多设置。
池化
我们想通过创建一个 Cache
类的实例来创建一个缓存,该实例将长时间保持活动状态。为此,我们可以利用 Component Services 对象池系统。
对象池旨在作为一种性能改进工具。通常,每次需要使用对象时,都必须先实例化它。实例化会产生处理成本,对象使用完毕后的销毁也会产生处理成本。但是,如果创建一定数量的对象并将其放入池中,则可以在需要时检索它们,并在完成后放回池中。池化可能更有效,因为检索和替换对象的成本低于创建和销毁它们的成本。
我们将在这里使用的技巧是创建一个只有一个对象的池。该对象将长时间存在;它将缓存我们的数据。
COM+ 组件总是会被询问是否可以进行池化。如果它们回答否,池化将不起作用!为了允许 Cache
组件进行池化,请向类添加此代码
protected override bool CanBePooled()
{
return true;
}
配置 COM+ 属性
如果您通过 Component Services 管理工具查看 COM+ Applications 的属性以及这些应用程序中 COM+ 组件的属性,您会发现有许多属性可以配置。其中一些属性只能通过属性窗口进行配置,而另一些可以在代码中配置。
在 cache.cs 文件中,在缓存对象的类定义之前添加以下内容
[ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=1, CreationTimeout=20000)]
[ComponentAccessControl(false)]
public class Cache : ServicedComponent
...
这些条目执行以下操作
ObjectPooling
- 这将对象池设置为启用,并将池的大小设置为始终为一个对象(最大 1,最小 1;其实是一回事!)。创建超时无关紧要。ComponentAccessControl
- 将其设置为false
,禁用该组件的访问控制。
此时,通过 Component Services 管理工具删除 COM+ Application 的旧版本,重新编译解决方案,并使用 regsvcs 重新安装缓存应用程序。
现在,一旦 Cache COM+ 应用程序运行,将始终有一个且只有一个Cache
对象,该对象将在应用程序的生命周期内持久存在。如果您运行 cacheClient
,您会发现字符串将在执行之间保持不变。但是,如果您在使用 cacheClient
之间留有超过几分钟的间隔,字符串将消失。这是因为 COM+ 应用程序在闲置几分钟后会自动关闭。要解决此问题,您需要配置 COM+ 应用程序:在 Component Services 中,找到 Cache 应用程序,然后在“Advanced properties”选项卡中,在“Server Process Shutdown”下,选择“Leave Running when Idle”。
这将使缓存在使用过程中保持不变。但是,还需要更改另外两个设置,以使缓存即使在您注销后也能保持不变
- 在“Identity”选项卡上,将应用程序设置为以命名用户身份运行。我只是使用了管理员的用户 ID 和密码,尽管我认为权限较低的用户也可以。
- 在“Activation”选项卡上,将“Activation Type”设置为“Server”,以便应用程序在其自己的服务器进程中运行,而不是在您注销时终止的进程中运行。
现在,如果您运行 cacheClient
来安装新的字符串到缓存中,您应该会发现它将持久存在很长时间,甚至可以注销并以其他用户身份登录,仍然可以看到字符串正在被缓存。
结论
创建这样一个组件很容易,一旦启动,它就会缓存数据直到计算机关闭。虽然这是一个非常简单的例子,但很容易对其进行扩展,例如,缓存可以是一个包含各种不同类型对象的哈希表。我认为这种方法还有许多其他应用,我最喜欢的是将其与 .NET Remoting 一起用作分布式缓存体系结构的基础。
使缓存正常工作的关键在于正确配置 COM+ 应用程序和组件。其中一些可以在代码中完成,其余配置可以通过 Component Services 管理工具完成。
历史
版本 1 - 2004 年 4 月 13 日。