从 C# 读取 WCF MSMQ 消息
Read WCF MSMQ Message from C#
我使用 WCF 客户端向 WCF 服务发送 msmq 消息,在 WCF 服务处理 msmq 消息之前,我想检查消息的正文。
检查msmq消息正文内容后,得到如下结果。
但是,我没能得到确切的字符串。
下面是 WCF 服务的定义
[ServiceContract]
public interface IMSMQService
{
[OperationContract(IsOneWay = true)]
void ShowMessage(string msg);
}
我用下面的方法获取消息正文,输出为空,如果我在ms上添加watch,我可以得到
"[=12=]\u0001[=12=]\u0001\u0004\u0002(net.msmq://vdi-v-tazho/private/TestQueue\u0003\aV\u0002\v\u0001s\u0004\v\u0001a\u0006V\bD\n\u001e[=12=]��+http://tempuri.org/IMSMQService/ShowMessage@\u0017VsDebuggerCausalityData\bAhttp://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink�<��ϣ-lN��FoJ�0�u\u0006�\"[=12=][=12=][=12=][=12=]\u0017�[=12=]i8�C�I�^Q�A\u0012�w}\f�A�\u000f\rޮ�pe[=12=]\t[=12=][=12=]D\f\u001e[=12=]��(net.msmq://vdi-v-tazho/private/TestQueue\u0001V\u000e@\vShowMessage\b\u0013http://tempuri.org/@\u0003msg�\u0004test\u0001\u0001\u0001"
//message.Formatter = new XmlMessageFormatter(new String[] { });
//StreamReader sr = new StreamReader(message.BodyStream);
string ms = "";
//while (sr.Peek() >= 0)
//{
// ms += sr.ReadLine();
//}
message.Formatter = new ActiveXMessageFormatter();
string result = System.Text.Encoding.UTF8.GetString(message.Body as byte[]);
StreamReader reader = new StreamReader(message.BodyStream);
ms = reader.ReadToEnd();
MessageBox.Show(ms);
我得到了以下代码来实现我的要求。
private void MSMQStringBody_Click(object sender, EventArgs e)
{
System.Messaging.MessageQueue[] queueList = System.Messaging.MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName);
MessageQueue myQueue = queueList[1];
List<System.Messaging.Message> messages = myQueue.GetAllMessages().ToList();
foreach (System.Messaging.Message message in messages)
{
System.Xml.XmlDocument result = ConvertToXMLDoc(message);
MessageBox.Show(result.InnerText);
}
}
public System.Xml.XmlDocument ConvertToXMLDoc(System.Messaging.Message msg)
{
byte[] buffer = new byte[msg.BodyStream.Length];
msg.BodyStream.Read(buffer, 0, (int)msg.BodyStream.Length);
int envelopeStart = FindEnvolopeStart(buffer);
System.IO.MemoryStream stream = new System.IO.MemoryStream(buffer, envelopeStart, buffer.Length - envelopeStart);
System.ServiceModel.Channels.BinaryMessageEncodingBindingElement elm = new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement();
System.ServiceModel.Channels.Message msg1 = elm.CreateMessageEncoderFactory().Encoder.ReadMessage(stream, Int32.MaxValue);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(msg1.GetReaderAtBodyContents());
msg.BodyStream.Position = 0;
return doc;
}
private int FindEnvolopeStart(byte[] stream)
{
int i = 0;
byte prevByte = stream[i];
byte curByte = (byte)0;
for (i = 0; i < stream.Length; i++)
{
curByte = stream[i];
if (curByte == (byte)0x02 &&
prevByte == (byte)0x56)
break;
prevByte = curByte;
}
return i - 1;
}
当你send/retrieve一个消息正文into/fromMSMQ时,你应该使用相同的"type"。请参阅下面的通用类型 "T"。 T 可以是您的任何自定义 class.
public T GetQueueMessage()
{
Message message = queue.Receive(new TimeSpan(0, 0, 0, 1, 0));
return (T)message.Body;
}
public void InsertQueueMessage(T message)
{
using (Message msg = new Message((object)message))
{
queue.Send(msg, MessageQueueTransactionType.Single);
}
}
我知道问题是 C# 代码,但我在这里包含了 Powershell 脚本,供我们这些喜欢使用 shell 快速检查 MSMQ 内容的人使用。使用 Edward 的代码,如果有人正在寻找可以提取这些 WCF 消息的脚本,这些 WCF 消息将作为负载发送到 WCF 服务,并且端点使用协议绑定 NetMsmqbinding 或 NetMsmqIntegrationBinding。
我没有使用 Int32.MaxValue,而是使用了另一个我知道在大多数情况下都足够的大整数值。顺便了解一下找到肥皂信封背后的逻辑会很高兴。
这是 Powershell 脚本:
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null
$queuePath = ".\private$\demoqueue4"
Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""
Run-MainDemoIterateMsmq $queuePath
Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
$doc = New-Object System.Xml.XmlDocument;
$messageLength = [int] $msg.BodyStream.Length
$buffer = New-Object byte[] $messageLength
$msg.BodyStream.Read($buffer, 0, $messageLength)
$envelopeStart = Find-SoapEnvelopeStart($buffer)
$envelopeStart = $envelopeStart - 0
$envelopeLength = $($buffer.Length - $envelopeStart)
#Write-Host $envelopeStart
$stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)
$elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
$elm.ReaderQuotas.MaxStringContentLength = 10000000
$elm.ReaderQuotas.MaxBytesPerRead = 10000000
$msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);
$doc.Load($msg1.GetReaderAtBodyContents());
$msg.BodyStream.Position = 0;
return $doc;
}
Function Find-SoapEnvelopeStart([byte[]] $stream)
{
$i = 0;
$j = 0;
$prevByte = $stream[$i];
$curByte = [byte]$j;
for ($i = 0; $i -lt $stream.Length; $i++)
{
$curByte = $stream[$i];
if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
break;
}
$prevByte = $curByte;
}
return $i - 1;
}
Function Run-MainDemoIterateMsmq([string] $queuePath) {
$queue = New-Object System.Messaging.MessageQueue $queuePath
foreach ($message in $queue.GetAllMessages()){
$xmlDoc = Get-XmlFromWcfMessage $message
Write-Host $xmlDoc.OuterXml
}
}
输出可能如下所示:
<SendMessage xmlns="http://tempuri.org/"><message>this is another test!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>why hello srmp</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>test</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>my message to msmq</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a new message!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>Another message to MSMQ! </message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>another test here</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a test message that will be sent using NetMsmqBinding. </message></SendMessage>
<SendMessageDataContract xmlns="http://tempuri.org/"><message xmlns:b="http://schemas.datacontract.org/2004/07/WcfDemoNetMsmqBinding.Host" xmlns:i="http://www.w3.org/2001
/XMLSchema-instance"><b:BoolValue>true</b:BoolValue><b:StringValue>This is a test of a stringvalue for a CompositeType</b:StringValue></message></SendMessageDataContract>
我使用 WCF 客户端向 WCF 服务发送 msmq 消息,在 WCF 服务处理 msmq 消息之前,我想检查消息的正文。
检查msmq消息正文内容后,得到如下结果。
但是,我没能得到确切的字符串。
下面是 WCF 服务的定义
[ServiceContract]
public interface IMSMQService
{
[OperationContract(IsOneWay = true)]
void ShowMessage(string msg);
}
我用下面的方法获取消息正文,输出为空,如果我在ms上添加watch,我可以得到
"[=12=]\u0001[=12=]\u0001\u0004\u0002(net.msmq://vdi-v-tazho/private/TestQueue\u0003\aV\u0002\v\u0001s\u0004\v\u0001a\u0006V\bD\n\u001e[=12=]��+http://tempuri.org/IMSMQService/ShowMessage@\u0017VsDebuggerCausalityData\bAhttp://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink�<��ϣ-lN��FoJ�0�u\u0006�\"[=12=][=12=][=12=][=12=]\u0017�[=12=]i8�C�I�^Q�A\u0012�w}\f�A�\u000f\rޮ�pe[=12=]\t[=12=][=12=]D\f\u001e[=12=]��(net.msmq://vdi-v-tazho/private/TestQueue\u0001V\u000e@\vShowMessage\b\u0013http://tempuri.org/@\u0003msg�\u0004test\u0001\u0001\u0001"
//message.Formatter = new XmlMessageFormatter(new String[] { });
//StreamReader sr = new StreamReader(message.BodyStream);
string ms = "";
//while (sr.Peek() >= 0)
//{
// ms += sr.ReadLine();
//}
message.Formatter = new ActiveXMessageFormatter();
string result = System.Text.Encoding.UTF8.GetString(message.Body as byte[]);
StreamReader reader = new StreamReader(message.BodyStream);
ms = reader.ReadToEnd();
MessageBox.Show(ms);
我得到了以下代码来实现我的要求。
private void MSMQStringBody_Click(object sender, EventArgs e)
{
System.Messaging.MessageQueue[] queueList = System.Messaging.MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName);
MessageQueue myQueue = queueList[1];
List<System.Messaging.Message> messages = myQueue.GetAllMessages().ToList();
foreach (System.Messaging.Message message in messages)
{
System.Xml.XmlDocument result = ConvertToXMLDoc(message);
MessageBox.Show(result.InnerText);
}
}
public System.Xml.XmlDocument ConvertToXMLDoc(System.Messaging.Message msg)
{
byte[] buffer = new byte[msg.BodyStream.Length];
msg.BodyStream.Read(buffer, 0, (int)msg.BodyStream.Length);
int envelopeStart = FindEnvolopeStart(buffer);
System.IO.MemoryStream stream = new System.IO.MemoryStream(buffer, envelopeStart, buffer.Length - envelopeStart);
System.ServiceModel.Channels.BinaryMessageEncodingBindingElement elm = new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement();
System.ServiceModel.Channels.Message msg1 = elm.CreateMessageEncoderFactory().Encoder.ReadMessage(stream, Int32.MaxValue);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(msg1.GetReaderAtBodyContents());
msg.BodyStream.Position = 0;
return doc;
}
private int FindEnvolopeStart(byte[] stream)
{
int i = 0;
byte prevByte = stream[i];
byte curByte = (byte)0;
for (i = 0; i < stream.Length; i++)
{
curByte = stream[i];
if (curByte == (byte)0x02 &&
prevByte == (byte)0x56)
break;
prevByte = curByte;
}
return i - 1;
}
当你send/retrieve一个消息正文into/fromMSMQ时,你应该使用相同的"type"。请参阅下面的通用类型 "T"。 T 可以是您的任何自定义 class.
public T GetQueueMessage()
{
Message message = queue.Receive(new TimeSpan(0, 0, 0, 1, 0));
return (T)message.Body;
}
public void InsertQueueMessage(T message)
{
using (Message msg = new Message((object)message))
{
queue.Send(msg, MessageQueueTransactionType.Single);
}
}
我知道问题是 C# 代码,但我在这里包含了 Powershell 脚本,供我们这些喜欢使用 shell 快速检查 MSMQ 内容的人使用。使用 Edward 的代码,如果有人正在寻找可以提取这些 WCF 消息的脚本,这些 WCF 消息将作为负载发送到 WCF 服务,并且端点使用协议绑定 NetMsmqbinding 或 NetMsmqIntegrationBinding。
我没有使用 Int32.MaxValue,而是使用了另一个我知道在大多数情况下都足够的大整数值。顺便了解一下找到肥皂信封背后的逻辑会很高兴。
这是 Powershell 脚本:
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null
$queuePath = ".\private$\demoqueue4"
Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""
Run-MainDemoIterateMsmq $queuePath
Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
$doc = New-Object System.Xml.XmlDocument;
$messageLength = [int] $msg.BodyStream.Length
$buffer = New-Object byte[] $messageLength
$msg.BodyStream.Read($buffer, 0, $messageLength)
$envelopeStart = Find-SoapEnvelopeStart($buffer)
$envelopeStart = $envelopeStart - 0
$envelopeLength = $($buffer.Length - $envelopeStart)
#Write-Host $envelopeStart
$stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)
$elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
$elm.ReaderQuotas.MaxStringContentLength = 10000000
$elm.ReaderQuotas.MaxBytesPerRead = 10000000
$msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);
$doc.Load($msg1.GetReaderAtBodyContents());
$msg.BodyStream.Position = 0;
return $doc;
}
Function Find-SoapEnvelopeStart([byte[]] $stream)
{
$i = 0;
$j = 0;
$prevByte = $stream[$i];
$curByte = [byte]$j;
for ($i = 0; $i -lt $stream.Length; $i++)
{
$curByte = $stream[$i];
if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
break;
}
$prevByte = $curByte;
}
return $i - 1;
}
Function Run-MainDemoIterateMsmq([string] $queuePath) {
$queue = New-Object System.Messaging.MessageQueue $queuePath
foreach ($message in $queue.GetAllMessages()){
$xmlDoc = Get-XmlFromWcfMessage $message
Write-Host $xmlDoc.OuterXml
}
}
输出可能如下所示:
<SendMessage xmlns="http://tempuri.org/"><message>this is another test!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>why hello srmp</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>test</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>my message to msmq</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a new message!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>Another message to MSMQ! </message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>another test here</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a test message that will be sent using NetMsmqBinding. </message></SendMessage>
<SendMessageDataContract xmlns="http://tempuri.org/"><message xmlns:b="http://schemas.datacontract.org/2004/07/WcfDemoNetMsmqBinding.Host" xmlns:i="http://www.w3.org/2001
/XMLSchema-instance"><b:BoolValue>true</b:BoolValue><b:StringValue>This is a test of a stringvalue for a CompositeType</b:StringValue></message></SendMessageDataContract>