下面的示例只是涉及到构建发送者,发送复杂消息等操作。这里的复杂消息包括两种,一种是作者自己封装的一个类,获取对话框中的几个文本对话框的值。第二种是Net中自带的类Message,t填充他的几个属性,代码如下:
private
System.Messaging.Message setMessage()
...
{
System.Messaging.Message msg=new System.Messaging.Message();
msg.Label="A message lable";
msg.Body="The message body";
msg.TimeToBeReceived=TimeSpan.FromSeconds(4000);
msg.UseDeadLetterQueue=true;
return msg;
}
private
void
button1_Click(
object
sender, System.EventArgs e)
...
{
MessageQueue mq;
SendForm form=new SendForm();
if(!MessageQueue.Exists(@".private$chelei"))
...{
try
...{
mq=MessageQueue.Create(@".private$chelei");
form.Name=this.txtname.Text;
form.Sex=this.txtsex.Text;
form.Email=this.txtemail.Text;
form.Address=this.txtaddress.Text;
mq.Send(form,"信息");
mq.Close();
MessageQueue.Delete(@".private$chenlei");
}
catch(Exception ex)
...{
MessageBox.Show(ex.Message,"Warning!");
//
}
}
else
...{
try
...{
mq=new MessageQueue(@".private$chenlei");
form.Name=this.txtname.Text;
form.Sex=this.txtsex.Text;
form.Email=this.txtemail.Text;
form.Address=this.txtaddress.Text;
mq.Send(form,"信息");
mq.Close();
MessageQueue.Delete(@".private$chenlei");
}
catch(Exception ex)
...{
MessageBox.Show(ex.Message,"Warning!");
}
}
}
private
void
button1_Click_1(
object
sender, System.EventArgs e)
...
{
try
...{
MessageQueue mq;
if(MessageQueue.Exists(@".private$aa"))
...{
mq=new MessageQueue(@".private$aa");
mq.Send(this.setMessage());
}
else
...{
mq=MessageQueue.Create(@".private$aa");
mq.Send(this.setMessage());
}
mq.Close();
MessageQueue.Delete(@".private$aa");
}
catch(Exception ex)
...{
MessageBox.Show(ex.Message,"Warning!");
}
}
}
说明:
1
、通过设置TimeToBeReceived属性,这个消息可以在目标队列中保存20秒。
如果没有在20秒内从这个队列中读取他,队列就会删除这条消息。
设置UseDeadLetter属性为true可以通知MSMQ在把它从目标队列中删除之前,把消息复制到
"
Dead-letter messages
"
系统队列中
2
、只有在发送消息的计算机在域模式下运行MSMQ时,才可以使用简单路径引用网络上的公共消息队列
私有队列路径表示:.
private
$aa
公共队列路径表示:.aa
3
、具体的SendForm类如下:
public
class
SendForm
...
{
private string m_Name;
private string m_Sex;
private string m_Email;
private string m_Address;
public SendForm()
...{
//
// TODO: 在此处添加构造函数逻辑
//
}
public SendForm(string name,string sex,string email,string address)
...{
this.m_Name=name;
this.m_Sex=sex;
this.m_Email=email;
this.m_Address=address;
}
public string Name
...{
get
...{
return this.m_Name;
}
set
...{
this.m_Name=value;
}
}
public string Sex
...{
get
...{
return this.m_Sex;
}
set
...{
this.m_Sex=value;
}
}
public string Email
...{
get
...{
return this.m_Email;
}
set
...{
this.m_Email=value;
}
}
public string Address
...{
get
...{
return this.m_Address;
}
set
...{
this.m_Address=value;
}
}
}
怎样引用队列?
方式一、
通过简单路径引用队列
只有在发送消息的计算机在域模式下运行MSMQ时,才可以使用简单路径引用网络上的公共消息队列。这 样打开队列的请求首先会访问Activte Directory服务器来验证是否在这个队列,然后在网络中解析他的位置。
方式二、
通过直接路径引用队列
我们可以通过直接路径在工作组模式下引用公共或私有队列,甚至在网络断开时也可以。当通过直接路径打开一个队列时,MSMQ不会访问Activte Directory服务器。实际上这个消息会直接发送到路径所指定的队列中去。
前面的内容已经介绍了关于构建消息发送等有关知识了,接下来,我们就要开始深入到接收消息的这部了。
关于接收问题,涉及到两个问题:
问题1、由于MSMQ并没有规定消息的格式和主体的结构,所以作为接收者应该而且必须知道如何解析消息的主体。只要发送者和接收者都能明白他就行。
问题2、怎样可以监控队列并在消息到来时读取他,这就要求接收者必须采取一个非常有效的队列监控机制。
所以我们在进行构建接受者的时候,就要充分地考虑到这两个问题。接下来,我们就逐一地解决他们。
消息的自定义类型
这就是我们之前提到的怎样解析消息,前面的例子使用的是一些简单的类型来说明消息队列的结构,然而在发送的数据包含着具体应用程序的数据,其中可以是一个订单,一个收据等。这时你才会发现,消息队列的强大功能。
内置的消息格式化程序可以很容易地把包含有应用程序数据的托管对象解析为消息
.NET消息队列提供了如下的格式程序:XmlMessageFormatter ,BinaryMessageFormatter ,ActiveXMessageFormatter
类型 特性
XmlMessageFormatter 这是默认的格式化程序,前面的例子都是使用它的,从这个名称我们就可以联想到,它是会将自定义的类型串行化为一个XML表示,这个格式化程序很慢,并且会创建相对较多的消息。然而,这些消息可以被运行在不同平台下的应用程序共享和理解。
BinaryMessageFormatter 这个格式化应用程序会把自定义类型串行化为一个专有的二进制的格式。他比上面一种的速度要快得多,而且生成的消息很紧凑。然而只有运行在.NET中的接收者才可以容易地解析这个消息的内容。
ActiveXMessageFormatter ActiveXMessageFormatter 和BinaryMessageFormatter一样,他会把自定义的类型串行化为专用的二进制格式。这个格式也就是MSMQ的COM组件使用的格式。这些传统的COM组件为COM语言(比如Visual Basic
6
)提供了基于MSMQ的功能。因此,您可以在用Visual Basic 6编写的MSMQ应用程序中使用这个格式化程序来发送消息或接收消息。
示例的代码:
1
、使用XmlMessageFormatter
下面是发送代码
1
private
void
btnsend_Click(
object
sender, System.EventArgs e)
2
...
{
3
4 try
5 ...{
6 MessageQueue mq=MessageQueue.Create(@".private$myPrivate");
7
8 SudentInfo form=new SudentInfo(this.txtname.Text,this.txtemail.Text,this.txtaddress.Text);
9 System.Messaging.Message msg=new System.Messaging.Message();
10 msg.Label="A student info";
11 msg.Body=form;
12 mq.Send(msg);
13 }
14 catch(Exception ex)
15 ...{
16 MessageBox.Show(ex.Message,"Warning");
17 }
18
19
20 }
接收代码:
private
void
btnrec_Click(
object
sender, System.EventArgs e)
...
{
MessageQueue mq=new MessageQueue(@".private$myPrivate");
Type[] types=new Type[]...{typeof(ch2.SudentInfo)};
mq.Formatter=new XmlMessageFormatter(types);
System.Messaging.Message msg=mq.Receive();
ch2.SudentInfo form=(ch2.SudentInfo)msg.Body;
this.txtsemail.Text=form.Email;
this.txtsname.Text=form.Name;
this.txtsadd.Text="私有字段,不能串行化";
}
前面我们用的代码,引用了一个自定义的类库,因此只有测试的程序引用了他才能够编译成功。所以我们必须将这个程序集部署到发送者和接收者中。这里似乎就失去了分布式的意义。那么我们应该怎样解决呢?
下面介绍两个方法,
1
、我们可以把消息类型指定为字符串数组,在这个数组中的每一个字符串都包含有类型的全名。
2
、还可以让用编程的方式判断传入的类型以及构造出正确的XmlMessageFormatter。例如我们使用Message.Label属性来表示包含在消息主体中的数据类型。
方案一、
string
[] types
=
new
string
[]
...
{"",""}
;
mq.Formatter
=
new
XmlMessageFormatter(types);
方案二、
//
发送者
Message msg
=
new
Message();
msg.Label
=
typeof
(Customer).AssemblyQualifiedName;
//
接收者
string
[] types
=
new
string
[]
...
{msg.Label}
;
msg.Formatter
=
new
XmlMessageFormatter(types);
object
o
=
msg.Body;
尽管这个形式相对来说很慢,但是他还是有一些优点的。因为由于消息是简单的XML,所以它可以被任何XML解析器读取和解释。换句话说,应用程序不用XmlMessageFormatter也能反串行化整个消息。
//
接收代码
Message msg
=
mq.Receive();
XmlTextReader xtr
=
new
XmlTextReader (msg.BodyStream);
2
、使用BinaryMessageFormatter
示例代码
private
void
sendByBinary()
...
{
try
...{
MessageQueue mq=MessageQueue.Create(@".private$myPrivate");
ch2.DeptmentInfo form=new DeptmentInfo(this.txtname.Text,this.txtemail.Text,this.txtaddress.Text);
System.Messaging.Message msg=new System.Messaging.Message();
//使用BinaryMessageFormatter这个类型进行串行化,默认情况下,这个属性不进行赋值的话就是XmlMessageFormatter
msg.Formatter=new BinaryMessageFormatter();
msg.Label="A student info";
msg.Body=form;
mq.Send(msg);
}
catch(Exception ex)
...{
MessageBox.Show(ex.Message,"Warning");
}
}
private
void
recByBinary()
...
{
try
...{
MessageQueue mq=MessageQueue.Create(@".private$myPrivate");
//使用BinaryMessageFormatter这个类型进行串行化,默认情况下,这个属性不进行赋值的话就是XmlMessageFormatter
msg.Formatter=new BinaryMessageFormatter();
//接收
System.Messaging.Message msg=mq.Receive();
//获取接收的对象
ch2.DeptmentInfo dept=(ch2.DeptmentInfo)msg.Body;
//输出
Console.WriteLine(dept.Address);
Console.WriteLine(dept.Name);
}
catch(Exception ex)
...{
MessageBox.Show(ex.Message,"Warning");
}
}
但要注意的是,和XmlMessageFormatter不同的是,BinaryMessageFormatter使用的是二进制格式来把对象串行化到消息主体中。实际上,他使用了和.Net Remoting一样的运行库串行化机制,这就意味着要使用Serializable特性来修饰类型。同时对比一下,他没有默认的形式那么灵活,尽管速度快,紧凑的多。然而发送者和接收者都必须有一个程序集的副本。
3
、使用ActiveXMessageFormatter
他的代码和前面的两个模式一样,在这里就不赘言了。