Tip: Separate your service implementation class from your service interface definition, and put the implementation in its own class away from other code. Use the same names for both but prefix the service interface with an I.
Rationale: The core reason for using service orientation is that the public contracts can be maintained while the internal implementation is replaceable. Although WCF allows you combine a service contract and its implementation in the same class, doing so undermines this principle. Instead, treat both service contracts (interfaces) and implementation classes as important but separate entities. The relation between the two is explicit in the code (the service class x implements Ix), and also implied by their similar names (Ix is the interface implemented by x).
What if I Don’t? You’ll tie your interfaces to their implementations, defeating the primary reason to use service orientation. At some point you’ll need to reimplement something and regret it.
Example: A service is needed to track time clocking. The service contract is defined as interface ITimeClock and maintained in its own source file, ITimeClock.cs. The service implementation is defined as class TimeClock and maintained in its own source file, TimeClock.cs.
Tip: Make an up-front decision about which instancing model you will use (per call, per session, shared session, singleton) and specify it in a ServiceBehavior attribute, even if you are using the default instancing model of per session. Keep the instancing model clearly in mind as the class’s members are defined, backed up with comments where necessary. Base the decision on what will work best for your service implementation.
Rationale: WCF instancing is easy to specify and easy to change, using a ServiceBehavior attribute, but the code has to be written with a particular instancing model is mind. The consequences of changing instancing models without changing the code as to match can be severe. For example, a class member variable can be a global value or a client-specific value depending on the instancing model.
What if I Don’t? Your code likely won’t work correctly. Regrettably, this may not be immediately apparent until you have enough concurrent traffic.
Example: A developer creates a service, neither specifying an instancing model nor giving thought to one. Initial testing of the service with a single client appears to pass with flying colors. Later, when there are multiple clients accessing the service, serious problems arise because the use of class instances, member variables , and static variables was not in accordance with a specific instancing model.
Tip: Where possible, avoid session state. Favor the Per Call or Singleton instancing modes. Stateful services should be the exception and stateless services the rule.
Rationale: Stateless services are far more versatile as a reusable software component. They are easier to scale, tend to have simpler implementations, and can be used in a broader set of contexts.
Be willing to make an exemption when you need to. Stateful services are sometimes necessary, which is why WCF supports them--but they should be the exception, not the rule.
Tip: Write thread-safe code, so your service can take advantage of multiple-thread concurrency (the default behavior). If it is not possible to write thread-safe code for some reason, be sure to set concurrency mode to single.
Rationale: There are few reasons today to write application code that is not thread-safe, and WCF’s default concurrency mode expects this. Use appropriate synchronization mechanisms to access shared resources. Multiple concurrency and thread-safe code will provide your service with the best performance, especially in a setting many clients.
What if I Don’t? Your code will run unsafely and/or inefficiently.
Tip: Avoid lengthy service operations that may time out before they have completed executing. This is primarily a concern with 2-way operations where a client is awaiting results.
Rationale: WCF service operations can time out, and there are time-out settings on both the service-side and the client-side. You really have no good way to know how much time there is for your code to run before a time-out occurs somewhere, and once you venture past 30 or 60 seconds you are pushing your luck. A time-out is especially difficult to handle on the client-side of things. Did the service get the client’s request and process it or not? All the client knows is that a reply didn’t come back in time.
Approaches: If a service is returning a result list that may potentially be quite large, consider one of these solutions:
· Scope the Results. Design the service operation to allow input parameters that set a limit on the size of the results, such as a date range or a maximum record count.
· Results Chunking. Enforce a maximum result size and return a partial list of results. Provide a mechanism for the client to request additional chunks of the results.
· Deflate the Results. Return a subset of result fields to keep the size small, and offer a method to retrieve detail for select row(s).