It appears I can freely switch between the following three different versions of the same WCF contract interface API, without breaking the clients:
[ServiceContract] interface IService { // Either synchronous // [OperationContract] // int SomeMethod(int arg); // Or TAP [OperationContract] Task<int> SomeMethodAsync(int arg); // Or APM // [OperationContract(AsyncPattern = true)] // IAsyncResult BeginSomeMethod(int arg, AsyncCallback callback, object state); // int EndSomeMethod(IAsyncResult ar); }
The existing test client app keeps working without any recompiling or touching. If I do recompile the service and re-import its reference into the client app, the WSDL definition remains the same, 1:1.
My questions:
The idea is to convert a set of synchronous SomeMethod
-style methods into TAP SomeMethodAsync
-style methods, to use async/await
in their implementation and thus improve the WCF service scalability, without breaking existing clients.
Also, there have been known woes with WCF service scaling under .NET 3.5 and .NET 4.0. They are documented in the MSKB article "WCF service may scale up slowly under load" and the CodeProject article "Tweaking WCF to build highly scalable async REST API". Basically, it wasn't enough to implement the service contract APIs as naturally asynchronous, the WCF runtime still was blocking the request thread.
There are the following two types. The Service Contract declares an interface in the WCF service for the client to get access to the interface. The Operation Contract declares a function inside the interface, the client will call this function.
A service contract can be declared using the [ServiceContract] attribute. It allows defining an Operation Contract under it to expose the service outside the world. It maps the interface and methods of your service to a platform-independent description.
The service contract is not supported in the wcf client.
The WCF service main components for creating and consuming the service are Address, Binding, and Contracts. It is also called as endpoints.
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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With