Download - WCF Comprehensive Overview
-
8/8/2019 WCF Comprehensive Overview
1/18
DISTRIBUTED .NET
Learn The ABCs Of
Programming WindowsCommunication FoundationAaron Skonnard
This article is based on a prerelease version of WinFX. All information containedherein is subject to change.
THIS ARTICLE DISCUSSES:
The WCF programming model Defining contracts and
behavior
Hosting a service and definingendpoints
Creating and configuringclients
THIS ARTICLE USES THE FOLLOWING
TECHNOLOGIES:.NET Framework 2.0, WCF, WSDL, SOAP
CODE DOWNLOAD AVAILABLE AT:WCF.exe(142 KB)Browse the Code Online
CONTENTS
WCF PROGRAMMING MODEL
SERVICE CONTRACTS AND DISPATCH BEHAVIORDATA CONTRACTS
MESSAGE AND SERVICE CONTRACTS
IMPLEMENTING SERVICE CONTRACTS
HOSTING THE SERVICE AND DEFINING ENDPOINTS
CHOOSING AND CUSTOMIZING BINDINGS
OPENING THE HOST
CONFIGURING SERVICE ENDPOINTS
USING ACTIVATION SERVICES
PROGRAMMING CLIENTS
CONFIGURING CLIENT ENDPOINTS
GENERATING CLIENT PROXIES
LOGGING MESSAGES
CONCLUSIONWindows Communication Foundation (WCF), formerly code-named "Indigo," is
about to radically change the face of distributed programming for developers
using the Microsoft .NET Framework. WCF unifies the existing suite of .NET
distributed technologies into a single programming model that improves the
overall developer experience through a consistent architecture, new levels of
-
8/8/2019 WCF Comprehensive Overview
2/18
functionality and interoperability, and all the extensibility points you could want.
This article introduces you to WCF programming and shows you how to get
started.
As its name suggests, WCF provides the .NET Framework with a basis for writing
code to communicate across components, applications, and systems. WCF was
designed according to the tenets of service orientation. A service is a piece of
code you interact with through messages. Services are passive. They wait forincoming messages before doing any work. Clients are the initiators. Clients send
messages to services to request work.
Figure 1 Services and Endpoints
Services expose one or more endpoints where messages can be sent. Each
endpoint consists of an address, a binding, and a contract (see Figure 1). The
address specifies where to send messages. The binding describes how to send
messages. And the contract describes what the messages contain. Clients need to
know this information before they can access a service.
Services can package up endpoint descriptions to share with clients, typically by
using Web Services Description Language (WSDL). Then clients can use the
provided service description to generate code within their environment capable of
sending and receiving the proper messages (see Figure 2).
Figure 2 Sharing Endpoint DescriptionsWindows Communication Foundation provides a new library of classes found in
the System.ServiceModel namespace that bring these service-oriented concepts
to life. This is what's typically referred to as the WCF programming model.
WCF Programming ModelWith WCF, you're either writing services that expose endpoints or you're writing
clients that interact with endpoints. Hence, endpoints are central to the WCF
programming model and infrastructure. WCF models endpoints with the .NET
classes and interfaces shown in Figure 3. This mapping is true whether you're
writing WCF clients or services.Figure 3 WCF Classes and Interfaces
Element Class or Interface
-
8/8/2019 WCF Comprehensive Overview
3/18
Endpoint System.ServiceModel.ServiceEndpoint
Address System.Uri
Binding System.ServiceModel.Binding
Contract Interfaces annotated with System.ServiceModel attributes
When building a WCF service, you typically start by defining a .NET interface
definition to serve as the service contract. Then you implement the service
contract in a .NET class, known as the service type, and configure its behavior.
Next, you define the endpoints the service will expose, specifying the address,
binding, and contract for each one. Finally, you host the service type in an
application using the WCF hosting infrastructure. Once the service type is hosted,
clients can retrieve its endpoint descriptions and begin integrating with it.
When building a WCF client, you first need the description of the target endpoint
you want to access. The endpoint description can be used to dynamically create a
typed proxy. WCF provides a tool named SvcUtil.exe for automating this process.
Then you can write code against the typed proxy to access the service by sending
the appropriate messages to the target endpoint.
Service Contracts and Dispatch BehaviorYou model service contracts in .NET using traditional C# interface definitions. Youcan use any .NET interface as a starting point, such as the one shown here:
namespace ServiceLibrary
{
public interface IEchoService
{
string Echo(string msg);
}
}
To make this a WCF service contract, you must annotate the interface itself with
[ServiceContract] and each operation you want to expose with[OperationContract]:
using System.ServiceModel;
namespace ServiceLibrary
{
[ServiceContract(Namespace="http://example.org/echo/")]
public interface IEchoService
{
[OperationContract]
string Echo(string msg);
}
}
These attributes influence the mapping between the worlds of .NET and SOAP.
WCF uses the information found in the service contract to perform dispatching
and serialization. Dispatching is the process of deciding which method to call for
an incoming SOAP message. Serialization is the process of mapping between the
data found in a SOAP message and the corresponding .NET objects used in the
method invocation. This mapping is controlled by an operation's data contract.
WCF dispatches based on the message action. Each method in a service contract
-
8/8/2019 WCF Comprehensive Overview
4/18
is automatically assigned an action value based on the service namespace and
method name. For example, the default action for the Echo method just shown is
http://example.org/echo/Echo. You can customize the action value for each
method using [OperationContract]. A value of * can be used for any action when
a specific match doesn't exist.
In the following example, WCF will dispatch messages with an action of
urn:echo:string to the Echo method. Messages with any other action aredispatched to the EchoMessage method:
[ServiceContract(Namespace="http://example.org/echo/")]
public interface IEchoService
{
[OperationContract(Action="urn:echo:string")]
string Echo(string msg);
[OperationContract(Action="*")]
Message EchoMessage(Message msg);
}
Data ContractsOnce the target method has been determined based on the action, WCF relies on
the method's data contract to perform serialization. The data contract is defined
by the types used in the method signature. In the previous example,
EchoMessage is generic and could be used to process a variety of incoming SOAP
messages. Therefore I've used Message to model the input and output. Message
is a special type used to represent all messages flowing through WCF. When
using Message, WCF does not perform type-based serialization. Instead, it just
gives you direct access to what's found in the SOAP message.
When Message is not used, WCF performs serialization to map between the data
found in the SOAP message and the corresponding .NET objects needed to invoke
the method. For example, in the case of Echo, WCF maps the SOAP payload to a.NET string. WCF provides an implicit mapping for all .NET primitive types (string,
int, double, and so on).
The way WCF serializes .NET classes depends on the serialization engine in use.
The default serialization engine is known as DataContract, a simplified version of
XmlSerializer, the default serialization engine used in ASMX today. DataContract
defines attributes for annotating class definitions to influence the serialization
process. Here's an example of it in use:
[DataContract(Namespace="http://example.org/person")]
public class Person
{
[DataMember(Name="first", Order=0)]public string First;
[DataMember(Name="last", Order=1)]
public string Last;
[DataMember(IsRequired=false, Order=2)]
private string id;
...
}
With DataContract, only fields marked with DataMember will be serialized. And
-
8/8/2019 WCF Comprehensive Overview
5/18
you can serialize private fields. This is much different from the way XmlSerializer
works. Now you can use Person in an operation contract:
[ServiceContract(Namespace="http://example.org/echo/")]
public interface IEchoService
{... // previous methods omitted
[OperationContract]
Person EchoPerson(Person p);
}
When EchoPerson is invoked, WCF will serialize Person instances according to the
DataContract attributes specified on the Person class. DataContract produces a
very simple XML structurea sequence of elements. You can control the name of
each element, the order, and whether a particular element is required, but that's
about it.
If you need to do anything more sophisticated, WCF lets you fall back to using
XmlSerializer. You indicate your desire to use XmlSerializer by annotating the
interface with [XmlSerializerFormat]:
[ServiceContract]
[XmlSerializerFormat]
public interface IEchoService { ... }
This tells WCF to use XmlSerializer for all types in the contract, according to the
XmlSerializer defaults and the various System.Xml.Serialization customization
attributes. This makes it much easier to move existing ASMX services forward to
WCF.
WCF also supports serializing types marked with [Serializable], which allows .NET
remoting types to work with WCF without change. WCF provides an implicit
mapping for [Serializable] types where all public/private fields are automaticallyserialized.
Message and Service ContractsAll of the examples up to this point have relied on WCF to automatically map the
method signature to the SOAP message. The parameter list and return type are
always mapped to the SOAP body for the request and response, respectively. If
you need to support headers, you can write another class that models the
structure of the entire SOAP envelope for the particular operation, specifying
which fields map to headers versus the body. You define this mapping with the
[MessageContract] attributes:
[MessageContract]public class EchoPersonMessage
{
[MessageBody]
public Person Person;
[MessageHeader]
public Authorization Authorization;
}
In this example, the Person field is mapped to the SOAP body while the
-
8/8/2019 WCF Comprehensive Overview
6/18
Authorization field is mapped to a SOAP header. Now you can use
EchoPersonMessage in an operation contract:
[ServiceContract]
public interface IEchoService
{... // previous methods omitted
[OperationContract]
void EchoPerson(EchoPersonMessage msg);
}
Using MessageContract is a more advanced technique that is only necessary
when you need direct control over the SOAP contract.
Implementing Service ContractsNow you can implement the service contract by simply implementing the .NET
interface in a class:
using System.ServiceModel;
namespace ServiceLibrary
{
public class EchoService : IEchoService
{
public string Echo(string msg)
{
return msg;
}
... // remaining methods omitted
}
}By doing this, EchoService is guaranteed to support the service contract defined
by IEchoService. When using an interface to define the service contract, you
don't need any contract-related attributes on the class definition. However, you
may want to use [ServiceBehavior] to influence its local behavior:
using System.ServiceModel;
namespace ServiceLibrary
{
... // interface definition omitted
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,
ConcurrencyMode=ConcurrencyMode.Multiple)]
public class EchoService : IEchoService
{
...
This particular example tells WCF to manage a singleton instance of the service
type and to allow multithreaded access to the instance. There is also an
[OperationBehavior] attribute for controlling operation-level behavior.
-
8/8/2019 WCF Comprehensive Overview
7/18
Behaviors influence processing within the host, but have no impact on the service
contract whatsoever. Behaviors are one of the primary WCF extensibility points.
Any class that implements IServiceBehavior can be applied to a service through
the use of a custom attribute or configuration element.
Hosting the Service and Defining Endpoints
To use EchoService, you need to host it in a .NET-based application. TheServiceHost class gives you direct control over the WCF hosting infrastructure.
You instantiate ServiceHost based on a particular service type. The following code
shows how to do this in a console application:
using System;
using System.ServiceModel;
using ServiceLibrary;
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(EchoService), new Uri("http://localhost:808
0/echo")))
{
...
In addition to specifying the service type, you also specify the base addresses for
the different transports you plan to use. In this example, I've specified a base
address of http://localhost:8080/echo. This will be used as the base for any
relative HTTP addresses I might specify when adding endpoints. The base HTTP
address is also used as the default for retrieving the service description.
You then add the service endpoints. Again, a service may have one or more
endpoints and each endpoint consists of an address, a binding, and a contract.You provide this information to your ServiceHost by calling AddServiceEndpoint.
This is where you specify the service contract you defined earlier (IEchoService).
For the binding, you typically choose from one of the many predefined bindings
that ship with WCF and an appropriate address given the binding's transport.
Here's an example:
host.AddServiceEndpoint(typeof(IEchoService),
new BasicHttpBinding(), "svc");
host.AddServiceEndpoint(typeof(IEchoService),
new NetTcpBinding(), "net.tcp://localhost:8081/echo/svc");
In this particular example, I've specified IEchoService as the contract for both
endpoints, but with each endpoint using a different binding and address. The firstendpoint uses the BasicHttpBinding and a relative HTTP address of svc (which
would make its absolute address http://localhost:8080/echo/svc). The second
endpoint uses the NetTcpBinding and an address of
net.tcp://localhost:8081/echo/svc. Therefore, this service allows consumers to
communicate with it over either HTTP or TCP using different WS-* protocols, as
defined by each binding.
Choosing and Customizing Bindings
-
8/8/2019 WCF Comprehensive Overview
8/18
The WCF infrastructure relies heavily on endpoint definitions to control how
messages are processed. In fact, WCF uses the endpoint definitions to
dynamically build the appropriate message processing runtime within hosts and
clients. The binding has the most significant influence on this process.
The binding controls three aspects of message communication: the suite of WS-*
protocols, including WS-Security, WS-ReliableMessaging, and so on; the message
encoding, such as XML 1.0, Message Transmission Optimization Mechanism(MTOM), and binary; and the transport protocol, including HTTP, TCP, and
Microsoft Message Queuing (MSMQ). A given binding specifies one message
encoding and one transport, but it can specify numerous WS-* protocols. Given
that, there are an overwhelming number of permutations that could be used. To
simplify things, WCF provides a set of predefined bindings that fit the most
common use cases. Figure 4 lists some of these and describes what they
embody.Figure 4 Predefined WCF Bindings
Class Name Element Name Transport Encoding WS-*Protocols
BasicHttpBinding basicHttpBinding HTTP XML 1.0 WS-I Basic
Profile 1.1
WSHttpBinding wsHttpBinding HTTP XML 1.0 Messagesecurity,reliablesessions,andtransactions
WSDualHttpBinding wsDualHttpBinding HTTP XML 1.0 Messagesecurity,reliablesessions,andtransactions
NetTcpBinding netTcpBinding TCP Binary Transportsecurity,reliablesessions,andtransactions
NetNamedPipeBinding netNamedPipeBinding NamedPipes
Binary Transportsecurity,reliablesessions,andtransactions
NetMsmqBinding netMsmqBinding MSMQ Binary Transportsecurityand queuetransactions
Developers who care primarily about interoperability and don't need WS-*
functionality will typically use BasicHttpBinding. Developers who care about
interoperability, but also need message-based security, reliable messaging, and
transactions will typically choose WSHttpBinding. Developers using WCF on both
sides (client and service) can choose from NetTcpBinding and
-
8/8/2019 WCF Comprehensive Overview
9/18
NetNamedPipeBinding, which provide significant optimizations. Those building
asynchronous systems can choose NetMsmqBinding. There are also a few
bindings that aren't listed here, such as MsmqIntegrationBinding for integrating
with existing MSMQ applications, NetPeerTcpBinding for building peer-to-peer
services, and WSFederationBinding for federated security. A service can support
any combination of these bindings.
Once you choose a binding and instantiate it, you can customize some of itscharacteristics through the properties exposed on the binding class. The following
example shows how to enable transport-based security on the BasicHttpBinding:
BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = BasicHttpSecurityMode.Transport;
b.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
host.AddServiceEndpoint(typeof(IEchoService), b, "svc");
If the predefined bindings and their customizations still don't fit your needs, you
can also write a custom binding by implementing a class that derives from
Binding.
Opening the HostNow that you've configured the host with endpoint information, WCF can build
the runtime needed to support your configuration. This occurs when you call
Open on a particular ServiceHost:
host.Open();
Once the call to Open returns, the WCF runtime is built and ready to receive
messages at the addresses specified by each endpoint. During this process, WCF
generates an endpoint listener for each supplied endpoint and the code needed to
support the WS-* protocols specified by the binding. (An endpoint listener is the
piece of code that actually listens for incoming messages using the specifiedtransport and address.)
You can retrieve information about the service at run time through the object
model exposed by ServiceHost. This allows you to retrieve anything you might
want to know about the initialized service, such as what endpoints it exposes and
what endpoint listeners are currently active.
Figure 5 shows a complete example of the console application that hosts
EchoService. Figure 6 shows the output. Notice there are two additional endpoint
listener addresses that I didn't specify in a ServiceEndpoint. WCF automatically
provided these using the base HTTP address for retrieving the service description.Figure 5 Console App Hosting EchoService
class Program{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(EchoService), new Uri("http://localhost:808
0/echo")))
{
// define the service endpoints
host.AddServiceEndpoint(typeof(IEchoService),
-
8/8/2019 WCF Comprehensive Overview
10/18
new BasicHttpBinding(), "svc");
host.AddServiceEndpoint(typeof(IEchoService),
new NetTcpBinding(), "net.tcp://localhost:8081
/echo/svc");
host.Open();
Console.WriteLine(
"{0} is open and has the following endpoints:\
n",
host.Description.ServiceType);
int i=1;
foreach (ServiceEndpoint end in host.Description.E
ndpoints)
{
Console.WriteLine("Endpoint #{0}", i++);
Console.WriteLine("Address: {0}",
end.Address.Uri.AbsoluteUri);
Console.WriteLine("Binding: {0}",
end.Binding.Name);
Console.WriteLine("Contract: {0}\n",end.Contract.Name);
}
Console.WriteLine(
"The following EndpointListeners are active:\n
");
foreach (EndpointListener l in host.EndpointListen
ers)
Console.WriteLine(l.Listener.Uri.AbsoluteUri);
// keep the process alive
Console.ReadLine();
}
}
}
Figure 6 Output of Console AppIf you browse to http://localhost:8080/echo, you'll see the default WCF help page
(see Figure 7) and if you browse to http://localhost:8080/echo?wsdl, you'll see
the generated WSDL definition. The other endpoint listener
(http://localhost:8080/echo/mex) knows how to speak WS-MetadataExchange.
It's important to note that this sample is not using IIS in any way. WCF provides
built-in integration with httpsys, which allows any application to automatically
-
8/8/2019 WCF Comprehensive Overview
11/18
become an HTTP listener.
Figure 7 EchoService Help Page
Configuring Service EndpointsHardcoding endpoint information into the host application is not ideal since
endpoint details may change over time. It's not hard to imagine how you could
store the endpoint information in a configuration file or database and read it whileinitializing ServiceHost. Since this is a common need, WCF automatically provides
this functionality through the predefined configuration
section.
The following configuration file defines the same two endpoints that were
specified by calling AddServiceEndpoint:
If you add this configuration file to the host application shown in Figure 5 and
-
8/8/2019 WCF Comprehensive Overview
12/18
comment out the calls to AddServiceEndpoint, you'll see the same results in the
output. This increases deployment flexibility since the communication details are
completely factored out of the compiled code. You can also configure bindings
within . Figure 8 shows how to configure
basicHttpBinding to use transport security like I had done in code.Figure 8 Configuring Transport Security
...
You can even define new custom bindings from scratch using the
element, which would be equivalent to deriving a new class
from Binding. When it comes to configuring endpoints, bindings, and evenbehaviors, anything you can do in code, you can also do through configuration.
Figure 9 Using the GUI to Define an EndpointAlthough IntelliSense for the configuration file works well in Visual Studio
2005, some developers still prefer to avoid XML altogether. The WinFX SDK
includes a tool called SvcConfigEditor, which provides a graphical interface for
working with the various settings. Figure 9 shows how
to configure endpoints using this tool.
-
8/8/2019 WCF Comprehensive Overview
13/18
Using Activation ServicesAlthough I've been experimenting with console applications, ServiceHost makes it
easy to host WCF services in a variety of applications, including Windows Forms
applications and managed Windows Services. In all of these application scenarios,
you're responsible for managing the process hosting WCF. This is known as self-
hosting in WCF terms.In addition to self-hosting, WCF also makes it possible to activate services by
using IIS along with traditional Web hosting techniques. You can accomplish this
by using a .svc file (similar to .asmx) that specifies the service type to host:
You place this file in a virtual directory and deploy your service type to its \bin
directory or the Global Assembly Cache (GAC). When using this technique you
specify the service endpoint in the web.config, but you don't need to specify the
address since it's implied by the location of the .svc file.
...
Now if you browse to the .svc file, you'll notice the help page is displayed,
showing that a ServiceHost was automatically created within an ASP.NET
application domain. This is accomplished by an HTTP module that filters incoming
.svc requests and automatically builds and opens the appropriate ServiceHost
when needed.If you install the WinFX extensions for Visual Studio 2005, you'll find a new Web
Site project template called Indigo Service (this name will change). When you
create a new Web site based on this template, it automatically gives you the .svc
file along with the corresponding implementation class (found in App_Code). It
also comes with a default endpoint configuration in web.config.
On IIS versions 5.1 and 6.0 the WCF activation model is tied to the ASP.NET
pipeline, and therefore to HTTP. IIS 7.0, which is planned for release with
Windows Vista, introduces a transport-neutral activation mechanism known as
Windows Activation Services (WAS). With WAS, you'll be able to leverage .svc-
like activation over any transport.
Programming Clients
Programming WCF clients involves sending messages to a service endpointaccording to its address, binding, and contract. To accomplish this, you first
create a ServiceEndpoint representing the target endpoint. The following example
shows how to create a ServiceEndpoint, based on the service's HTTP endpoint, in
a client console application:
using System;
using System.ServiceModel;
-
8/8/2019 WCF Comprehensive Overview
14/18
using ServiceLibrary;
class Program
{
static void Main(string[] args)
{
ServiceEndpoint httpEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IEchoServic
e)),
new BasicHttpBinding(), new EndpointAddress(
"http://localhost:8080/echo/svc");
This code assumes that the client has access to the same IEchoService interface
definition that the service used and that the client knows what binding and
address to use. Then you can create a ChannelFactory based on the
ServiceEndpoint:
ChannelFactory factory =
new ChannelFactory(httpEndpoint);
ChannelFactory creates typed proxies. In this case, it creates proxies of typeIEchoService, which you can use to invoke the operations defined by the
contract:
IEchoService svc = factory.CreateChannel();
Console.WriteLine(svc.Echo("Hello, world"));
If the service requires a customized binding, you will need to create the binding
and customize it before creating ServiceEndpoint. If you want to access the TCP
endpoint, simply create another ServiceEndpoint specifying the TCP endpoint
details and supply it to ChannelFactory instead of the HTTP endpoint. Everything
else would work the same.
The proxy shields you from the different addresses and bindings in use, allowingyou to write application code against the service contract. Figure 10 shows the
complete client console application.Figure 10 EchoService Client App
using System;
using System.ServiceModel;
using ServiceLibrary;
class Program
{
static void Main(string[] args)
{
try{
// define service endpoints on client
ServiceEndpoint httpEndpoint = new ServiceEndpoint
(
ContractDescription.GetContract(
typeof(IEchoService)),new BasicHttpBinding(
),
new EndpointAddress("http://localhost:8080/ech
-
8/8/2019 WCF Comprehensive Overview
15/18
o/svc"));
ServiceEndpoint tcpEndpoint= new ServiceEndpoint(
ContractDescription.GetContract(
typeof(IEchoService)),
new NetTcpBinding(), new EndpointAddress(
"net.tcp://localhost:8081/echo/svc"));
IEchoService svc = null;
// create channel factory based on HTTP endpoint
using (ChannelFactory httpFactory =
new ChannelFactory(httpEndpoint)
)
{
// create channel proxy for endpoint
svc = httpFactory.CreateChannel();
// invoke service operation
Console.WriteLine("Invoking HTTP endpoint: {0}
",
svc.Echo("Hello, world"));}
// create channel factory based on TCP endpoint
using (ChannelFactory tcpFactory =
new ChannelFactory(tcpEndpoint))
{
// create channel proxy for endpoint
svc = tcpFactory.CreateChannel();
// invoke service operation
Console.WriteLine("Invoking TCP endpoint: {0}"
,
svc.Echo("Hello, world"));
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
Configuring Client EndpointsHardcoding endpoint information into client code is also less than ideal. So WCF
provides a similar configuration mechanism for specifying client endpoints within
. The following application configuration file specifies the
same client endpoint details used in the code:
-
8/8/2019 WCF Comprehensive Overview
16/18
Notice that I've given each client endpoint a name. You can use this name in your
code when creating a ChannelFactory, as illustrated in the following code:
using (ChannelFactory httpFactory =
new ChannelFactory("httpEndpoint"))
{
svc = httpFactory.CreateChannel();
Console.WriteLine("Invoking HTTP endpoint: {0}",
svc.Echo("Hello, world"));
}
Now when you want to create a ChannelFactory for the TCP endpoint, you can
simply change the configuration name to tcpEndpoint. You can also configurebindings in the client configuration file just like I did in the service configuration
file.
If you add this configuration file to the client console application shown in Figure
10, comment out the code to create the ServiceEndpoint objects, and specify the
endpoint names when constructing each ChannelFactory, the result will be the
same.
Generating Client ProxiesThe preceding examples assumed the client had access to the same interface
definition used to implement the service. This is common when .NET is used to
implement both sides (in traditional .NET remoting scenarios), but that's not
always the case, and it's never the case when the service wasn't implementedwith the .NET Framework. The preceding examples also assumed the client knew
the precise endpoint details in advance, which isn't always common either.
When clients don't have access to such information, they can discover it using the
WS-MetadataExchange specification. Services share endpoint descriptions with
clients through WSDL definitions. Most service platforms provide tools for
generating client-side code from WSDL definitions. The WinFX SDK provides
SvcUtil.exe for this purpose.
When executing SvcUtil.exe, you specify the URL of the WSDL definition and it
will generate the necessary .NET code and configuration elements that define the
endpoints and bindings used by the service endpoints. Figure 11 shows the
output of running SvcUtil.exe against http://localhost:8080/echo. Notice that it
generates two files: EchoService.cs and output.config.
Figure 11 SvcUtil.exe Output
-
8/8/2019 WCF Comprehensive Overview
17/18
EchoService.cs contains a .NET interface definition equivalent to the one the
service implemented. Output.config contains the client endpoint information
needed to access the service (similar to what I just wrote manually). You'll need
to merge the contents of output.config with your application configuration file
manually. With this in place, you can write client code using the same techniques
shown in the previous examples, only using the generated interface and
configuration file.In general, the WCF client programming model is explicit about the service
boundary. You create a typed channel against a specific service endpoint and
then send messages through it. Although this helps emphasize the tenets of
service orientation, it can be tedious to work at this level all the time. To help
you, SvcUtil.exe also generates a proxy class that completely hides the
ChannelFactory and ServiceEndpoint creation details. If you open EchoService.cs,
you'll find the following class definition:
public partial class EchoServiceProxy :
System.ServiceModel.ClientBase, IEchoService
{
public EchoServiceProxy(){
}
public EchoServiceProxy(string endpointConfigurationName)
:
base(endpointConfigurationName)
{
}
...
This proxy class can simplify your client application code. All you have to do is
instantiate the proxy, specify the name of the endpoint configuration, and make
method calls. Here's an example:
using (EchoServiceProxy proxy = new EchoServiceProxy("IEchoSer
vice"))
{
// invoke service operation
Console.WriteLine("Invoking HTTP endpoint: {0}",
proxy.Echo("Hello, world"));
}
using (EchoServiceProxy proxy = new EchoServiceProxy("IEchoSer
vice1"))
{
// invoke service operation
Console.WriteLine("Invoking TCP endpoint: {0}",proxy.Echo("Hello, world"));
}
The generated configuration file (output.config) defines the IEchoService and
IEchoService1 endpoint configurations.
Logging MessagesAs you begin working with the WCF programming model, you may find it useful to
trace the SOAP messages traveling between clients and services. Windows
-
8/8/2019 WCF Comprehensive Overview
18/18
Communication Foundation provides built-in support for message logging, which
can be turned on through your application configuration file.
Figure 12 SvcTraceViewer.exeSvcConfigEditor provides a Diagnostics tab where you can enable the messaging
logging features. Once you enable messaging logging and rerun the app, you'll
see the trace file appear in the specified location. The WinFX SDK also provides
SvcTraceViewer.exe for viewing the information in a trace file (see Figure 12).
ConclusionWCF is a new step in distributed programming for developers using the .NET
Framework. If you currently build systems using any of today's .NET distributed
technologies, it's time to start paying attention to WCF and the future it holds.
It's only a matter of time before all .NET-targeted code related to
communications will be written using WCF.
Note that all of the code samples shown in this article are based on Visual Studio2005 and the WCF November 2005 CTP.
Aaron Skonnard is a co-founder ofPluralsight, a Microsoft .NET training
provider. Aaron is the author ofPluralsight's Applied Web Services 2.0, Applied
BizTalk Server 2006, and Introducing WCF courses. Aaron has spent years
developing courses, speaking at conferences, and teaching professional
developers. Reachhim at pluralsight.com/aaron.