18

Is it possible to host multiple service contracts in one WCF service? If so, how? I've been googling and some posts say you can do it (but not how) and others have said it's just not possible.

When I run the server, I get this error:

The contract name 'ConsoleAppWcfCommon.IBarService' could not be found in the list of contracts implemented by the service 'ConsoleAppWcfServer.FooService'.

This is my server code:

    static void Main(string[] args)
    {
        string serviceAddress = "net.tcp://localhost:8088/FooBarService";

        // I'm stuck here as I have to pick *one* service
        ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));            

        // I can add both endpoints here, but this is what gives me the error.
        selfServiceHost.AddServiceEndpoint(typeof(IFooService), new NetTcpBinding(), serviceAddress);
        selfServiceHost.AddServiceEndpoint(typeof(IBarService), new NetTcpBinding(), serviceAddress);

        selfServiceHost.Open();
        Console.ReadLine();
        selfServiceHost.Close();
    }

And this is the client code:

    static void Main(string[] args)
    {
        NetTcpBinding netTcpBinding = new NetTcpBinding();

        EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");

        // Call IFooService
        var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
        IFooService channelFoo = channelFactoryFoo.CreateChannel();
        Debug.WriteLine(channelFoo.FooMethod1());

        // Call IBarService
        var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
        IBarService channelBar = channelFactoryBar.CreateChannel();
        Debug.WriteLine(channelBar.BarMethod1());
    }

My goal is to let the client make a call to Foo (or Bar) and only see the methods available to each. In my real application, I have about 10 domain entities with about four operations on each. I'm trying not to have one interface with 40 methods in it. And I don't want to have to host 10 different WCF services to do this.

Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • 3
    The only way to do this is to have **one service implementation class** that implements **both** interfaces in question. Do you have that? So you would need to have `public class FooService : IFooService, IBarService { .... }` – marc_s May 11 '13 at 21:02
  • 1
    http://stackoverflow.com/a/334554/352101 – Bolu May 11 '13 at 21:03
  • @marc_s I don't have that, but I could as I own all of the code. In my example above, are you saying that the server code should work as-is if FooService implements both interfaces? – Bob Horn May 11 '13 at 21:06
  • The other thing I'm not sure about is whether you can have two service endpoints at the same location, one for each of the service interfaces. But first of all, you'll definitely need one single service implementation class that implements both interfaces... – marc_s May 11 '13 at 21:08
  • 2
    I got it working. I had to share a binding *instance* among the endpoints. I'll share the code as an answer so it can help someone else. Thanks, Marc. – Bob Horn May 11 '13 at 21:11
  • You can have two service endpoints. you can expose same service by multiple end points as long as you have different combination of ABC in the endpoint – Guanxi May 11 '13 at 21:18

1 Answers1

29

As marc_s pointed out, the answer was to have one service implementation class that implements both interfaces. Below is the full working code.

Server:

    static void Main(string[] args)
    {
        string serviceAddress = "net.tcp://localhost:8088/FooBarService";

        ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));            

        // The endpoints need to share this binding.
        var binding = new NetTcpBinding();

        selfServiceHost.AddServiceEndpoint(typeof(IFooService), binding, serviceAddress);
        selfServiceHost.AddServiceEndpoint(typeof(IBarService), binding, serviceAddress);

        selfServiceHost.Open();

        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press any key to terminate service.");
        Console.WriteLine();
        Console.ReadKey();

        selfServiceHost.Close();
    }

Client:

    static void Main(string[] args)
    {
        NetTcpBinding netTcpBinding = new NetTcpBinding();

        EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");

        // Call IFooService
        var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
        IFooService channelFoo = channelFactoryFoo.CreateChannel();
        Console.WriteLine(channelFoo.FooMethod1());

        // Call IBarService
        var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
        IBarService channelBar = channelFactoryBar.CreateChannel();
        Console.WriteLine(channelBar.BarMethod1());

        Console.ReadKey();
    }

Foo Contract:

[ServiceContract]
public interface IFooService
{
    [OperationContract]
    string FooMethod1();

    [OperationContract]
    string FooMethod2();
}

Bar Contract:

[ServiceContract]
public interface IBarService
{
    [OperationContract]
    string BarMethod1();

    [OperationContract]
    string BarMethod2();
}

Foo Service:

public class FooService : IFooService, IBarService
{
    public string FooMethod1()
    {
        return "FooMethod1";
    }

    public string FooMethod2()
    {
        return "FooMethod2";
    }

    public string BarMethod1()
    {
        return "BarMethod1";
    }

    public string BarMethod2()
    {
        return "BarMethod2";
    }
}
Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • 1
    I really like that you posted your end result code - this does help others, me included. I see comments like I will post final code ; and yet people just don't do that and I am left banging my head! ++ – Stix Feb 05 '16 at 16:47
  • Nice code, but if I am in WCF hosted on IIS, where do I put the stuff that goes in Main? – Rhyous Jun 15 '16 at 16:27
  • It would be in the area of your WCF service that initializes things when the service starts. Where do you currently set the bindings and endpoints? That's where this code would go. – Bob Horn Jun 15 '16 at 17:14
  • In IIS hosted applications this must be set up using web.config, so the real answer is this code would go no-where. – caesay Mar 06 '17 at 19:46