Summary
If you wish to use PipeTransmissionMode.Message instead of PipeTransmissionMode.Byte for your named pipes, the NamedPipeServerStream must be created with a PipeDirection parameter of PipeDirection.InOut:
Server Code:
using (NamedPipeServerStream ps = new NamedPipeServer("myPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None))
{
ps.WaitForConnection(); // no sense writing to the pipe until there is a client to read from it.
...
// this would likely be enclosed in some kind of loop to pass messages to the client.
string msg = "Hello, client!";
byte[] msgBuff = System.Text.Encoding.UTF8.GetBytes(message);
ps.Write(msgBuff, 0, msgBuff.Length);
...
}
Client Code:
public const int BUFFSIZE = 1024; // or whatever
using (NamedPipeClientStream cs = new NamedPipeClientStream("myPipe"))
{
cs.Connect(); // connect to the pipe server
cs.ReadMode = PipeTransmissionMode.Message;
// read one message from the server
int byteCount = 0;
byte[] msgBuff = new byte[BUFFSIZE];
StringBuilder mb = new StringBuilder();
do {
byteCount = cs.Read(buff, 0, BUFFSIZE);
mb.Append(System.Text.Encoding.UTF8.GetString(buff, 0, count);
} while (!(cs.IsMessageComplete));
string msg = mb.ToString();
// do something with the message
Console.WriteLine("Message received from server: {0}", msg);
// would print "Hello, client!" on the client's console.
}
Discussion
It may be odd, but for some reason, a NamedPipeServerStream must be created with a PipeDirection parameter of InOut in order for PipeTransmissionMode.Message to work. Not only is this not directly documented, but the way the error is reported is completely counter-intuitive, and appears to have nothing to do with the pipe's TransmissionMode.
Not Directly Documented
The closest to this being "documented behavior" is a blog post by Microsoft's BCL team here. (See the third example of the post.) The example shows the code, but does not explain why the server's pipe must be in/out. None of the rest of the named pipes documentation indicates why this is.
Counter-Intuitive
I like .NET in general in part because of its discoverability: With the code completion support and "pop-up" signature documentation, it is generally possible to discover how to use a Framework object without having to consult the documentation. This behavior, however, is completely counter-intuitive.
First of all, a pipe's direction and whether it's operating in message/byte mode appear completely orthogonal. Why a server's pipe has to be in/out is not explained. Second, the exception that occurs when you get it wrong does not appear to have anything to do with ... well, anything: The client gets an "UnauthorizedAccessException" when attempting to Connect() its pipe.
This is wrong it at least three respects: It's the server's mistake, not the client's; it occurs when connecting, rather than when trying to set the client's ReadMode; and what does access authorization have anything to do with TransmissionMode, anyway? I could understand such an exception if a client tried to use the same mode as the server (it wouldn't work very well for both the client and the server to open the pipe for reading, for example).
The specific exception message is likewise uninformative: "Access to the path is denied." That sounds like a permissions issue, but when I'm testing this, I'm running two processes in parallel under the same user id: no permissions conflict should even be possible.
I hope this helps someone.