简体   繁体   中英

Dynamically create WCF ServiceHost based on parsing Endpoint Address with NamedNetPipes Binding

Need a way for one service on a well-known Endpoint to return strings which are relative addresses. The client can then connect to Endpoints using these relative addresses. Clearly this resembles REST in some ways, but in this case running a Windows Service using NetNamedPipeBinding for IPC, so no need for HTTP.

Don't want to create the Endpoint ahead of time since there will be a potentially large number of relative addresses, only some of which the client would be interested in.

All Contracts are known in advance.

Tried to find a solution with AddressFilterMode but wasn't sure how to provision new Binding so that client connected to it, UriTemplate but don't want to use the HTTP framework. Haven't looked into RoutingService because constrained to .Net 3.5.

Pseudocode for client would be something like that below...

namespace Testing
{
    class RunTest
    {
        static void Test()
        {
            NetNamedPipeBinding namedpipe = new NetNamedPipeBinding();
            ChannelFactory<Contracts.IRoot> factoryRoot =
                new ChannelFactory<Contracts.IRoot>(
                namedpipe
                , new EndpointAddress("net.pipe://localhost/root");
            );
            Contracts.IRoot root = factoryRoot.CreateChannel();
            ICommunicationObject commsRoot = root as ICommunicationObject;
            commsRoot.Open();

            // Service examines address and creates Endpoint dynamically.
            string address = root.SomeFunctionWhichGetsARelativeAddress();

            // IBar service routes endpoint requests internally based on
            // "address" variable.
            ChannelFactory<Contracts.IBar> factoryBar = 
                new ChannelFactory<Contracts.IBar>(
                namedpipe
                , new EndpointAddress("net.pipe://localhost/root/IBar/" +
                                       address)
            );
            Contracts.IBar bar = factoryBar.CreateChannel();
            bar.DoSomething();
        }
    } // Ends class RunTest
} // Ends namespace Testing

AddressFilterMode.Prefix might suffice. The actual Endpoint used can be inspected in Service methods via OperationContext . Current . IncomingMessageHeaders . To

Helper code can parse the endpoint and do any necessary internal processing from there. Hopefully there's some extensibility on the server side which can simplify that code.

Pseudocode for host:

namespace Services
{
    [System.ServiceModel.ServiceBehavior(AddressFilterMode =
         System.ServiceModel.AddressFilterMode.Prefix)]
    class BarService : Contracts.IBar
    {
        #region IBar Members

        public void DoSomething()
        {
            System.Uri endpoint = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.To;
            Console.WriteLine("DoSomething endpoint: {0}", endpoint);
        }
    } // Ends class BarService
} // Ends namespace Services
class RunHost
{
    static void HostIBar()
    {
        System.Uri uriBase = new System.Uri("net.pipe://localhost");
        System.ServiceModel.ServiceHost hostBar =
            new System.ServiceModel.ServiceHost(
            typeof(Services.BarService),
            uriBase);
        hostBar.AddServiceEndpoint(
              typeof(Contracts.IBar) // Type implementedContract
            , namedpipeBinding // System.ServiceModel.Channels.Binding binding
            , "root/IBar" //string address
        );
        hostBar.Open();

        Console.WriteLine("Press <ENTER> to stop...");
        Console.ReadLine();
    }
}

Correction: I'd originally said that this wouldn't treat "net.pipe://localhost/root/IBar/1" and "net.pipe://localhost/root/IBar/2" as distinct endpoints, but it does. Each causes its own WCF Service instance to be created and called.

An additional change was to encode the data in URL style query parameters and not embed it in the path. Eg: "net.pipe://localhost/root/IBar?something=1&somethingelse=11" and "net.pipe://localhost/root/IBar?something=2&somethingelse=22" using HttpUtility.ParseQueryString

Message Filters are the way to go. You can use “Prefix” or create a custom.

WCF Addressing In Depth

From the Message Filters section of the article:

...it uses message filters to determine the matching endpoint, if one exists. You can choose which message filter to use or you can provide your own. This flexibility allows you to break free from the traditional dispatching model when using Windows Communication Foundation to implement things other than traditional SOAP—for instance, the techniques described here enable you to implement REST/POX-style services on the Windows Communication Foundation messaging foundation.

Nice question, by the way. I learned something trying to figure this out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM