Named Pipes in WCF are named but not by you (and how to find the actual windows object name)
If Windows Communication Foundation (WCF) implementation has its own idiosyncrasies, named pipes provider is the champion. First, let’s start with the name of the provider. Named Pipes in Windows can be used to communicate between process on the same machine or between different machines across a network. WCF only implements the on-machine part of it. Named Pipes name has the format \\ServeName\pipe\PipeName and for on-machine pipes you can use \\.\pipe\PipeName. WCF, if you remember, use the uri format net.pipe://host/path but unlike it may seem, the actual pipe name (Windows Object) will not be anything near \\host\pipe\path but rather a randomly generated GUID that will be different every time you start your host. When troubleshooting a TCP host/client in WCF, you can simple use netstat /ano to verify if the port is there and which process is listening to it. If it is not listening you know that the host is either not running or running in a different port. For Named Pipes, you will not be able to identify whether the host is listening or not because you don’t have the pipe name.
I will explain how WCF client can figure out the pipe name. Instead of writing a very large paragraph no one will read let’s put it all in perspective with a scenario: I have created a host with a named pipe biding. The endpoint is net.pipe://localhost/TradeService/Service1. I deploy my solution in my server as Windows Service and one day I cannot connect to my host. I check the ABC (Address-Biding-Contract) of my client and it is as expected. The same happens in the host. My objective is identify if the named pipe is available.
First I download SysInternals tools (https://technet.microsoft.com/en-us/sysinternals/default.aspx) and install everything on c:\systenternals. SysInternals include a tool to list all pipes available in the machine. I start a new cmd prompt with Administrator Privileges, move to my SysInternals folder a run PipeList.exe.
You will see two GUID-like Named Pipes in the list (76637f46-853d-4984-8fd5-a4ef6c56606a and 58c9f8e0-67dc-4050-aa4f-24960a7260dd). But I want to know which one is listening to net.pipe://localhost/TradeService/Service1. Named Pipe implements the naming in the listener factory class in this way: it generates a random GUID to use as pipe name, it creates a shared memory object based on the listen address uri to store this GUID and creates some instances of the named pipe to listen to the requests. The client uses the same technique to generate the shared memory file name and read its contents to know the named pipe name.
The shared memory object (or memory mapped file) name is generated this way:
- It gets the endpoint and substitute the host name by + or * depending on the wildcard mode.
- It then add a “/” to the end if not present already and transform to up case all characters of pipe and path
- If the size of the resulting string is bigger than 128 characters a hash is applied to the resulting string
- The final name is net.pipe:E + Base64 of string generated in item 2 or net.pipe:H + Base64 of string generated in item 3 if uri is bigger than 128 characters
For our example:
Normalized Endpoint: net.pipe://+/TRADESERVICE/SERVICE1/
Base 64 representation: bmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=
Final memory mapped file: net.pipe:EbmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=
If you use Handle.exe from SysIntenals you can verify the existence of the file in both host server and client.
And of course using Handle.exe net.pipe: will show all memory mapped files with GUIDs for named pipes generated by WCF.
Inside these memory mapped files you will find the GUID in binary format starting at the 5th character. There is no easy way to read mapped memory files in .NET (at least before .NET 4.0) and I will publish a C++ console application in my next post to implement the endpoint name resolution for named pipes in WCF.