views:

1331

answers:

3

While I am trying to learn WCF, and it seems straight-forward enough, I came through an odd situation...at least it seems odd to me.

Why is it that the ServiceHost ctor takes a concrete class, and the AddServiceEndpoint takes the Interface, and not vice versa? it seems the latter is more logical from an OOP standpoint.

Consider the following:

    [ServiceContract]
    interface IVocalAnimal
    {
     [OperationContract]
     string MakeSound();
    }
  ...      
  public class Dog : IVocalAnimal
  {
     public string MakeSound()
     {
        return("Woof!");
     }
  }
 ...
 public class Cat : IVocalAnimal
  {
     public string MakeSound()
     {
        return("Meeooow!");
     }
  }

So now we wanto create an "AnimalSound" service that you can connect to get the sound of a Dog or a Cat via /AnimalSoundService/Dog or /AnimalSoundService/Cat

...
Uri baseAddress = new Uri("net.pipe://localhost/AnimalSoundService");
ServiceHost serviceHost = new ServiceHost(typeof(IVocalAnimal), baseAddress);
serviceHost.AddServiceEndpoint(typeof(Dog), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "Dog");
serviceHost.AddServiceEndpoint(typeof(Cat), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "Cat");
...

But the above code will not compile as for some reason(s) I don't quite understand, the ServiceHost ctor wants the concrete class (so either Dog or Cat) and the EndPoint wants the Interface.

So what is the reason it is not vice-versa as it seems to me more natural that the finer granularity endpoint supports a specific implementation (so you could hit specific implementations of the contract per endpoint address) while the more general ServiceHost should be the one to accept the interface?

Btw, I am not being pedantic..I am just honestly trying to understand as I am sure it is I that missed something here.

+1  A: 

When you create the ServiceHost, you are creating the actual service, so it must be concrete.

Your endpoints, on the other hand, are what your clients see. You don't necessarily want your clients to know your implementation -- they should just get the interface definition.

The endpoind DOES support a specific implementation, as you say: whichever one you use when you create the ServiceHost. The purpose of endpoints, is not to provide multiple implementations, but to provide multiple protocols/bindings to access a single implementation.

If you want distinct Dog and Cat services, I believe you'll need two ServiceHosts, each with one NetNamedPipeBinding endpoint.

Jay
"The purpose of endpoints, is not to provide multiple implementations, but to provide multiple protocols/bindings to access a single implementation"<---OK, makes sense. I have gotten it backwards.But say that my serviceHost base is "http://localhost:8000/AnimalSoundService/Service" and I use HTTP binding, that means that another ServiceHost will not be able to share the same port, and client will have to connect to different ports?
Futurist
After a small experiment I figured that 2 serviceHost instances can share the same port. So I guess to make my example work you create 2 serviceHost with 2 different base addresses: net.pipe://localhost/AnimalSoundService/Dog and net.pipe://localhost/AnimalSoundService/Cat ..It makes more sens now. Thanks Jay.
Futurist
Listening for each service on its own port is an option. I have one solution that uses this approach -- 3 services, 3 ports, but only when debugging. Hosting in IIS, this is obviously not an issue -- each service is addressable by URL. The key to sharing your services on a single port is Net.TCP Port Sharing, which is especially for WCF: http://msdn.microsoft.com/en-us/library/aa395195.aspx
Jay
A: 

I see what you thinking. From an OOP perspective it makes sense, but that's not a service perspective. A service is a group of operations. That group of operations is defined in a contract. You can use classes to model service contracts, but most use interfaces because interfaces are a more direct model. MSDN has a very good discussion of those concepts.

Remember, you don't know me and I don't know you. We exchange messages, not objects. I don't want cats and dogs from you. I would not know what to do with a cat or a dog you gave me unless we have prior agreement. You tell me what I can do and I call methods on you to do it. Here's a good article on data on the inside versus data on the outside.

JP Alioto
Thanks for the links. So I guess what people do is either create a mega concrete service class or create a serviceHost instance per concrete class.
Futurist
A: 

I have to disagree a bit with the other answers. While they are technically correct in a way, I feel the most important reason for this to be the way it is has little to do with hiding the implementation or using classes vs interfaces to define service contracts.

It's a lot more obvious why it is the way it is if you take into account the fact that a single service implementation can expose multiple endpoints. Each endpoint might, or might not, expose a different contract, and each one could be exposed on a different binding, for all you know.

For example, you might have a service that exposes a one-way contract over MSMQ and a two-way contract over HTTP. Or perhaps it exposes a JSON contract on one URL and an XML one on another.

tomasr
I guess what I am having an issue with is that the service implementation is a huge concrete class, and the endpoints are the contract interface...
Futurist