Export (0) Print
Expand All

Getting Started with WCF

Articles in this series

When you get started with WCF, there a few basic things that you need to know to design, implement and host your services. In fact the WCF templates for Visual Studio make it a single step process in some cases since they start you off with a sample service that can be immediately hosted and tested with the WCF testing tools. Calling a service from a client application is also quite simple – just generate a proxy and write code against the object model.

Once you get past your first sample, however, there are a large number of design choices and features to consider for your services, hosting environment and clients. This chapter of WCF Essentials will serve as a summary of the steps you will take to design, implement, host and consume WCF services. The purpose is not to explain the details behind each design choice or feature – but to make you aware that these are things you should consider. Later sections of this whitepaper will provide recommendations to narrow the choices you face.

Designing a Service Contract

To implement a WCF service you start by designing a service contract, and then implementing that contract on a service type. A simple service contract usually involves applying the ServiceContractAttribute to an interface and then applying the OperationContractAttribute to each method to expose as part of the service contract. Example 1 illustrates a simple WCF service contract with a single service operation.

NOTE: I have supplied a namespace for the service contract instead of relying on the default namespace. This is a best practice that will be discussed in a later chapter.

Example 1: A simple WCF service contract

[ServiceContract(Namespace="urn:WCFEssentials/Samples/2008/12")]

public interface ISimpleService

{

    [OperationContract]

    string SendMessage(string message);

}

You should at least consider the following when designing a service contract:

  • What properties should be set on the and ?
  • Should other attributes be applied to the service contract or its methods – for example those related to fault contracts, sessions, transactions and web programming (non-SOAP messaging)?
  • What complex types will be used for serialization? Should those types be defined as inferred data contracts, data contracts, serializable, or IXmlSerializable? Are there any custom serialization requirements?
  • Are message contracts appropriate for the service contract?
  • What is the versioning strategy for contracts and services?

Recommendations for these considerations are discussed in the chapters entitled “Contracts” and “Versioning Strategies”.

Implementing a WCF Service

Once the service contract is defined, you implement it on a service type. At a minimum, that means providing code for each method (service operation) defined in the service contract to coordinate access to business functionality. You should also consider what attributes should be applied to the service type or its operations. Specifically, some service and operation behaviors should be set in code – as opposed to declarative configuration, for example:

  • What instancing mode will be used?
  • What concurrency mode will be used?
  • Are transactions supported for this service type?
  • Should the service join a particular synchronization context?

Example 2 illustrates the WCF service implementation for the service contract in Example 1. At a minimum the InstanceContextMode should always be explicitly set to make it clear to developers which mode is being used. The default is PerSession which is typically not the desired setting.

Example 2: A simple WCF service implementation

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]

public class SimpleService : ISimpleService

{

    public string SendMessage(string message)

    {

        Console.WriteLine(message);

        return string.Format("Message received: {0}", message);

    }

}

Behavior configuration options are discussed in the chapter on “Behaviors” and recommendations for specific types of behaviors are discussed in the appropriate chapters of this whitepaper.

Hosting a WCF Service

Hosting a WCF service means selecting a hosting environment and then configuring a ServiceHost instance with endpoints and behaviors. The ServiceHost type is the centerpiece for hosting any service type, regardless of the hosting environment. Initializing the ServiceHost elicits the following considerations:

  • How many endpoints will be exposed for the service type? What protocols will be supported?
  • Will a metadata exchange endpoint be provided?
  • Which service behaviors and endpoint behaviors will be configured?
  • What features will be configured programmatically?
  • What features will be configured declaratively?
  • Will a custom and be useful to encapsulate common initialization features?

Example 3 shows how to programmatically initialize the ServiceHost instance for the service defined in Example 2. A single endpoint is exposed over TCP for the service contract shown in Example 1.

Example 3: Initializing the ServiceHost programmatically

using (ServiceHost host = new ServiceHost(typeof(WcfServiceLibrary.SimpleService)))

{

    host.AddServiceEndpoint(typeof(WcfServiceLibrary.ISimpleService), new

NetTcpBinding(), "net.tcp://localhost:9000/SimpleService");

    host.Open();

    Console.ReadLine();

}

Hosting recommendations are discussed in the “Hosting” chapter of this whitepaper.

Generating Proxies

Clients use proxies to communicate with services. SvcUtil.exe (SvcUtil), a command line utility, can be used to generate a proxy with configuration equivalent to the service endpoint. But, if you have access to the service metadata (the service contract and any related data contracts) in a referenced assembly you can also use ChannelFactory<T> to build a client channel (a proxy equivalent) to communicate with a service. Example 4 illustrates the code to call a service operation after generating a proxy.

Example 4: Calling a service operation with a generated proxy

ServiceReferences.SimpleServiceClient proxy = new ServiceReferences.SimpleServiceClient();

string s = proxy.SendMessage("Hello from Test Client");

MessageBox.Show(s);

proxy.Close();

Whether you generate a proxy or write custom code there are other client concerns that influence how you manage calls to services from the client, including:

  • How will collections and arrays be handled?
  • Is a consistent object model desired to match the service implementation?
  • How will exceptions and faulted channels be managed?
  • Are there multithreading considerations?
  • Is UI responsiveness a concern?

These factors are discussed further in the “WCF Clients” chapter of this whitepaper.

Assembly Allocation

It is helpful to have a plan up front for placing the parts of a WCF application into assemblies. This makes projects more manageable, easier to maintain, and if done right allows for sharing metadata assemblies between services and clients. When you establish categories of assemblies with an assembly naming convention up front, it also becomes easier to add new functionality to an application.

Consider the list of assemblies in Example 5 that comprise those used by the articles manager feature for a sample application. For this example the naming convention for the assemblies uses the prefix WCFEssentials.ArticlesManager, which is representative of the overall application name and the ArticlesManager feature name. The assumption here is that every major feature in an application will have assemblies for: data access, business logic, entities that are serializable, contracts, services, a test host and a test client. In addition, there may be shared entities and constants common to the overall application.

Example 5: Breakdown of assemblies for the code sample

Assembly Name Description

WCFEssentials.ArticlesManager

Contains business logic for the managing article links.

WCFEssentials.ArticlesManager.Data

Contains data access logic for the articles manager.

WCFEssentials.ArticlesManager.Services

Contains WCF services related to the articles manager. For example the ArticlesManagerService, other related services if applicable, and new versions of services when the assembly is versioned.

WCFEssentials.ArticlesManager.Contracts

Contains service contracts, message contracts and fault contracts related to the ArticlesManagerService.

WCFEssentials.ArticlesManager.Entities

Contains serializable types related to the data contracts

WCFEssentials.Common.Entities

Contains serializable types and data contracts common to many services in the WCFEssentials application.

WCFEssentials.Common.Constants

Contains constants common to many services, contracts and entities, such as namespaces.

WCFEssentials.ArticlesManager.Services.TestHost

A Console application to host articles manager services with appropriate initialization code that will be used in production.

WCFEssentials.ArticlesManager.Services.TestClient

A client application to test functionality exposed by the articles manager service.

Of course there are some reasonable alternatives to this assembly breakdown, such as:

  • Flattening the service and business logic tier into a single assembly – in this case WCFEssentials.ArticlesManager.Services. I recommend this only if business logic will always be exposed through a service. The service contract would still be separate so that metadata can be shared without sharing implementation. In addition, within the flattened service assembly I would still recommend separating service types from business types.
  • Flattening all contracts into a single assembly – WCFEssentials.Contracts. This is manageable if there are only a few services in the application. In this case common contracts are also included in this assembly.
  • Flattening all entities into a single assembly – WCFEssentials.Entities. This is manageable if there are only a few services in the application. In this case common entities are also included in this assembly.

You should agree on your assembly allocation convention during the design phase of your application in order to save time as you begin to write code. The “WCF Clients” chapter of this whitepaper will also discuss how this allocation can help you when sharing libraries between services and clients.

Recommendations: Getting Started

  1. Define a naming convention and assembly allocation plan during the design phase.
  2. Always put service implementations in a separate assembly from service contracts and related metadata to support sharing libraries with clients.
  3. Try to allocate separate assemblies for services, contracts, entities and constants.
  4. Create a custom test host and test client for every service.

Stay tuned as we post a series of chapters discussing specific recommendations for contracts, bindings, behaviors, hosting, clients, exception handling and more. Each short chapter will provide guidance and code samples to illustrate that guidance for a particular topic.

Show:
© 2014 Microsoft