In the previous lab, you created a service and client from scratch without leveraging
the tools available to WCF developers. Although this helps you to understand the
raw requirements for sending messages between clients and services, in reality, developers
need tools to be productive. This time around, I’ll show you how to use several
such tools that help you to generate services, access metadata, create
configuration settings, and generate proxies. Specifically, you’ll use the following:
Visual Studio service templates
Service Configuration Editor
ServiceModel Metadata Utility (SvcUtil)
The primary goal of the lab in this section will be to improve your productivity for
building clients and services, but several other concepts will be discussed in the process.
To begin with, you’ll use declarative configuration settings instead of code to
configure the service host and client. To enable proxy generation, you’ll access service
metadata, which involves enabling a service behavior. In addition, you’ll learn
more about service configuration settings for base addresses, endpoints, bindings
and behaviors.
After you complete the lab, I’ll spend some time discussing these concepts.
Lab: Using Tools to Generate Clients and Services
In this lab, you will generate service code using two approaches: by adding a service
to an existing host and by generating a new service library, both using Visual Studio
templates. To configure service endpoint for the host, this time you’ll use the Service
Configuration Editor. To generate client proxies and related configuration you’ll use
the ServiceModel Metadata Utility (SvcUtil). Both of these tools are available
through the Solution Explorer in Visual Studio.
Visual Studio extensions for WCF will be part of the next release of
Visual Studio, code-named "Orcas." As such, the user interfaces and
features of these extensions may change from the time of this writing.
Using the WCF Service template
In this first section of the lab, you’ll create a new service using the WCF Service template
and add it to an existing project. This template will add a sample service contract
and service type to the project, along with the required service model assembly
references. Since you will be adding the WCF Service to an executable project (the
host), the template will also generate some code for hosting the service.
Start by opening an existing Visual Studio solution that contains two projects: a
shell console client and host. The solution is located at <YourLearningWCFPath>\Labs\Chapter1\HelloIndigo\HelloIndigo.sln.
First, you will add a new service to the host project. From Solution Explorer,
right-click on the Host project node and select Add -> New Item. Select the WCF
Service template and name the file HelloIndigoService.cs.
Open HelloIndigoService.cs in the code window and add a namespace qualifier
for the service contract, then modify the service operation name and signature to
match the following code in bold:
[ServiceContract(Namespace="http://www.thatindigogirl.com/samples/2006/06")]
public interface IHelloIndigoService
{
[OperationContract]
string HelloIndigo( );
}
Modify the service implementation in the same file to implement the correct
operation signature. This is how the resulting service type should look:
public class HelloIndigoService : IHelloIndigoService
{
public string HelloIndigo( )
{
return "Hello Indigo";
}
}
The WCF Service template also generated a helper class for hosting the service,
named MyServiceHost, located beneath the service type. You’re going to edit
this class and remove the hardcoded base address provided to the ServiceHost
instance.
Locate the StartService( ) method in MyServiceHost and modify it so that a base
address is no longer passed to the ServiceHost constructor. The resulting changes
are shown here:
You’re going to use the hosting helper class to initialize the ServiceHost for the
service. Go to the Host project and open Program.cs. Modify the Main( ) entry
point so that it looks as follows:
At this point, you have defined a service inside the Host project and added code to
host the service, but the implementation is incomplete. The ServiceHost requires at
least one endpoint before clients can invoke the service.
Configuring service endpoints using the Service Configuration Editor
In this section, you will provide an endpoint for the ServiceHost—this time using the
Service Configuration Editor. Unlike in the previous lab, endpoints will be configured
using an external application configuration file. As such, you’ll open the application
configuration file for the Host application using the tool to configure
ServiceHost endpoints in that file.
Go to the Host project and right-click on the app.config file. Select Edit WCF
Configuration. You’ll see the Service Configuration Editor interface shown in
Figure 1-21. Go to the Tasks pane and click "Create a New Service"; the New
Service Element Wizard will be displayed.
Follow these instructions as you go through each page in the wizard:
On the first page, you are asked to provide the service type. Browse to
<YourLearningWCFPath>\Labs\Chapter1\HelloIndigo\Host\Bin\Debug and
select Host.exe. The Type Browser dialog (shown in Figure 1-22) will list
Host.HelloIndigoService as the only service available in the assembly. Select
it from the list and click Open. Click Next to continue.
Now you will be asked to specify a service contract. There is only one service
contract implemented by HelloIndigoService, so the selected service
contract should be Host.IHelloIndigoService. Click Next to continue.
Select HTTP as your service communication mode and click Next.
Select Basic Web Services interoperability as your interoperability method
and click Next.
Now you’ll be asked to provide an endpoint address. Here you can provide a
relative address by clearing the current text and typing "HelloIndigoService."
Click Next.
Review the configuration you have chosen for the service, then click Finish.
Go to the Configuration pane in the Service Configuration Editor interface and
expand the Endpoints folder beneath Host.HelloIndigoService. Select the only
endpoint labeled (Empty Name).
Go to the Service Endpoint pane, and in the General tab, provide the name
basicHttp as shown in Figure 1-23. At this point, you have created a single, relative
service endpoint.
In this lab, the client will generate a proxy using SvcUtil. To support this,
you’ll enable the metadata exchange behavior by adding a behavior to the service
configuration.
Go to the Configuration section and expand the Advanced folder. Select Service
Behaviors and go to the Tasks pane to select New Service Behavior Configuration.
Go to the Behavior pane and set the configuration name to serviceBehavior.
Click the Add button to add a behavior element and select serviceMetadata from
the list provided.
Go to the Configuration pane and you’ll now see a new serviceMetadata node
beneath serviceBehavior. Select the node and review the default settings in the
General tab.
The behavior must be explicitly associated to the service. Go to the Configuration
pane and select the service node, Host.HelloIndigoService. Go to the Service
pane and set the BehaviorConfiguration property to serviceBehavior (you
can select it from the dropdown list).
Enabling the metadata behavior is a good start, but a new endpoint is also
required to support metadata exchange. Go to the Configuration pane, rightclick
on the Endpoints folder, and select New Service Endpoint.
Go to the Service Endpoint pane and set the name to mex. In the Endpoint Properties
section, set the Binding to mexHttpBinding. For the Contract property type,
select IMetadataExchange.
In order to support metadata exchange, the host must have a base address for
the metadata exchange protocol being used. In addition, since you supplied a
relative address for the service endpoint, it also requires a base address matching
the binding protocol. In this case, an HTTP base address will be used.
Go to the Configuration pane and select the Host node beneath Host.
HelloIndigoService. Go to the Host pane and select New to create a new base
address. From the Base Address Editor, supply the following base address: http://
localhost:8000/HelloIndigo.
Save the configuration settings you just generated. Select File . Save followed by
File -> Exit. Return to Visual Studio and open the app.config for the Host project.
You will see a <system.serviceModel> section like the one shown in Example 1-5.
Compile the Host project and then run it. Leave the host running for the next step.
Example 1-5. Service model configuration generated by Service Configuration Editor
You just created a declarative configuration for the ServiceHost, instead of programmatically
initializing its base addresses and service endpoints. In addition, you
enabled the service metadata behavior and created a metadata exchange endpoint so
that clients can generate a proxy using SvcUtil. That’s the next step.
Generating a proxy with Add Service Reference
It’s time to generate code for the client to consume the service, starting by generating
a client proxy. To achieve this you will use the Add Service Reference functionality
exposed by Visual Studio, which uses the ServiceModel Metadata Utility (SvcUtil)
to generate a proxy and configuration settings for that proxy.
Go to the Client project and from Solution Explorer, right-click on the Client
project node and select Add Service Reference. The dialog presented requires
you to provide a valid base address to the service. Supply the base address http://localhost:8000/HelloIndigo and leave the Service reference name as localhost.
When you close this dialog, a service proxy and configuration file will be generated
for the client application. Stop debugging so you can add code to the client
application.
To see the proxy, go to the Client project and expand the Service References
folder. Beneath it you will see localhost.map, and beneath that localhost.cs—the
latter of which contains the proxy.
A new configuration file, app.config, was also added to the project. This contains
the service model configuration for the proxy. Later I’ll talk about how
these things come together.
Add code to the client application to invoke the service using the generated
proxy. Go to the Client project and open Program.cs. Add code to the Main( )
entry point as shown in bold in Example 1-6.
Compile the solution and run the Host project, followed by the Client. The client’s
console output should show the result of invoking the service’s HelloIndigo
operation.
Example 1.6. Using a generated proxy to invoke a service
static void Main(string[] args)
{
localhost.HelloIndigoServiceClient proxy = new
Client.localhost.HelloIndigoServiceClient( )
string s = proxy.HelloIndigo( );
Console.WriteLine(s);
Console.WriteLine("Press to terminate Client.");
Console.ReadLine( );
}
This concludes one technique for generating a service, ServiceHost configuration,
and a client proxy.
Creating a WCF Service Library
In this section, you will generate a service using another technique: adding a new
class library that includes a WCF service. The WCF Service Library template is a
quick and easy way to generate a new class library with a sample service contract,
service type, and the appropriate assembly references.
Go to the Solution Explorer and right-click on the solution node. Select Add ->
New Project and select the WCF Service Library template. Name the project
HelloIndigo.
Rename the class file from Class1.cs to HelloIndigoService.cs.
Modify the service contract that is supplied by the project template. Open
HelloIndigoService.cs in the code window and provide a namespace for the
ServiceContractAttribute and change the interface definition to look as follows:
[ServiceContract(Namespace="http://www.thatindigogirl.com/samples/2006/06")]
public interface IHelloIndigoService
{
[OperationContract]
string HelloIndigo( );
}
Now, modify the service implementation so that it implements the new contract.
Rename the service to HelloIndigoService and implement IHelloIndigoService as
shown here:
public class HelloIndigoService: IHelloIndigoService
{
public string HelloIndigo( )
{
return "Hello Indigo";
}
}
Compile the HelloIndigo project.
The default data contract created when you used the WCF Service
template is not necessary for this lab.
Now you will modify the existing host project so that it hosts this new service.
Go to the Host project and open HelloIndigoService.cs. Comment the entire service
contract and implementation to avoid collision with the HelloIndigo library
you’re about to reference.
Add a reference to the HelloIndigo class library project. Right-click on the Host
node and select Add Reference. From the Projects tab, select the HelloIndigo
project.
The ServiceHost must be modified to refer to the service type from this project.
In the HelloIndigoService.cs file, find the StartService( ) method and modify
the ServiceHost constructor to use the fully qualified name of the service,
HelloIndigo.HelloIndigoService, as shown here:
myServiceHost = new ServiceHost(typeof(HelloIndigo.HelloIndigoService));
You’ll also have to edit the service model section of the configuration file to use
the correct service and contract types. Go to the Host project and open the app.config file. Change the service type and contract type for the <service> configuration
section as shown here in bold:
Test the solution again by compiling and running the Host and then the Client.
Now you have learned how to create a new class library with a sample WCF service
and seen the changes required to the service model configuration and ServiceHost to
reference a different service type.
Generating a proxy using the Service Model Metadata Utility
In this section, you will generate a client proxy using the SvcUtil directly instead of
using Add Service Reference. The purpose of this exercise is to show you how to
exercise greater control over the generation of proxies and configuration settings.
First, run the Host project so that the endpoint is available to generate a proxy.
From the Windows Start menu, find the Microsoft Visual Studio 2005 program
group and launch the Visual Studio 2005 Command Prompt. Run the following
command to generate a new proxy for the client application and replace the
application configuration settings generated previously:
The /d: option for SvcUtil allows you to provide a path where output
files will be generated. In the Preface, I explained that I would be using
the term <YourLearningWCFPath> to refer to your base path—where
you unzipped the file provided with the book. Thus, if your base path is
c:\LearningWCF, then your SvcUtil command in this example would be:
To use this proxy you’ll have to modify the client application. Go to the Client
project. If you select the "Show all files" icon in Solution Explorer, you’ll see a
new file beneath the project node. Right-click serviceproxy.cs and select "Include
in Project." Right-click localhost.map beneath Service References and select
"Exclude from Project."
Now open Program.cs and modify the code that constructs the service proxy. The
proxy that was generated does not belong to a namespace, so you must remove the
fully qualified name for HelloIndigoServiceClient. The resulting code is:
using (HelloIndigoServiceClient proxy = new HelloIndigoServiceClient( ))
Compile and run the solution once again.
Service Templates
This lab introduces several Visual Studio templates for generating service code. In an
existing project—no matter whether it is a class library, console application, Windows
application, or web site—you can add a new WCF Service. This template generates
a sample service contract and service type to get you started. If you add the
WCF Service to an executable project, the template also supplies a helper class for
hosting the service. When you want to create a class library for your services, you can
create a WCF Service Library project. This template creates a new class library,
including a sample service contract and service type. In this case, the assumption is
that you’ll create a separate host for the service (my personal preference). Using each
of these templates also adds the appropriate service model assembly references to
save you the trouble.
Service templates for web sites are slightly different from other projects because the
hosting environment is slightly different. The overall result is the same—sample code
is generated and assembly references are added. The difference is that an additional
file is generated with a .svc extension for web hosting. You’ll see this in the next lab.
ServiceModel Metadata Utility
The ServiceModel Metadata Utility is a command-line tool that is installed with the
Windows SDK for .NET 3.0—an executable file named svcutil.exe. This tool can be
used for two key purposes:
To generate code and configuration settings from metadata
To generate metadata from code and configuration
With SvcUtil you can export and import metadata, validate services, and manipulate
how types are generated and shared between services and clients. Add Service Reference
uses SvcUtil to generate proxies and configuration, but from the command line,
you can exercise greater control over this process.
This lab illustrates a very simple command-line instruction for generating a proxy
and configuration file from a metadata exchange endpoint as follows:
To see all the options for SvcUtil, from the command line you can type:
svcutil /?
Using Add Service Reference to generate the client configuration and proxy will work
for many cases, but there are some cases in which you need to exercise control over
things such as how arrays are handled, to make asynchronous calls to the proxy, and
to share types with the service. I’ll explore other uses for SvcUtil throughout this
book.
Service Configuration Editor
The Service Configuration Editor is another tool that is installed with the Windows
SDK for .NET 3.0—an executable file named svcconfigeditor.exe. This tool is a wizard
that helps you configure service model settings for WCF clients and services. You
can launch the Service Configuration Editor directly from Solution Explorer to edit
the <system.serviceModel> section for any client or host application configuration file
(as the lab illustrates). The wizard guides you through steps to configure services,
bindings, behaviors, and more, which is particularly useful when you are new to
WCF since you may not be familiar with each section of the configuration file.
The service model configuration for clients and service are both encapsulated within
the <system.serviceModel> configuration section so you can use this tool to edit both
sides. When starting from scratch, you can use the tool to add new services or client
endpoints, to attach behaviors to services or endpoints, to supply base addresses for
the host, to supply metadata exchange endpoints, and even to customize binding
configurations (something I’ll talk about in Chapter 3). For existing applications, you
may just use the tool to view settings and make minor changes.
As I show you configuration settings throughout this book, I’ll talk about many settings
in the <system.serviceModel> section—all of which can be configured using the
Service Configuration Editor. But you’ll find that as you gain more experience with
<system.serviceModel> settings, it is much more productive to edit the configuration
file directly, relying on Intellisense.
ServiceModel Configuration
This lab illustrates the use of declarative configuration settings to configure the
ServiceHost and the client proxy—although, in the latter case, you generated the
configuration. Both ServiceHost and proxy types rely on programmatic or declarative
configuration to initialize endpoints and configure behaviors. The latter technique
provides greater deployment flexibility while programmatic settings enable
you to enforce certain settings. In this section I’ll focus on the service model configuration
settings.
All configuration settings related to the service model are contained within the
<system.serviceModel> section new to WCF. Any application configuration file can
contain this section, which means app.config for executables, and web.config for web
sites. The service model is vast and there are many configuration options, most of
which will be explored throughout the book. However, the core elements of this
configuration you will repeatedly use are: <services>, <client>, <bindings>,
<behaviors>. Table 1-1 provides a brief explanation of each section.
Service model configuration settings can also be set at runtime through the proxy or
ServiceHost; however, declarative configuration is often preferred to hardcoding settings
in code. You can modify configuration files without impacting the compiled
service or client code and this supports more flexible deployment scenarios.
Throughout this book, you will see examples that configure the service
model in code where there are practical applications for it.
ServiceHost Initialization
The first lab illustrates how to configure the ServiceHost programmatically. This lab
illustrates how to configure the ServiceHost declaratively using the service model
configuration section. But how does the ServiceHost know which configuration section
to use? When the ServiceHost is opened, it reads the <services> section looking
for a <service> element that matches its service type. From the lab, consider this
ServiceHost constructor:
ServiceHost myServiceHost = new ServiceHost(typeof(HelloIndigo.HelloIndigoService));
The ServiceHost will look for a section using the name HelloIndigo.
HelloIndigoService, as shown here:
The <service> element can include base addresses and service endpoints, as
shown previously in Example 1-5. You can supply a base address for any protocol
so that you can expose relative service endpoints over that protocol. The following
illustrates the <host> section with base addresses for HTTP, TCP, and named
pipe protocols:
One or more <endpoint> sections may also be provided. As discussed previously, an
endpoint is defined by an address, contract, and binding. If address is omitted altogether,
the base address for the related binding protocol is used (and required). If the
address omits the full URI, it is appended to the base address matching the binding
protocol. However, you can specify a complete address that ignores the base address.
The following illustrates these three choices for an endpoint configuration:
Endpoints have to be unique for a particular service. When multiple endpoints are
exposed by a service, they must differ in address, contract, or transport protocol.
There are several reasons why a service may expose multiple endpoints,
including the following:
The service implements multiple contracts, each requiring its own
endpoint
The same or different service contracts must be accessible over
multiple protocols
The same or different service contracts must be accessible by clients
with different binding requirements, possibly related to security,
reliable messaging, message size, or transactions<
/ul>
These topics will be explored throughout the book.
Enabling Metadata Exchange
A metadata exchange endpoint is required to support the dynamic generation of
proxy and configuration for client applications. You must explicitly enable metadata
exchange by adding the endpoint and enabling the metadata exchange behavior.
A metadata exchange (mex) endpoint is just like any other service endpoint in that
it requires an address, contract, and binding. The address for a metadata
exchange endpoint requires a base address for the selected binding protocol. The
contract must be IMetadataExchange, a predefined service contract belonging to
the System.ServiceModel.Description namespace (see Example 1-7).
Example 1-7. IMetadataExchange contract as defined by the service model
As for the binding, there are several predefined mex bindings, including
MexHttpBinding, MexHttpsBinding, MexTcpBinding, and MexNamedPipeBinding. That
means you can expose a mex endpoint over HTTP, HTTPS, TCP, or named pipes
and have SvcUtil consume those endpoints.
Like any other endpoint, metadata exchange endpoints can also be
consumed at runtime by clients. Applications can call mex endpoints
to dynamically generate proxies or just to request information about
the associated service.
The following illustrates a service exposing two TCP endpoints: one for the service,
another for metadata exchange:
Supplying the endpoint is not sufficient on its own. The service metadata behavior
must also be enabled. Example 1-5 shows you how to enable the behavior by associating
a service behavior to the service and including the <serviceMetadata> element.
Once the behavior is enabled, you can use SvcUtil for proxy generation against any
mex endpoint. For example, to generate a service proxy and configuration using the
TCP endpoint with SvcUtil, you can type this instruction at the command line:
It might seem a little annoying at first that you have to enable metadata
exchange before you can generate a client proxy. This opt-in
behavior is actually a good thing in the long run. You don’t want your
services exposing endpoints of which you aren’t aware or that you
don’t want to support.
Working with Behaviors
As you’ve seen, the ServiceHost is initialized by the <service> configuration section
associated with its service type. At least one endpoint must be configured for the service
to be useful to clients. In this lab, a single service endpoint and a metadata
exchange endpoint are exposed—both over HTTP. While endpoints describe where
to reach the service, which operations are available at the specified address, and what
protocols are required—behaviors affect the service model locally at the client or service.
What that means is that behaviors are not exposed as part of metadata, and
they are not shared between clients and services. Instead, they locally affect how the
service model processes messages.
Behaviors can be defined in configuration or in code. Different behaviors are available
to clients and services, since the local affect on the service model also differs.
Service behaviors
Service behaviors are types that implement IServiceBehavior from the System.
ServiceModel.Description namespace. There are service behaviors to control debugging,
metadata, security features, serialization, and throttling. When enabled, each
behavior interacts with the service model to achieve its goal. For example, when the
metadata behavior is enabled, the service model will allow requests to a metadata
exchange endpoint. Otherwise, it will not.
Service behaviors are configured in the <serviceBehaviors> section. The following
example illustrates enabling service debug and service metadata behaviors:
You may forget to make the association between the service and
behavior at least a few times. Don’t forget to double-check your configuration
when you aren’t seeing the expected results at runtime!
You can also programmatically configure service behaviors through the ServiceHost
instance. The Description property of the ServiceHost has a Behaviors collection.
You can see if a behavior exists by calling the Find<T>( ) method on the collection.
You can add new behaviors by calling Add( ) on the collection. Example 1-9 shows an
example that looks to see if the ServiceMetadataBehavior exists, and if not adds it to
the collection and enables browsing.
Example 1-9. Adding the metadata service behavior programmatically
ServiceHost host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService);
ServiceMetadataBehavior mexBehavior =
host.Description.Behaviors.Find<ServiceMetadataBehavior>( );
if (mexBehavior == null)
{
mexBehavior = new ServiceMetadataBehavior( );
mexBehavior.HttpGetEnabled = true;
host.Description.Behaviors.Add(mexBehavior);
}
host.Open( );
Client behaviors
Client behaviors implement IEndpointBehavior, also from the System.ServiceModel.
Description namespace. There are client behaviors to control debugging, security,
serialization, timeouts, and routing. Endpoint behaviors interact with the service
model at the client. Endpoint behaviors are configured in the <endpointBehaviors>
section. The following example enables exception debugging for callbacks:
To programmatically configure endpoint behaviors, you can use the object model of
the client proxy. The Endpoint property of the client proxy has a Behaviors collection
through which you can search for existing behaviors and add behaviors—similar
to the way you would for the ServiceHost. Example 1-11 shows an example that
looks to see if the ServiceDebugBehavior exists, and if not adds it to the collection.
Example 1-11. Adding the debug service behavior programmatically
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient( );
ServiceDebugBehavior debugBehavior =
proxy.Endpoint.Behaviors.Find<ServiceDebugBehavior>( );
if (debugBehavior == null)
{
debugBehavior = new ServiceDebugBehavior( );
I will explore other behaviors for the client and service throughout this
book as I review features related to each behavior. At this point, I want
you to understand how services and client endpoints are related to
behaviors.
Proxy Initialization
For a client to invoke service operations, it must open a communication channel to a
particular service endpoint. This channel is bound to a particular endpoint—its
address, binding, and contract. This is done by creating a proxy.
In the first lab, a proxy is created directly by using the channel factory:
IHelloIndigoService proxy =
ChannelFactory<IHelloIndigoService>.CreateChannel(new BasicHttpBinding( ), new
EndpointAddress("http://localhost:8000/HelloIndigo/HelloIndigoService"));
This approach assumes that:
You have prior knowledge of the endpoint address.
A copy of the service contract definition is locally available.
You have prior knowledge of the required protocols or binding configuration.
If you own both sides (client and service), it is feasible to share an assembly that contains
service metadata and to separately communicate the address and binding
requirements. When you don’t own both sides, generating the proxy is a more effective
way to import the metadata necessary to construct the client channel. In this lab,
the proxy is generated with SvcUtil. This proxy includes a generated copy of the service
contract and a channel wrapper to simplify the client code necessary to consume
the service. SvcUtil also generates the service model configuration necessary to
initialize the proxy.
The service contract generated by SvcUtil looks similar to the contract at the service
with the exception of additional details specified in the ServiceContractAttribute
and OperationContractAttribute, shown in Example 1-12.
Example 1-12. Service contract generated by SvcUtil
[System.ServiceModel.ServiceContractAttribute(Namespace=
"http://www.thatindigogirl.com/samples/2006/06",
ConfigurationName="Client.localhost.IHelloIndigoService")]
public interface IHelloIndigoService
{
[System.ServiceModel.OperationContractAttribute(Action=
The namespace specified by the ServiceContractAttribute is the same as at the service.
This is critical to compatible message serialization.
The SvcUtil that generated the client-side service contract also generated a proxy
type. The proxy type is a partial class that inherits ClientBase<T> from the System.
ServiceModel namespace (T is the service contract type). As shown in bold in
Example 1-13, the proxy exposes service contract operations and internally uses its
reference to the client communication channel to invoke each service operation. In
fact, this inner channel reference is like the one you previously created with the channel
factory.
Example 1-13. Proxy type generated by SvcUtil
public partial class HelloIndigoServiceClient :
System.ServiceModel.ClientBase<Client.localhost.IHelloIndigoService>,
Client.localhost.IHelloIndigoService
{
...overloaded constructors
public string HelloIndigo( )
{
return base.Channel.HelloIndigo( );
}
}
When the first operation is invoked on this proxy, the inner channel is created based
on the endpoint configuration for the proxy. Since in this lab only one endpoint is
available, the construction of the proxy looks something like this:
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient( );
If there are several endpoints to choose from in the <client> configuration section, you
are required to provide an endpoint configuration name to the proxy constructor:
// Proxy construction
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient("basicHttp");
// Endpoint configuration
<endpoint address="http://localhost:8001/HelloIndigo/HelloIndigoService"
binding="basicHttpBinding" name="basicHttp" contract="Host.IHelloIndigoService" />
Once the client channel has been used (by invoking an operation), the proxy is bound
to the endpoint configuration that initialized it. The same proxy instance cannot be
used to invoke another service endpoint, and no changes to protocols or behaviors are
allowed. A new proxy (channel) must be constructed if such changes are required.
Hosting a Service in IIS
How messages reach a service endpoint is a matter of protocols and hosting. IIS can
host services over HTTP protocol, the Windows Activation Service (WAS) can support
others such as TCP and named pipes, and self-hosting can support many protocols
and includes several deployment options such as console or Windows Forms
applications and Windows services. Selecting a hosting environment has nothing to
do with service implementation, but everything to do with service deployment and
overall system design.
This lab will show you how to host an existing service type as part of a web site
hosted in IIS. In the process, I’ll also be illustrating other extended concepts such as:
The WCF Service web site template
Message-based activation
Additional metadata behavior settings
Exporting service descriptions
Consuming service description documents to generate client code
As always, after the lab I’ll describe some of these features in greater detail.
Lab: Creating an IIS Host and Browsing Metadata
For this lab, you will work with an existing solution that contains a completed service
library and shell client application. Using Visual Studio templates, you’ll create a
new IIS web site project that contains a service and modify it to host a preexisting
service. To consume the service, you’ll generate a client proxy from static service
documentation exported using SvcUtil.
Creating a WCF Service web site
The first thing to do is create a WCF-enabled web site using the WCF Service template,
which is new to WCF. When services are added to a web site, the supplied
sample service is accompanied by a .svc file, the web server endpoint.
Open the startup solution for the lab, located at <YourLearningWCFPath>\Labs\Chapter1\IISHostedService\IISHostedService.sln. This solution contains a copy of
the HelloIndigo project from earlier labs and a shell client application.
You are going to create a new web site to host the service. Go to Solution Explorer,
right-click the solution node and select Add -> New Web Site. Select the WCF Service
template and make sure the location type for the new web site is HTTP (see
Figure 1-25). Set the location value to http://localhost/IISHostedService.
When Visual Studio creates a new HTTP web site, a virtual application
is created in IIS pointing to a directory beneath c:\inetpub\
wwwroot (or wherever your Default Web Site is pointing). In
Figure 1-25, the path to the IISHostedService project might be c:\inetpub\wwwroot\IISHostedService.
The WCF Service template generates a new web site with a default service implementation.
You can delete the service implementation since you will be hosting
an existing service. Go to Solution Explorer and expand the App_Code folder for
the web site (see Figure 1-26). There you’ll see the file Service.cs. Delete it from
the project.
Go to the web site project and add a reference to the HelloIndigo project, which
contains the service you’re about to host.
You now can modify the web endpoint for the service so that it is associated
with the correct service type. Open Service.svc in the code window and modify
the @ServiceHost directive to associate the web endpoint with the service type
HelloIndigo.HelloIndigoService, as shown here:
Now, when a request arrives to Service.svc, the service model will activate
a new ServiceHost instance associated with the HelloIndigoService
type.
The WCF Service template also generated configuration settings for the host, but
these settings are based on the service supplied by the template. You must modify
these settings to reflect the correct service contract and service type.
Open the web.config file and find the <service> section. Change the name attribute
of the <service> section to HelloIndigo.HelloIndigoService and change the contract
attribute of the <endpoint> section to HelloIndigo.IHelloIndigoService. While
you’re at it, change the binding to basicHttpBinding instead of wsHttpBinding. The
result is shown here:
You now have a web site that will expose an endpoint to reach HelloIndigoService.
Before generating the client proxy, I’ll show you some useful metadata features.
Browsing service metadata
In this part of the lab, you’ll make changes to the configuration file so that metadata
can be viewed in a browser.
Before making any changes, test the web endpoint in a browser. Go to Solution
Explorer and right-click on the web site project node; select "Set as Startup
Project." Run the web site from within Visual Studio (F5). This launches the service
endpoint located at http://localhost/IISHostedService/Service.svc in a browser.
What you should see is a web page indicating that metadata publishing has been
disabled for the service.
Add metadata support to the service model configuration for the web site. Open
the web.config file and modify the previously generated service behavior to add
the <serviceMetadata> behavior. You will also add a metadata exchange endpoint
for the service. The changes are shown in bold in Example 1-14.
Example 1-14. Adding metadata browsing support to the web host
Run the web site again (F5). This time you should see the service help page in
the browser, providing some instructions for SvcUtil. Leave the browser running
and return to Visual Studio.
Without restarting the host, you’re going to make a change that enables HTTP
GET access to the service metadata. Open the web.config file and set
httpGetEnabled to true for the <serviceMetadata> behavior:
Save this change and return to the browser instance showing the service help page.
Refresh the browser (F5) to see what has changed. This time, you should observe
the SvcUtil instruction has an active link with a ?wsdl suffix after the service endpoint
(see Figure 1-27). Click the link, and you’ll be taken to the WSDL document
for the service (see Figure 1-28).
Exporting metadata for proxy generation
In this part of the lab, you will export the service metadata to a set of files that can
later be distributed and used to generate a proxy, offline. The files exported will be
WSDL documents.
Launch the Visual Studio 2005 Command Prompt. Run the following command
to instruct SvcUtil to export the service metadata and its associated schemas for
the HelloIndigoService:
This will generate two .wsdl files and two .xsd files in the solution directory.
Use these files to generate the application configuration and proxy required for
clients to consume the service. In the same command window, execute the following
command:
The result of this command will be serviceproxy.cs and app.config files generated
for the client application.
Add the two files just generated to the client project. The proxy and configuration
will be used to invoke the service hosted in IIS. Go to the Client project and
refresh the file list in Solution Explorer. You should see the two new files appear;
include them in the project.
Invoke the service using the generated proxy. Open Program.cs in the code window
and modify the Main( ) entry point adding code to create a proxy and
invoke the HelloIndigo( ) operation. The resulting additions are shown in bold
in Example 1-15.
Compile and run the Client project. The output should be similar to that in earlier
labs.
Example 1-15. Invoking a service hosted in IIS through its proxy
static void Main(string[] args)
{
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient( )
string s = proxy.HelloIndigo( );
Console.WriteLine(s);
Console.WriteLine("Press <ENTER> to terminate Client.");
Console.ReadLine( );
}
Web Site Templates
Many web site templates exist for creating new ASP.NET applications, so it shouldn’t
surprise you that there is a template to get you started with WCF. The new WCF Service
template can be used to create a new web site that is file-based or hosted in IIS.
This lab illustrates how to create an IIS-hosted site—the preferred way to test your services
if you want an accurate depiction of security-related behavior. Regardless, if you
create an IIS- or file-based web site, the files generated are the same:
A sample service contract and implementation
A.svc endpoint for the sample service
A web.config file with service model configuration settings for the sample service
Example 1-27. Client endpoints generated for ServiceA and ServiceB
IIS hosting requires a file-based endpoint with a .svc extension. That’s because it
relies on file-extension mappings to determine how incoming requests should be delegated.
The .svc extension is a new extension specific to WCF, and IIS knows to pass
those requests to the service model for processing (via ASP.NET). In this hosting
environment, each unique service must have a .svc endpoint. Chapter 4 discusses hosting
in detail.
The .svc endpoint has one job to do—help the service model find the correct service
type to host. The @ServiceHost directive is the link between the incoming request and
the service model. In theory this directive can point to a service type declared with
inline code based on a source file or belonging to a compiled assembly.
Similar to inline ASMX web services, .svc files can contain the actual source code for
the service contract and type. This makes it possible to deploy just the .svc file without
any accompanying source, as shown in Example 1-16. In this case, the Service
attribute refers to the inline service type, and you can even enable inline debugging
by setting the Debug attribute to true. Although ASP.NET 2.0 introduced the possibility
of compiling this inline code into an application assembly to protect the
source, I still consider this a tight coupling of the service implementation to the hosting
environment—and that doesn’t promote reuse or deployment flexibility.
Example 1-16. Inline service code
<% @ServiceHost Language="C#" Debug="true" Service="MyService" %>
using System;
using System.ServiceModel;
[ServiceContract( )]
public interface IMyService
{
[OperationContract]
string SomeOperation(string myValue);
}
public class MyService: IMyService
{
public string SomeOperation(string myValue)
{
return "Hello: " + myValue;
}
}
Another approach is to associate the .svc file with a code file in the web site as the
original sample service did in this lab. For ASP.NET 2.0 web sites this means placing
the source in the \App_Code directory. In this case, the Service attribute still refers to
the service type, but the CodeBehind attribute is present to indicate the location of its
source file:
This approach still couples the source to the host and lacks autonomous version control
over services apart from their host.
Ultimately, the preferred way to associate a service type with its .svc endpoint is to
add an assembly reference to the project and specify the fully qualified service type in
the Service attribute:
This approach gives you the desired autonomy and reuse for the service.
Message-Based Activation
One of the benefits of using a fully featured host such as IIS or WAS is that it handles
service activation on your behalf as messages arrive to the service. In the first
and second labs in this chapter, you hosted a service in a console application. In all
such self-hosting environments, you must explicitly run the host process before clients
can invoke the service. The ServiceHost instance is constructed and opened
explicitly, and its lifetime is tied to the lifetime of the host process.
IIS and WAS, on the other hand, are system services that are equipped to process
incoming messages even if the ServiceHost has not yet been constructed. For example,
when a request arrives for a particular .svc endpoint, the request is ultimately
forwarded to the service model. The service model looks at the @ServiceHost declaration
to find the associated service type. It then instantiates the ServiceHost instance
for that type on your behalf, within an ASP.NET worker process. The web.config settings
are used to initialize the ServiceHost and then Open( ) is called—at which point
the first request is forwarded to the appropriate channel listener. Once the
ServiceHost has been constructed and opened, subsequent requests for the same service
are directed to it. Simply put, with IIS or WAS hosting, you needn’t manually
create the ServiceHost instance—this is handled for you by the host process. This is
called message-based activation. The details of hosting are discussed in Chapter 4.
Another convenience of IIS and WAS hosting is that you can modify web.config settings
for a service and the changes are reflected in subsequent calls without restarting
IIS or WAS. That’s because changes to configuration files are detected, and if
necessary, a new application domain is constructed to service requests. For example,
if changes to the service model configuration require that a new ServiceHost instance
be constructed to reflect the changes. In a self-hosting environment, new settings are
not known to the host process and thus are not reflected until you restart. You could
optionally build logic into the host to detect changes and recycle any ServiceHost
instances. With IIS and WAS, configuration changes are detected and a new
ServiceHost is created to handle subsequent requests.
Browsing and Exporting Metadata
To consume a service, clients require access to service metadata, including the service
contract, any custom data types, and binding requirements. Earlier in this chapter,
you learned how to enable the service metadata behavior and how to expose a
metadata exchange endpoint to support proxy generation using SvcUtil. This lab
illustrates how to view metadata in the browser and how to export that metadata to
files for offline consumption. This capability is useful for a few reasons:
For debugging purposes, it can be helpful to view the WSDL document, for
example when trying to solve interoperability issues between platforms.
Allowing client developers to eat up web server resources by browsing to dynamically
created metadata is suboptimal. Instead, once the contract is stable, you
should export it and allow developers to browse static files.
It may be helpful to send developers the WSDL document via some other delivery
mechanism such as email. This way they can generate proxies while offline.
Browsing metadata
Services may expose one or more endpoints, all of which are included in the service
metadata. When a WSDL document is generated, for example, this document
describes the contracts exposed across all endpoints. In other words, the WSDL document
is one-to-one with the service. You can browse to any service if they have an
HTTP base address. In the case of self-hosting environments, the <host> section of
the service configuration can supply the base address.
For services hosted in IIS, the base address is the application directory in IIS with the
.svc endpoint. For example, in this lab you would browse to http://localhost/IISHostedService/Service.svc.
When you browse to a service’s base address you are presented with the service help
page. The service model dynamically generates this for you. If you haven’t enabled
the metadata behavior, the help page will still be presented with instructions on how
to do this. If you have enabled the metadata behavior but have forgotten to enable
browsing, you’ll receive the same instructions. In configuration, if you set
httpGetEnabled to true, the help page will produce a link to the WSDL document
(Figure 1-27 and Figure 1-28):
The service metadata behavior is required if you expose a metadata exchange endpoint
for generating proxies, but you may want to explicitly disable both the help
page and metadata browsing by adding the service debug behavior with
httpHelpPageEnabled set to false and by setting httpGetEnabled to false:
The WSDL document is dynamically generated each time metadata is accessed. During
development this is a useful feature to have, but once you publish your service to
production, it may be desirable to suppress dynamic generation to reduce overhead
on the web server. But what if you want to provide a link to static metadata? An
alternative is to leave metadata browsing enabled and provide a static file where the
WSDL document can be retrieved. This is achieved by providing a value for the
externalMetadataLocation attribute:
font class="docsubhead2"> Exporting metadata
To produce a static WSDL document, you can export service metadata using
SvcUtil, as illustrated in this lab. SvcUtil uses the mex endpoint to retrieve service
metadata and save it to a WSDL document that can be stored on the filesystem.
The command switch for SvcUtil to export metadata is /t:metadata. This command
dumps the service metadata to several .wsdl and .xsd files in the specified directory:
The service model spreads the service description across multiple files. These files
have a hierarchical relationship where a root .wsdl imports child .wsdl and .xsd files.
In reality they are all one service description if you denormalize the output. With this
output, you can still use SvcUtil to generate code for client applications as this lab
illustrates.
Master SharePoint with 3 eLearning Seminars Learn how to build a better SharePoint infrastructure and enable powerful collaboration with MVPs Dan Holme and Michael Noel. Register today!
SharePointConnections Conference Fall 2008 Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).
VMworld 2008 - Sign Up Today! Join your peers on September 15-18 at The Venetian Hotel in Las Vegas as VMware hosts VMworld 2008, the leading Virtualization event.
Microsoft® Tech•Ed EMEA 2008 IT Professionals Advance your thinking with new ideas and practical real-world solutions at Microsoft’s FIVE day technical infrastructure conference 3-7 Nov., 2008. Register before 26 September 2008 to save €300.
Order Your SQL Fundamentals CD Today! Learn how to use SQL Server, understand Office integration techniques and dive into the essentials of SQL Express and Visual Basic with this free SQL Fundamentals CD.
Are You Really Compliant with Software Regulations? View this web seminar that will help you with compliance best practices and check out a management solution to assure that you won’t be in jeopardy of an audit.