Why won't MSMQ send a space character?
I'm exploring MSMQ services, and I wrote a simple console client-server application that sends each of the client's keystrokes to the server. Whenever hit a control character (DEL
, ESC
, INS
, etc) the server understandably throws an error. However, whenever I type a space character, the server receives the packet but doesn't throw an error and doesn't display the space.
Server:
namespac开发者_如何学Ce QIM
{
class Program
{
const string QUEUE = @".\Private$\qim";
static MessageQueue _mq;
static readonly object _mqLock = new object();
static XmlSerializer xs;
static void Main(string[] args)
{
lock (_mqLock)
{
if (!MessageQueue.Exists(QUEUE))
_mq = MessageQueue.Create(QUEUE);
else
_mq = new MessageQueue(QUEUE);
}
xs = new XmlSerializer(typeof(string));
_mq.BeginReceive(new TimeSpan(0, 1, 0), new object(), OnReceive);
while (Console.ReadKey().Key != ConsoleKey.Escape) { }
}
static void OnReceive(IAsyncResult result)
{
Message msg;
lock (_mqLock)
{
try
{
msg = _mq.EndReceive(result);
Console.Write(".");
Console.Write(xs.Deserialize(msg.BodyStream));
}
catch (Exception ex)
{
Console.Write(ex);
}
}
_mq.BeginReceive(new TimeSpan(0, 1, 0), new object(), OnReceive);
}
}
}
Client:
namespace QIM_Client
{
class Program
{
const string QUEUE = @".\Private$\qim";
static MessageQueue _mq;
static void Main(string[] args)
{
if (!MessageQueue.Exists(QUEUE))
_mq = MessageQueue.Create(QUEUE);
else
_mq = new MessageQueue(QUEUE);
ConsoleKeyInfo key = new ConsoleKeyInfo();
while (key.Key != ConsoleKey.Escape)
{
key = Console.ReadKey();
_mq.Send(key.KeyChar.ToString());
}
}
}
}
Client Input:
Testing, Testing...
Server Output:
.T.e.s.t.i.n.g.,..T.e.s.t.i.n.g......
You'll notice that the space character sends a message, but the character isn't displayed.
Your issue is not with MSMQ, it's with the XmlSerializer
class. See:
var key = Console.ReadKey();
XmlSerializer s = new XmlSerializer(typeof(string));
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
s.Serialize(ms, key.KeyChar.ToString());
ms.Position = 0;
var foo = (string)s.Deserialize(ms);
}
If you type a space in the console, you'll see that key.KeyChar.ToString()
yields " "
, but foo
is equal to ""
. Because of the default implementation of XmlReader
, the XmlSerializer
class considers a string of only whitespace to be empty; if the string contains any other characters, both leading and trailing spaces are preserved. The whitespace does get serialized, but deserializing it turns it into an empty string.
Use this instead:
Console.Write(
s.Deserialize(System.Xml.XmlReader.Create(msg.BodyStream,
new System.Xml.XmlReaderSettings()
{
IgnoreWhitespace = false
})));
The answer from @Adam is right. The easiest solution is to use BinaryMessageFormatter (it will result in slightly smaller messages anyway).
After you initialize the message queue objects in both the client and the server, set the formatter explicitly:
_mq.Formatter = new BinaryMessageFormatter();
Then in the server, don't try to mess with BodyStream directly. Instead just use Body (which will have already been deserialized by the formatter):
Console.Write(".");
Console.Write(msg.Body);
精彩评论