locked
Binding the same WCF implementation to basicHttpBinding and netNamedPipeBinding RRS feed

  • Question

  • Hi All,
      I'm learning WCF and I'm having a bit of trouble.  I'm creating a Windows Service that will publish to 2 endpoints.  One is basicHttpBinding for communication across nodes, the other is a namedPipe for communcation across processes on the same machine.  Ultimately I'll be changing the http to tcp, but for now I want to use http as it's easier for me to interact with during the creation of the program.  I have the following config, in my .config file for my app.

    <services>
                <service behaviorConfiguration="SchedulerMetaBehavior" name="SpidertracksScheduledTaskRunner.Services.WcfSchedulerExporter">
                    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpBinding"
                        name="httpEndpoint" contract="SpidertracksScheduledTaskRunner.Services.IWcfScheduler" />
                    <endpoint address="mex" binding="mexHttpBinding" name="mexMetadataEndpoint"
                        contract="IMetadataExchange" />
                    <endpoint address="" binding="netNamedPipeBinding"
                        bindingConfiguration="netPipeBinding" name="netPipeEndpoint"
                        contract="SpidertracksScheduledTaskRunner.Services.IWcfScheduler" />
                    <host>
                        <baseAddresses>
                            <add baseAddress="http://127.0.0.1:20000/ScheduledTaskRunner" />
                            <add baseAddress="net.pipe://localhost/ScheduledTaskRunner"/>
                        </baseAddresses>
                    </host>
                </service>
            </services>
    Here is the declaration of my interface and my impl

    Interface:

     /// <summary>
        /// Copy of the <see cref="IScheduler"/> interface with some modifications to allow WCF remoting.  Removes some functionality that should not/can not be controlled by a client
        /// <author>Todd</author>
        /// </summary>
        [ServiceContract(Namespace = "testservice.com/scheduledtaskrunner")]
        public interface IWcfScheduler
        {
    
    ...
    
    
    }
    Impl:
        /// <summary>
        /// A that uses the WCF framework as a replacement for the legacy <see cref="RemotingSchedulerExporter"/>
        /// <author>Todd Nine</author>
        /// </summary>
        /// only ever want a single instance running since we wire it.
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class WcfSchedulerExporter : IWcfSchedulerService
        {
            /// <summary>
            /// Our instance of the remote scheduler
            /// </summary>
            private IScheduler scheduler;
    
    
    
            public IScheduler{ set{ scheduler = value;}}
    ...
    }
    

    In my code I create the service in the following way.

    schedulerFactory = CreateSchedulerFactory();
    scheduler = GetScheduler();
    
    //set the factory to pull objects from the IoC Servicelocator container
    scheduler.JobFactory = new ServiceLocatorJobFactory();
    
    
    IWcfSchedulerService wcfSchedulerService = new WcfSchedulerExporter();
    wcfSchedulerService.Scheduler = scheduler;
    
    service = new ServiceHost(wcfSchedulerService);
    
    
    
    logger.Info("Wiring the scheduler in to the service");
    
    ...
    
    scheduler.Start();
    
    while(!scheduler.IsStarted)
    {
    	Thread.Sleep(100);    
    }
    
    logger.Info("Scheduler started successfully");
    
    logger.Info("Starting the WCF service");
    
    // Open the host and start listening for incoming messages.
    service.Open();
    
    
    
    logger.Info("WCF service started");

    Now, I want to allow clients to both call the service via the pipe and http, as well as receive the service metadata.  Using the WCF test client tool, I'm able to retreive metadata for both services from http://127.0.0.1:20000/ScheduledTaskRunner, but I'm unable to get metadata from net.pipe://localhost/SpidertracksTaskRunner.  I always receive this error. 

    Metadata contains a reference that cannot be resolved: 'net.pipe://localhost/SpidertracksTaskRunner'.    There was no endpoint listening at net.pipe://localhost/SpidertracksTaskRunner that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.    The pipe endpoint 'net.pipe://localhost/SpidertracksTaskRunner' could not be found on your local machine.

    Cearly I've incorrectly defined my endpoints, but I'm not sure how to implement 2 different protocols with the same underlying singlton instance.  Any help would be greatly appreciated.

    Thanks,
    Todd
    Wednesday, November 25, 2009 4:15 AM

Answers

  • If you want to expose your metadata through a net.pipe protocol, you'll have to use a proper binding. So you should create another mex endpoint like this:

    <endpoint address="mex/pipes" binding="mexNamedPipeBinding" contract="IMetadataExchange" />

    Regards,
    Stipe Ivan


    • Marked as answer by SpdrMan Thursday, November 26, 2009 1:54 AM
    Wednesday, November 25, 2009 9:46 AM

All replies

  • If you want to expose your metadata through a net.pipe protocol, you'll have to use a proper binding. So you should create another mex endpoint like this:

    <endpoint address="mex/pipes" binding="mexNamedPipeBinding" contract="IMetadataExchange" />

    Regards,
    Stipe Ivan


    • Marked as answer by SpdrMan Thursday, November 26, 2009 1:54 AM
    Wednesday, November 25, 2009 9:46 AM
  • Thanks for the help Stipe.  I've tried what you've suggested, with a little tweaking it seems to work with my test client.  I have the following config below.


      <system.serviceModel>
            <diagnostics wmiProviderEnabled="true" performanceCounters="Default">
                <messageLogging logMalformedMessages="true" logMessagesAtServiceLevel="true"
                    logMessagesAtTransportLevel="true" />
            </diagnostics>
            <behaviors>
                <serviceBehaviors>
                    <behavior name="SchedulerMetaBehavior">
                        <serviceMetadata httpGetEnabled="true" />
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <bindings>
                <basicHttpBinding>
                    <binding name="httpBinding" />
                </basicHttpBinding>
                <netNamedPipeBinding>
                    <binding name="netPipeBinding" />
                </netNamedPipeBinding>
            </bindings>
            <services>
                <service behaviorConfiguration="SchedulerMetaBehavior" name="SpidertracksScheduledTaskRunner.Services.WcfSchedulerExporter">
                    <!-- HTTP config -->
                    <endpoint address="" binding="basicHttpBinding" name="httpEndpoint" bindingConfiguration="httpBinding"  contract="SpidertracksScheduledTaskRunner.Services.IWcfScheduler" />
                    
                    <endpoint address="mex" binding="mexHttpBinding" name="httpMetadataEndpoint" contract="IMetadataExchange" />
                    
                    
                    <!-- pipe config -->
                    <endpoint address="" binding="netNamedPipeBinding" name="pipeEndpoint" bindingConfiguration="netPipeBinding" contract="SpidertracksScheduledTaskRunner.Services.IWcfScheduler" />
                    
                    <endpoint address="mex" binding="mexNamedPipeBinding" name="pipeMetadataEndpoint"  contract="IMetadataExchange" />
    
                    <host>
                        <baseAddresses>
                            <!-- HTTP Base Endpoint -->
                            <add baseAddress="http://127.0.0.1:20000/ScheduledTaskRunner" />
                            
                            <!-- Pipe base endpoint -->
                            <add baseAddress="net.pipe://ScheduledTaskRunner"/>
                        </baseAddresses>
                    </host>
                </service>
            </services>
        </system.serviceModel>


    I understand what the meta data publishing does, but it's still not clear to my how it "automagically" figures out which address to wire itself to, I think I can use the same address on my mex endpoints when they are 2 different endpoints on 2 different service address given that they should be unique per endpoint implementation, even if they both have "mex" as one is on the http and one on net.pipe.  If there are 2 bindings that implement 2 different protocols, does it bind based on the base address URN and the binding attribute type?  I guess I'm just still unclear regarding how enpoints are mapped on to base addresses if there is more than 1 defined base address.  Can anyone shed some light on how this happens?

    Thanks,
    Todd
    Wednesday, November 25, 2009 10:23 PM
  • Basically, an endpoint uses a binding that uses a specific protocol. On the other hand you can have only one base address per protocol per service. WCF runtime just needs to check the protocol type for a binding used at a specific endpoint and append the address of that endpoint to a base address associated with the same protocol.

    Did this help?

    Regards,
    Stipe Ivan 
    Wednesday, November 25, 2009 11:15 PM
  • Gotcha, so the WCF framework is smart enough to bind each endpoint to it's appropriate base protocol.  However within each base address, each endpoint must have a unique address, otherwise they conflict.  Thanks for your help, this has been really helpful.  There aren't a lot of well documented examples on creating multiple endpoints of different protocols for a single service.
    Thursday, November 26, 2009 1:54 AM