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 Visual Studio.
Note:Visual Studio 2008 includes productivity tools for WCF that are available only in CTP format for Visual Studio 2005.
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.
1. 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.
2. 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.
Two files are generated: HelloIndigoService.cs and IHelloIndigoService.cs.
3. Open IHelloIndigoService.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(); }
4. Open HelloIndigoService.cs and modify the service implementation 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"; } }
5. Open Program.cs and add code to the new Main() entry point so that it looks as follows:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(HelloIndigoService))) { host.Open(); Console.WriteLine("Press <ENTER> to terminate the host application"); Console.ReadLine(); } } } }
6. Compile the Host project.
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.
1. From Solution Explorer,go to the Host project and open the app.config file.
A sample configuration has been created by the WCF Service template added in the previous section—but you will create a similar configuration from scratch.
Delete this configuration so that the configuration file contains only the following:
<?xml version="1.0" encoding="utf-8" ?> <configuration> </configuration>
2. From Solution Explorer,right-click on the app.config file.
Select Edit WCF Configuration.
You’ll see the Service Configuration Editor interface shown in Figure 1-21.
Figure 1-21. Service Configuration Editor for WCF
Note:If the context menu Edit WCF Configuration does not appear you may have to open the Service Configuration Editor once from the main menu.
Select Tools ? WCF Service Configuration Editor to launch the editor, close the dialog and retry the context menu.
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:
a. 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.
Figure 1-22. The service type browser lists all service types in a particular assembly
b. 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.
c. Select HTTP as your service communication mode and click Next.
d. Select Basic Web Services interoperability as your interoperability method and click Next.
e. 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.
f. Review the configuration you have chosen for the service, then click Finish.
3. 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.
Figure 1-23. Configuring a service endpoint using the Service Configuration Editor
4. 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.
5. 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).
6. 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,IMetadataExchange.
需要注意的是此处Contract类型是手动输入的,不是通过浏览来加载的(如果有可以浏览的,是可以通过浏览加载的)
7. 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.
8. 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.
Example 1-5. Service model configuration generated by Service Configuration Editor
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="serviceBehavior"> <serviceMetadata /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="serviceBehavior" name="Host.HelloIndigoService"> <endpoint address="HelloIndigoService" binding="basicHttpBinding" bindingConfiguration="" name="basicHttp" contract="Host.IHelloIndigoService" /> <endpoint binding="mexHttpBinding" bindingConfiguration="" name="mex" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8000/HelloIndigo" /> </baseAddresses> </host> </service> </services> </system.serviceModel> </configuration>
9. Compile the Host project and then run it without debugging. Leave the host running for the next step.
Note:In Visual Studio 2008,you cannot add a service reference to a client application while the service is running in debug mode within the same Visual Studio instance.
If you run the host project without debugging you will be able to add a service reference.
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.
1. 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 set the namespace to localhost.
When you click OK to close this dialog,a service proxy and configuration file will be generated for the client application.
To see the proxy,go to the Client project and expand the Service References folder.
Beneath it you will see Reference.svcmap,and beneath that Reference.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.
2. 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.
static void Main(string[] args) { try { localhost.HelloIndigoServiceClient proxy = new Client.localhost.HelloIndigoServiceClient(); string s = proxy.HelloIndigo(); Console.WriteLine(s); Console.WriteLine("Press <ENTER> to terminate Client."); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.ReadLine(); }
Example 1-6. Using a generated proxy to invoke a service
Compile the solution and run the Client project.
The client’s console output should show the result of invoking the service’s HelloIndigo operation.
After testing, stop debugging the Client project and close the Host console.
Note:Most labs and sample code from this book use the same port numbers for HTTP and TCP respectively.
Thus,if you forget to close down a host that is using a particular port number,
and try to run a different host that uses the same,
you will see an error since the port is already in use.
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.
1. 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.
2. Rename Service1.cs and HelloIndigoService.cs and Service1.cs to IHelloIndigoService.cs and HelloIndigoService.cs, respectively.
3. Modify the service contract that is supplied by the project template.
Open IHelloIndigoService.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( );
}
4. Now,modify the service implementation so that it implements the new contract.
Open HelloIndigoService.cs,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.
Note:The default data contract created when you used the WCF Service template, the CompositeType class, is not necessary for this lab.
5. Delete the app.config file created for the HelloIndigo project,and then compile the project.
Note:The release of Visual Studio 2008 and .NET Framework 3.5 introduced a WCF Service Host and a WCF Test Client to simplify testing WCF services.
When you create a new WCF Service Library the app.config file is used to configure the WCF test host.
I’ll briefly discuss these test tools in a later section.
6. Now you will modify the existing host project so that it hosts this new service.
From Solution Explorer,go to the Host project and select the files IHelloIndigoService.cs and HelloIndigoService.cs.
Right-click on the selection and select Exclude From Project to avoid collision with the HelloIndigo library you’re about to reference.
7. 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.
8. The ServiceHost must be modified to refer to the service type from this project.
In the Program.cs file,modify the ServiceHost constructor to use the fully qualified name of the service, HelloIndigo.HelloIndigoService, as shown here:
host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService))
9. 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:
<service behaviorConfiguration="serviceBehavior" name="HelloIndigo.HelloIndigoService">
<endpoint address="HelloIndigoService" binding="basicHttpBinding" name="basicHttp" contract="HelloIndigo.IHelloIndigoService" />
<!-- other settings -->
</service>
10. 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.
1. First,run the Host project without debugging so that the endpoint is available to generate a proxy.
From the Windows Start menu,find the Microsoft Visual Studio 2008 program group and launch the Visual Studio 2008 Command Prompt beneath the Visual Studio Tools folder in the program group.
Run the following command to generate a new proxy for the client application and replace the application configuration settings generated previously:
svcutil /d:<YourLearningWCFPath>\Labs\Chapter1\HelloIndigo\Client /o:serviceproxy.cs /config:app.config http://localhost:8000/HelloIndigo
The output should look similar to Figure 1-24.
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:
svcutil /d:c:\LearningWCF\Labs\Chapter1\HelloIndigo\Client /o:serviceproxy.cs/config:app.config http://localhost:8000/HelloIndigo
If your path includes spaces,such as c:\Learning WCF,then you will have to provide quotes to the path, as shown here:
svcutil /d:"c\Learning WCF\Labs\Chapter1\HelloIndigo\Client" /o:serviceproxy.cs/config:app.config http://locahost:8000/ HelloIndigo
2. 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 localhostreference.svcmap beneath Service References\localhost 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( ))
3. Compile and run the Client and test the solution once again.
Now let’s examine some of the ideas introduced in this lab in greater detail.