among applications, including (but not limited to) remoting, web services, and a myriad of
networking protocols. This has often frustrated application developers who not only had to
pick the appropriate technology to use, but also had to write plumbing code that would allow
their applications to use different technologies depending on where or how they would be
deployed. For example, when users are connected directly to the intranet it is probably better
for them to use a remoting or direct TCP/IP connection for their speed benefits. However,
these aren’t the ideal solution for communication when the application is outside the corporate
firewall, in which case a secured web service would be preferable.
682 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
WCF is designed to solve this sort of problem by providing a means to build messaging applications
that are technology-agnostic, which can then be configured (in text-based configuration files) to
what technologies each service will support and how they will be used. Therefore, you only need
to write the one service and it can support all the various communication technologies supported by
WCF. WCF is essentially a unified communication layer for .NET applications.
GettinG started
A WCF service can be added to an existing project (such as a web application), or it can be created
as a standalone project. For the purposes of this example you will be creating a standalone service
so you can easily see how a single service can be configured and hosted in many communication
scenarios.
When you open the New Project dialog and click the WCF category (under either the VB or C#
languages), you will notice a number of different WCF project types as shown in Figure 31-1.
fiGure 31-1
The WCF Workflow Service Application project template provides an easy way to expose a
Windows Workflow (WF) publicly, and this is discussed in Chapter 32. The Syndication Service
Library project template is used to expose data as an RSS feed. However, the project template you
will be using in the example for in this chapter is the WCF Service Library project template.
If you look in the Web category in the New Project dialog, you will see that
there is also a WCF Service Application project template, which wasn’t under
the WCF category. This project template creates a WCF service that is already
configured to be hosted within an ASP.NET web application.
Defining Contracts .
683
By default, a new WCF Service Library will include IService1.vb and Service1.vb (or .cs if you
are using C#), which define the contract and the implementation of a basic service, respectively.
When you open these files you will see that they already expose some operations and data as an
example of how to expose your own operations and data yourself. This can be all cleared out until
you simply have an interface with nothing defined (but with the ServiceContract attribute left in
place), and a class that simply implements that interface. Or you can delete both files and start anew.
When you want to add additional services to your project you will find a WCF Service item template
in the Add New Item dialog that will add both an interface and a class to your project to use for the
contract and implementation of the service.
defininG contracts
This example project will expose some data from the Entity Framework model that you created in
Chapter 29 for the AdventureWorksLT database, and expose some operations that can be performed
on that data. The way that you do so is by creating contracts that will define the operations and
the structure of the data that will be publicly exposed. Three core types of contracts exist: service
contracts, data contracts, and message contracts.
.
A service contract is a group of operations, essentially detailing the capabilities of the service.
.
A data contract details the structure of the data being passed between the service and the client.
.
A message contract details the structure of the messages passed between the service and the
client. This is useful when the service must conform to a given message format. This is an
advanced topic, and not required for basic services, so we won ’t cover this type of contract in
this chapter.
These contracts are defined by decorating the classes/interfaces in the service with special attributes.
In this chapter you walk through an example of creating a WCF service exposing customer data from
the AdventureWorksLT database to client applications. To do this you will expose operations for
working with the customer data, which will expose the actual customer data itself in the database.
For the purpose of this example you’ll start fresh — so delete IService1
(.vb or .cs) and
Service1
(.vb or .cs). Add a new item to the project using the WCF Service item template,
called CustomerService. This will add two new files to your project — CustomerService
(.vb
or .cs) and ICustomerService
(.vb or .cs).
There are two primary angles that you can take when designing services. You
can take either an implementation-first approach (where you write the code first
and then apply attributes to it to create the contract), or you can take a contract-
first approach (where you design the schema/WSDL first and generate the code
from it). An in-depth discussion of these approaches is beyond the scope of
this chapter; however, WCF can support both approaches. The example in this
chapter follows the contract-first approach.
684 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
creating the service contract
Focus on defining the service contract first. The operations you want to expose externally are:
.
AddCustomer
.
GetCustomer
.
UpdateCustomer
.
DeleteCustomer
.
GetCustomerList
You may recognize the first four operations as standard CRUD (Create, Read, Update, and
Delete) operations when you are working with data. The final operation will return a list of all the
customers in the database.
Now that you know what operations are required you can define your service contract.
You may have noted from the sample implementation in the WCF project
template that all of the service attributes were defined in the interface. However,
creating an interface to decorate with the contract attributes is not essential — in
fact, you don’t need to create an interface at all, and you can decorate the class
itself with the attributes instead. However, standard practice (and best practice)
dictates that the contract should be defined as (and in) an interface, so you will
be following this best practice in the example.
You will define your operations in the ICustomerService interface. However, these operations will
expose data using a data class that you haven’t defined as yet — in the meantime, create a stub
data class and you can flesh it out shortly. Add a new class to the project called CustomerData
and leave it as it is to act as your stub. Each of the operations needs to be decorated with the
OperationContract attribute:
Vb
< ServiceContract([Namespace]:="http://www.professionalvisualstudio.com") >
Public Interface ICustomerService
< OperationContract() >
Function AddCustomer(ByVal customer As CustomerData) As Integer
< OperationContract() >
Function GetCustomer(ByVal customerID As Integer) As CustomerData
< OperationContract() >
Sub UpdateCustomer(ByVal customer As CustomerData)
< OperationContract() >
Sub DeleteCustomer(ByVal customerID As Integer)
< OperationContract() >
Defining Contracts .
685
Function GetCustomerList() As List(Of CustomerData)
End Interface
c#
[ServiceContract(Namespace="http://www.professionalvisualstudio.com")]
public interface ICustomerService
{
[OperationContract]
int AddCustomer(CustomerData customer);
[OperationContract]
CustomerData GetCustomer(int customerID);
[OperationContract]
void UpdateCustomer(CustomerData customer);
[OperationContract]
void DeleteCustomer(int customerID);
[OperationContract]
List<CustomerData> GetCustomerList();
}
Both the ServiceContract and OperationContract attributes have a number of properties that
you can apply values to, enabling you to alter their default behavior. For example, both have a name
property (enabling you to specify the name of the service/operation as seen externally). Of particular
note is the ServiceContract’s Namespace property, which you should always explicitly specify
(as has been done in the preceding code). If a namespace has not been explicitly set, the schema
and WSDL generated for the service will use http://tempuri.org as its namespace. However, to
reduce the chance of collisions with other services it’s best to use something unique such as your
company’s URL.
Now that you’ve defined your contract you need to actually implement these operations. Open the
CustomerService class, which implements the ICustomerService interface. VB will implement
the methods automatically (you may need to press Enter after the Implements ICustomerService
for these to actually be implemented), and in C# you can use the smart tag (Ctrl+.) to have the
methods automatically implemented. The service contract is now complete and ready for the
operations to be implemented (that is, write the code that performs each operation). However, before
you do so you still need to define the properties of the data class, and at the same time you should
also define the data contract.
creating the data contract
You are returning objects containing data from some of the operations you expose in your service,
and accepting objects as parameters. Therefore, you should specify the structure of these data
objects being transferred by decorating their classes with data contract attributes.
686 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
From the .NET Framework 3.5 SP1 onward it is no longer essential that you
explicitly define a contract for your data classes if the classes are public and each
has a default constructor (this is referred to as having an inferred data contract
instead of a formal data contract). However, it is useful (and recommended)
to create a formal contract anyway — especially if you need to conform to a
specific message format in your communication, have non-.NET clients access
your service, or want to explicitly define what properties in the data class
are included in the message. Because explicitly specifying the data contract is
generally recommended, this is the approach you will be taking in the example.
This example requires only one data class — the CustomerData class that you already created
(although no properties have been defi ned on it as yet), which you will now decorate with the data
contract attributes. Whereas the service contract attributes were found in the System.ServiceModel
namespace, data contract attributes are found in the System.Runtime.Serialization namespace,
so C# developers will need to start by adding a using statement for this namespace in their classes:
using System.Runtime.Serialization;
Each data class first needs to be decorated with the DataContract attribute, and then you can
decorate each property to be serialized with the DataMember attribute:
Vb
< DataContract([Namespace]:="http://www.professionalvisualstudio.com") >
Public Class CustomerData
< DataMember() > Public Property CustomerID As Integer
< DataMember() > Public Property Title As String
< DataMember() > Public Property FirstName As String
< DataMember() > Public Property MiddleName As String
< DataMember() > Public Property LastName As String
< DataMember() > Public Property Suffix As String
< DataMember() > Public Property CompanyName As String
< DataMember() > Public Property EmailAddress As String
< DataMember() > Public Property Phone As String
End Class
c#
[DataContract(Namespace="http://www.professionalvisualstudio.com")]
public class CustomerData
{
[DataMember] public int CustomerID { get; set; }
[DataMember] public string Title { get; set; }
[DataMember] public string FirstName { get; set; }
[DataMember] public string MiddleName { get; set; }
[DataMember] public string LastName { get; set; }
[DataMember] public string Suffix { get; set; }
[DataMember] public string CompanyName { get; set; }
[DataMember] public string EmailAddress { get; set; }
[DataMember] public string Phone { get; set; }
}
If you don ’ t want a property to be serialized, simply don ’ t apply the DataMember attribute to it. Like
the service contract attributes you can also set the value of each of the various properties each attribute
has. For example, the DataContract attribute enables you to set properties such as the namespace
for the class ’ s data contract (the Namespace property), and an alternative name for the class ’ s data
contract (the Name property). The DataMember attribute also has a number of properties that you
can set, such as the member ’ s name (the Name property), and whether the member must have a value
specifi ed ( IsRequired ).
When defi ning your data contract you might ask why you are decorating the
data classes directly and aren ’ t defi ning the contract on an interface as you did
with the service contract (which was considered good practice). This is because
only concrete types can be serialized — interfaces cannot (and thus cannot be
specifi ed as parameter or return types in WCF calls). When an object with only
an interface specifying its type is to be deserialized, the serializer would not
know which type of concrete object it should create the object as. There is a
way around this but it ’ s beyond the scope of this chapter. Note that if you try
to create an interface and decorate it with the DataContract attribute, this will
generate a compile error.
You must be aware of some caveats when designing your data contracts. If your data class inherits