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 (http://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:
Endpoint: net.pipe://localhost/TradeService/Service1
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.
Great article !
Interesting Finds: March 23, 2011
As I have promised in my previous post, I am making available a C++ console application to troubleshoot
Great article, but what is the reason for creating a shared memory object to get the name?
Hi Christian,
I asked this question myself and that's why I investigated the issue. The reason lies in the fact that net.pipe naming convention cannot be easily translated to Windows named pipes intenal naming. Http enables more flexibility with host headers and flexible path which is not the case with named pipes. The shared memory will bear the normalized name of the net.pipe endpoint and it is one of the best IPC (inter-process communication) if you are in the boundaries of the machine. Please let me know if I answered your question.
Hi Rodney,
When using the app I get the below error:
PS C:scriptsReadMemory> .ReadMemory -file "net.pipe:EbmV0LnBpcGU6Ly8rL1BST0RVQ1RTRVJWSUNFUElQRS8="
Mapped Memory Object Name: net.pipe:EbmV0LnBpcGU6Ly8rL1BST0RVQ1RTRVJWSUNFUElQRS8=
Bad News: Mapped File net.pipe:EbmV0LnBpcGU6Ly8rL1BST0RVQ1RTRVJWSUNFUElQRS8= was not found. LastError: 2
Can you shed some light?
I decide to explore a bit and it turns out the sysinternal tool procexp. exe will show the the GUID of the service under the handle view.
DeviceNamedPipe##_some-GUID_##
Why cannot netnamedpipe be used for communication across lan in WCF?
Deepak,
It is technically feasible to implement named pipes across LAN, however it was a product team design choice to make it only inter process. Next opportunity I will ask why they chose this way.
Just for clarity, when you say "and creates some instances of the named pipe to listen to the requests" are you saying that Net Named Pipes uses the shared memory as its medium of communication between the client and service?
BJHuffine: it means it creates a few threads to receive and dispatch messages received by this named pipes. The shared memory is only used to store the real name of the pipe but not for inter process communication.
Very helpful!!! Thank you!
extremely good article! thanks.
but, if you are searching for the named pipe, why not obtain the PIPELIST output before you start the Service and compare it with what you get after the service really starts?