Thursday 2 February 2012

net pipes with WCF in Azure / IIS7

There are a few things worth remembering


1. It's best to leave the address of the service empty in the service side config. You may be forgiven for thinking that the address (for a net named pipe endpoint) can be anything you like, after all it's a pointer to shared memory? Yes, but not in IIS, you need to ensure your address matches the activation path
For example:
If you host a service with net named pipe endpoint and this is deployed to your machine, default web site, lets say it's called WCFService1 with Service1.svc
The address needed at the client would be : "net.pipe://localhost/WCFService1/Service1.svc"


2. Don't forget to add a net named pipe binding to the root website and enable the protocol for the IIS application. Also ensure that the WAS service for net pipe activation is running. (Powershell can accomplish all these things and see here for a nice example for ensuring an azure hosted site will start).


3. You cant (so far as I can see) have two websites in IIS that both have the net named pipe binding. The reason is probably because the activation service can distinguish between the sites by address (unlike net tcp where you could specify differing ports for each site to listen for the incoming message). This is the error you would get:



An error occurred in the Activation Service 'NetPipeActivator' of the protocol 'net.pipe' while trying to listen for the site '1', thus the protocol is disabled for the site temporarily. See the exception message for more details.
URL: WeakWildcard:net.pipe://[machine name]/
Status: ConflictingRegistration
Exception:
Process Name: SMSvcHost
Process ID: 6968




I believe Weakwildcard refers to (I believe) the WCF Hostname comparison mode
This “Weakwildcard” setting is the default in IIS hosted sites.

4. WCF defaults the context mode to per-session, both net tcp and named pipes use a session at the protocol level. In WCF therefore you cannot turn session off if you are using a contract that implements either of these bindings. Specific to net pipe, if you have a "client" which calls a "server" **one way** for example

//Client (abridged)

        public void Test()
        {
            using (var cf = new ChannelFactory(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/NetPipeTest/Service1.svc";))

            {
                var client = cf.CreateChannel();
                client.GetData();
                (client as IClientChannel).Close();
            }
        }

//Server (abridged)

    [ServiceBehavior]

    public class Service1 : IService1, IDisposable
    {
        public void GetData()
        {
// Long running
            for( var i = 0; i < 5 ; i++)
            {
                System.Threading.Thread.Sleep(1000);
            }
        }
        public void Dispose() { }
    }

The client will be blocked on the "close()" if the "GetData()" method on the "server" is long running. If Getdata() throws then a abstract exception will be generated on the client at close(). To work around this you could offload the long running part of "GetData()" to a new task, perhaps with task factory new task.

See here for some related info