在.NET中使用COM+队列组件

.NET在异步函数调用上作了很大的努力。通过“代表(DELEGATE)”程序员可以非常方便对函数进行异步调用。编译器在幕后加入了BeginEnvoke()以及EndEnvoke()函数的定义和实体,这样你可以对对象的函数进行异步调用,并方便地拿到函数返回结果。

但是.NET提供的异步调用还不能完全取代COM+队列组件提供的异步功能,原因如下:

第一,.NET不支持断开的网络。客户端和服务器程序必须同时在线运行,并且中间的网络必须保持连接;

第二,在.NET中为使用异步调用,客户端程序要做不少改动。使用的方法和通常的同步调用有不小的区别;

第三,.NET没有不支持“自动再试(Auto-Retry")”机制。总之,如果你涉及到异步调用,COM+提供的队列组件应该是一个值得考虑的方案。

 

COM+队列组件的工作原理

COM+的队列组件是COM+和Microsoft提供的消息队列服务(MSMQ)相结合的产物。本质上讲是利用了“消息中间层”来将客户端和服务器端程序异步地连接在一起。MSMQ提供了消息的中间存储和传递服务。

从表面上看,客户端程序创建了队列组件类的实例,并调用实例的函数。但实际上,这只是一个假象。你创建的只是一个叫做“记录器(Recorder)”的对象。它的作用是记录你的函数调用行为。而后你的函数调用记录会形成一个消息(Message)并放到了队列中,留给COM+的组件去处理。对于客户端程序来说,函数调用会马上返回,线程(THREAD)可以马上进行其它的工作。被调用的函数什么时候正真被COM+内的组件执行则不是客户端程序所需要操心的事了。MSMQ和COM+会把记录了客户端的函数通用行为的消息传达到COM+内的组件那里,COM+内的组件会执行原先客户端程序的函数调用。其过程如下所示:

 

客户端程序COM+端服务器程序
1.创建对象1. 创建记录器对象(Recorder Object)
2.调用对象函数2.记录函数调用
3.释放对象3.函数调用记录放置到一个消息中
4.继续其它操作4.消息被放到消息队列中

放置在队列中的消息是由COM+的消息“监听者(Listener)”来处理的。监听者随时观察着消息队列,当有消息被放置到队列中后,它读出这个消息,创建一个队列组件的实例。当这个实例生成后,它就重放原先客户端程序对组件的函数调用过程。

如果函数调用过程中出现了错误,消息处理将被终止,并且这个消息会自动被放置到“再试”队列去。间隔一定时间后,这个消息会再次被处理。如果在“再次处理”过程中,消息仍然出现错误,那么这个消息会被放置到再下一级的“再试”队列中去。这样的“再试”队列共有5级。如果经过这5级后消息仍没有能被成功的处理,那么这个“问题消息”将会被放到“死队列”。管理员必须亲自过问这个消息了。

 

再试次数时间间隔
一次1分钟
二次2分钟
三次4分钟
四次8分钟
五次16 分钟

COM+处理消息的过程如下所示

 

COM+监听者我们的队列组件
1.监视消息队列  
2.从队列中读取消息  
3.创建对象1.队列组件的实例被创建
4.重放客户端的函数调用2.执行函数调用
5.如果出现问题,消息被放置到下一级队列中去。  

 

COM+队列组件的开发

COM+队列组件的开发和其它队列组件的开发过程相似。区别之处在于设置一些队列有关的属性。下面这个小例程是一个比较典型的示例。

     
     using System;
using System.Windows.Forms;
using System.Reflection;
using System.EnterpriseServices;
// 说明COM+应用程序名字
[assembly: ApplicationName("QCSimpleDemo")]
// 说明COM+应用程序的激活方式。对于队列组件,需要采用"服务器"激活方式
[assembly: ApplicationActivation(ActivationOption.Server)]
// 说明COM+应用程序的的钥匙文件名
[assembly: AssemblyKeyFile("QCsimpleDemo.snk")]
// 要使用COM+提供的队列服务,ApplicationQueuing和QueueListenerEnabled两个
// 属性必须设置为 True。这样COM+会自动创建和该COM+应用程序同名的消息队列
// 并且设置在COM+应用程序启动的时候,队列监听者将被创建并监视消息队列,处理消息。
 [assembly: ApplicationQueuing(Enabled=true, QueueListenerEnabled=true)]
// 本例程是在WINDOWS的工作组环境下工作的。在这种网络环境下,消息认证不被支持。为了避免
// 出现"拒绝访问"的错误,在这里"访问管理"被关闭,认证也没有设置。在生产实际中, MSMQ
// 一般是在域(DOMAIN)下工作的,适当的访问管理和认证是必要的。
[assembly: ApplicationAccessControl(Value=false,
                Authentication=AuthenticationOption.None)]
namespace QCSimpleDemo
{
    [InterfaceQueuing]
    // 使用这一属性使得客户端的函数调用可以被放置到队列中去。
    public interface IQComponent 
    {
        void ComplicatedFunction(string parameter)而;
    }
    // 队列组件必须继承ServicedComponent类。同时它还要实现IQComponent接口
    public class QComponent  : ServicedComponent, IQComponent
    {
        public ComplicatedFunction(string parameter)
        {
            //将你的复杂程序放置在这里。这里的程序只是一个示范
MessageBox.Show(parameter, "Message is processed!");
        }
    }
}

 

COM+队列组件的客户端程序开发

在客户端的程序开发中,只有一点要注意,那就是如何生成记录器对象。.NET的System. Runtime.InteropServices中的Marshal类提供了一个静态函数来帮助你生成记录器对象。客户端程序如下所示。

     
     using System;
using System.Runtime.InteropServices;
using QCSimpleDemo;
public class ConsoleClient
{
	public static void Main(String[] args)
	{
		if(args.Length !=1)
		{
			Console.WriteLine("Usage: ConsoleClient message");
			return;
		}
		// 客户端程序不能直接创建队列组件的对象。它将创建一个RECORDER对象来记录客户端
		// 
程序的调用。创建的方法是利用.NET的Marshal类的静态函数BindToMoniker(...)
		// BindToMoniker函数接收一个字符串参数,返回一个相应的对象。
try
		{
			IQComponent iQC = (IQComponent)
                  Marshal.BindToMoniker("queue:/new:QCSimpleDemo.QComponent");
			iQC.ComplicatedFunction (args[0]);
			Marshal.ReleaseComObject(iQC);
		}       
		catch (Exception ex)
		{
			Console.WriteLine("An exception was caught : " + ex.Message 
);
		}
	}
}

 

程序的编译和运行

1.服务器端队列组件

 

步骤.NET的DOS窗口中的命令
1.生成钥匙文件sn -k QCSimpleDemo.snk
2.编译源程序csc /target: library /out:QCSimpleDemo.dll /r:System.
EnterpriseServices.dll /r:System.Windows.Forms.dll /r:
System.dll QCObj.cs
3.注册队列组件regsvcs QCSimpleDemo.dll
4.安装ASSEMBLYgacutil -i QCSimpleDemo.dll

当你完成上述步骤后,你应该在“组件服务”控制台中看到如下的COM+应用程序:

 

另外,在“计算机管理”控制台中应该看到和COM+应用程序同名的队列以及0-4级5个“再试”队列和“死消息”队列。如下图所示:

 

2.客户端程序

 

步骤.NET的DOS窗口中的命令
编译源程序csc /t:exe /out:ConsoleClient.exe /r:QCSimpleDemo.dll /r:System.dll ConsoleClient.cs
运行程序ConsoleClient Hello_guys

3.启动COM+应用程序

在“组件管理”控制台中选中COM+应用程序,右键单击,在菜单中选取“启动(Start)”,之后你会看到弹出的消息框,表明COM+中的队列组件收到了客户端的消息,并做了相应的操作。

 

COM+队列组件的开发的注意事项

1.队列组件函数设计的问题

队列组件是以异步方式响应客户端的函数调用,客户端程序调用的函数可能在很久以后才会被COM+应用程序处理,所以客户端无法得到函数返回结果。这样,你在设计函数时要注意函数不能设有返回值(VB.NET中只能使用SUB)

2.客户端对消息的控制

如果客户端程序是传统的COM程序,当客户程序释放了记录器(Recorder)的引用后,记录器会将客户端程序的函数调用以消息的形式放到队列里去(本质上讲是记录器的"引用计数器"(Reference Count)为0时)。在.NET里,没有“引用计数器”的概念,那么什么时候消息会被放到队列中呢?

.NET用的是“垃圾清洁工(Garbage Collector)”来回收和管理内存。当记录器的包装对象(Wrapper Object)被回收清理的时候,客户端的函数调用才会被放到队列中去。由于“垃圾清洁工”的工作特性使得消息被放到队列中这一动作有时间上的不确定性。为了加速这一过程,客户端程序可以调用一个函数让让包装对象马上释放记录器。这个函数是ServicedComponet的一个静态函数,叫做DisposeObject()。我们在这里可以对先前的客户程序做一些改进。其核心语句为:

     
     try
{
	IQComponent iQC = (IQComponent)
         Marshal.BindToMoniker("queue:/new:QCSimpleDemo.QComponent");
iQC.ComplicatedFunction (args[0]);
	Marshal.ReleaseComObject(iQC);
	
	ServicedComponent sc = iQC as ServicedComponent;
	If(sc != null)
		sc.DisposeObject(sc);
}

本文旨在通过一个小的例程来介绍一下如何在.NET中使用COM+的队列组件服务。希望给那些频繁使用异步函数调用的程序员一些新的思路。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值