3

I have an application using discovery that may be deployed locally on the same PC or remote from the service it consumes. Is there any way to expose the named pipe binding via WCF discovery? If not I suppose I can negotiate after the service is discovered to determine the most suitable binding.

pnuts
  • 58,317
  • 11
  • 87
  • 139
Luke
  • 18,585
  • 24
  • 87
  • 110

1 Answers1

6

Yes, it's possible to do that. But since the address will be listed as "localhost" (the only possible address for net.pipe), you'll likely need some sort of test to verify that the service is actually running on the same machine as the discovery client.

public class StackOverflow_7068743
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        string Echo(string text);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            return text + " (via " + OperationContext.Current.IncomingMessageHeaders.To + ")";
        }
    }
    public static void Test()
    {
        string baseAddressHttp = "http://" + Environment.MachineName + ":8000/Service";
        string baseAddressPipe = "net.pipe://localhost/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddressHttp), new Uri(baseAddressPipe));
        host.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
        host.AddServiceEndpoint(new UdpDiscoveryEndpoint());
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.AddServiceEndpoint(typeof(ITest), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "");
        host.Open();
        Console.WriteLine("Host opened");

        DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
        FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ITest)));
        Console.WriteLine(findResponse.Endpoints.Count);

        EndpointAddress address = null;
        Binding binding = null;
        foreach (var endpoint in findResponse.Endpoints)
        {
            if (endpoint.Address.Uri.Scheme == Uri.UriSchemeHttp)
            {
                address = endpoint.Address;
                binding = new BasicHttpBinding();
            }
            else if (endpoint.Address.Uri.Scheme == Uri.UriSchemeNetPipe)
            {
                address = endpoint.Address;
                binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
                break; // this is the preferred
            }

            Console.WriteLine(endpoint.Address);
        }

        if (binding == null)
        {
            Console.WriteLine("No known bindings");
        }
        else
        {
            ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, address);
            ITest proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Echo("Hello"));
            ((IClientChannel)proxy).Close();
            factory.Close();
        }

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • If the service his hosted by an ASP.net web application, the base address for the named pipe endpoint is "net.pipe://{macinename}/Service". In this case, can a client on the same machine use "localhost" instead of the machine name? – Mark Good Feb 23 '13 at 16:01