Different Forms of the Wcf Service Contract Interface

Different forms of the WCF service contract interface

WCF operations can be defined using either synchronous, EAP or (as of .NET 4.5) TAP. From MSDN:

Clients can offer the developer any programming model they choose, so long as the underlying message exchange pattern is observed. So, too, can services implement operations in any manner, so long as the specified message pattern is observed.

You can actually have all 3 patterns in a single contract interface, and they would all relate to the same message.

On the wire, there's no difference how you execute the operations. WSDL (which WCF builds from each endpoint's ABC - address, binding and contract) doesn't contain this information. It is generated from operation descriptions.

If you look at the OperationDescription class, which is used in a ContractDescription, you'll see each operation has these properties: SyncMethod, BeginMethod, EndMethod and TaskMethod. When creating a description, WCF will combine all the methods according to the operation's name into a single operation. If there's some mismatch between operations with the same name in different patterns (e.g. different parameters) WCF would throw an exception detailing exactly what's wrong. WCF automatically assumes (optional) "Async" suffix for Task-based methods, and Begin/End prefix for APM.

The client and server side are completely unrelated in this sense. The utility that generates proxy classes from WSDL (svcutil), can build proxies for any execution pattern. It doesn't even have to be a WCF service.

On the server side, if more than one pattern is implemented, WCF will use just one in the following order of precedence: Task, Sync and APM. This is documented somewhere in MSDN, I just can't find it right now. But you can look at the reference source here.

In conclusion, you can safely change your server implementation as long as you don't modify the message the operation represents.

Regarding the scaling (should be a different question IMO)

  • WCF's throttling default values have been updated in .NET 4.5 to much more reasonable values and are now processor-dependent (see here).
  • There's no change in regards to the thread-pool issue. The problem stems from the initial size of the completion port thread-pool, which is initially set to 4 times the amount of the logical processors. You can use ThreadPool.SetMinThreads to increase the amount by some factor (see this post). This setting could also be beneficial on the client side.

If you use async on the server side (when calling other services, database, etc.), the threading situation could improve dramatically because you won't be wasting thread-pool threads that are just waiting for IO to complete.

The best thing in these situations is to do a LOT of benchmarking.

Multiple WCF Services implementing same Service Contract interface

Thanks guys for your answers. I have a solution now that works for me, without putting the interface in a separate assembly and in the GAC. I'm not looking at using the interface for other projects, just using the same interface for multiple services in the same project.

What I was trying to do was make the change between RealService and TestService in the configuration file of the WCF service, so the client would not know the difference (the client would not have to change its configuration to point to a different .svc file). I'm not sure this is possible, or it least if it is, it is definitely not straightfoward.

What I am doing now is just specifying both services in the configuration file of the WCF service, and then I point the client to one or the other based on which service I want. Since this WCF service is for internal use only and we have control of both the client and the service, it is not a bad tradeoff. This solution is probably more explicit in its intentions anyways.

Here is the snippet of the configuration file:

<services>
<service behaviorConfiguration="WcfService1.Service1Behavior"
name="WcfService1.TestService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="testBasicHttpBinding"
contract="WcfService1.IUselessService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="WcfService1.Service1Behavior"
name="WcfService1.RealService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="testBasicHttpBinding"
contract="WcfService1.IUselessService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>

Service implements multiple ServiceContract types then Restful Service throws ServiceActivationException

  1. Do you use the Factory=System.ServiceModel.Activation.WebServiceHostFactory on the .svc file? If so, remove the Factory attribute, since you're defining the endpoints in config.
  2. An endpoint in WCF is bound to a contract (interface); if you have two different interfaces, you'll need two different endpoints.

Update following edit: the Factory used by the restful service, Autofac.Integration.Wcf.AutofacWebServiceHostFactory, Autofac.Integration.Wcf, is using the WebServiceHost, which requires the service class to implement only one [ServiceContract] interface. Do you need the Autofac factory? If not, just remove that attribute; otherwise, since you're already defining the endpoints via config, I imagine it should work with the "normal" factory (AutofacServiceHostFactory) as well (I've never used Autofac, but you can try that).

Advantage of using interface as Service contract in WCF

As you have demonstrated - you don't need to define an interface for a service contract to get it working. However, arguable in doing so, your class is violating the principle of Single Responsibility (granted this is officially an OO principle - but in my opinion it is one of those universal principles that seems to be a good idea everywhere).

The service contract acts as the "contract" (duh!) between the publisher of the service and the clients that consume it. As such, once you have clients consuming it, you need to be very careful about any changes you make - especially if the clients may be third parties over which you have no control. In accordance with the "Single Responsiblity Principle", defining an interface that represents the contract allows you let this interface have responsibility for the public API, separating it from the implementation.

[ServiceContract]
public interface ILoggingService
{
[OperationContract]
void LogMessage(string message);
}

This implementation is a relies of the fact that all clients connect to the same instance:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SingletonLoggingService : ILoggingService
{
void LogMessage(string message)
{

}

}

This implementation give you a new instance of the service for every call to it:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SingletonLoggingService : ILoggingService
{
void LogMessage(string message)
{

}

}

The advantage of the interface, is that I can mess around with the implementation as much as I like (including it's instancing mode, concurrency, it's behaviour under client sessions, namespace, the name of the class etc.), and not have to worry that I'm potentially breaking any clients.

Agreed - there are ways to maintain backwards compatibility even if you define the service contract to be the class - but it's far more error prone and you are more likely to forget something. Separating the public API and it's implementation leads to cleaner code, and a smaller risk of developers making mistakes.

WCF Service Reference generates its own contract interface, won't reuse mine

"Reuse types in referenced assemblies" only allows you to reuse Data Contracts, not Service Contracts. If you want to share Service Contracts, you don't need to use "Add Service Reference" at all. You can just use ChannelFactory directly.

// Supply the binding and address in code
Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://tempuri.org/address");
IServiceContract channel = ChannelFactory<IServiceContract>.CreateChannel(binding, address);

// Or read them from the config file
ChannelFactory<IServiceContract> channelFactory = new ChannelFactory<IServiceContract>();
IServiceContract channel = channelFactory.CreateChannel();

The channel object will also implement ICommunicationObject, so you can cast it if you need to call methods like Open() or Close().

Using Interfaces With WCF

If your data contracts are interfaces WCF can't know what object to instantiate for an incoming request. There is no need for the class to be the same as in the service, after all the Add Service Reference reads the WSDL and generates new classes based on the type info in the WSDL.



Related Topics



Leave a reply



Submit