change to display the request and response values. Unlike the very basic test page for ASP.NET Web
Services, the WCF Test Client can help you simulate calls to WCF services that contain complex
types. In Figure 31-7, you can see that in the Request section each parameter is displayed, and the
customer object parameter of the AddCustomer operation has been broken down with data entry
fields for each of its properties (those that were marked with the DataMember attribute). After
setting values for each of these properties you can then invoke the operation by clicking the Invoke
button. Figure 31-8 also shows that any return value will be displayed in a similar layout in the
Response section of the tab.
fiGure 31-8
If you are trying to isolate an issue it can be useful to see exactly what information is traveling
down the wire for each service request. You can do this using third-party tools such as Fiddler,
but for a simple XML representation of what was sent and received you can simply click the
XML tab. Figure 31-9 shows the body XML for both the request and the response. You will
notice that there is additional XML due to the request and response each being wrapped in a
SOAP envelope.
694 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
fiGure 31-9
This is fine while you are debugging the service, but in production you will need to properly host
your service. You have a lot of ways to host your service, and how you choose to do so really
depends on your scenario. If it’s a situation where the service is acting as a server (which clients
communicate with) and communicates via HTTP, then Internet Information Services (IIS) is
probably your best choice. If your service is being used to communicate between two applications,
your application itself can be used to host the service. Other options you may wish to consider are
hosting the service in a Windows Service, or (if the host machine is running Windows Vista/7 or
Windows Server 2008) under Windows Process Activation Services (WAS). We will take a look at
the two most common scenarios: hosting your service in IIS, and hosting it in a .NET application
(which will be a console application).
The first example shows how to host your WCF service in IIS. The first step is to set up the folder
and files required. Create a new folder (under your IIS wwwroot folder, or anywhere you choose)
with a name of your own choosing, and create another folder under this called bin. Copy the
compiled service assembly (that is, the .dll file) into this folder. Also take the App.config file
and copy it into the folder one level higher (that is, the first folder you created), and rename it to
web.config.
Now you need to create a simple text file (in the Visual Studio IDE, Notepad, or a text editor of
your choice) and call it CustomerService.svc (it can be any name, but it does require the .svc
extension). Put this line as the contents of the file:
<%@ServiceHost Service="Chapter31SampleCS.CustomerService"%>
Essentially, this specifies that IIS should host the service called Chapter31SampleCS.
CustomerService (which it expects to find in one of the assemblies in the bin folder).
Hosting WCf services .
695
In summary, you should have a CustomerService.svc file and a web.config file in a folder, and
the service assembly (dll) in the bin folder below it. Ensure (in the folder permissions) that the IIS
process has read access to this folder.
Now you need to configure the service in IIS. Open IIS, and under the default web site add a new
application. Give it a name (such as CustomerService), and specify the folder created earlier as its
physical path. Also make sure you select to use the ASP.NET v4.0 application pool (so it will use V4
of the .NET Framework), and that should be it!
You can then navigate to the service’s URL in a browser to see if it works, and use the WCF Test
Client to actually test the operations.
If you create the project using the WCF Service Application project template, the
correct structure and required files will already be created for you and ready to
host under IIS.
The other example goes through hosting the WCF service in a .NET application (known as a self - hosted
service). You can either put the service code (created previously) directly in this project, or reference
the service project you created earlier. For this example, just create a simple console application to act
as the host, and reference the existing service project. Create a new console application project in
Visual Studio called CustomerServiceHost, and add a reference to the service project. You will also
need to add a reference to the System.ServiceModel assembly. Copy the App.config fi le from the
service project into this project (so you can use the service confi guration previously set up).
Use the following code to host the service:
Vb
Imports System.ServiceModel
Imports Chapter31SampleVB
Module CustomerServiceHost
Sub Main()
Using svcHost As New ServiceHost(GetType(CustomerService))
Try
'Open the service, and close it again when the user presses a key
svcHost.Open()
Console.WriteLine("The service is running...")
Console.ReadLine()
'Close the ServiceHost.
svcHost.Close()
Catch ex As Exception
Console.WriteLine(ex.Message)
Console.ReadLine()
End Try
696 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
End Using
End Sub
End Module
c#
using System;
using System.ServiceModel;
using Chapter31SampleCS;
namespace CustomerServiceHost
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost serviceHost =
new ServiceHost(typeof(CustomerService)))
{
try
{
// Open the service, and close it again when the user
// presses a key
serviceHost.Open();
Console.WriteLine("The service is running...");
Console.ReadLine();
serviceHost.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}
}
In summary, the configuration for the service is being read from the .config file (although it could
also be specified programmatically), so you just need to create a service host object (passing in the
type of the service to be hosted), and open the host. When you are done you just need to close the host
and clean up!
Now you can run the project and access the service using the URL specified in the .config file. As
you can see, very little code is required to host a WCF service.
consuMinG a wcf serVice
Now that you have successfully created your WCF service it’s time to access it within an application.
To do so add a Windows Forms project to your solution called CustomerServiceClient.
Consuming a WCf service .
697
The next thing is to add a reference
to the WCF service to the Windows Forms
application. Right-click the project node in
the Solution Explorer tool window and select
Add Service Reference. This opens the dialog
shown in Figure 31-10, in which you can
specify the WCF service you want to add a
reference to. As you can see, there is a very
convenient Discover button that you can use
to quickly locate services contained within
the current solution.
Select the ICustomerService node in the
Services tree, change the namespace to
CustomerServices, and click the OK button
to complete the process. The next step is to
create a form that will display/edit data from
the service. Put the code to communicate with the service in the code behind for this form. Start by
adding a using/Imports statement to the top of the code for the namespace of the service:
Vb
Imports CustomerServiceClient.CustomerServices
c#
using CustomerServiceClient.CustomerServices;
Let’s say you have a BindingSource control on your form called customerDataBindingSource, whose
DataSource property you want to set to the list of customers to be retrieved from the service. All
you need to do is create an instance of the service proxy and call the operation, and the data will be
returned.
Vb
Dim service As New CustomerService
customerDataBindingSource.DataSource = service.GetCustomerList()
c#
CustomerService service = new CustomerService();
customerDataBindingSource.DataSource = service.GetCustomerList();
You can now run this application and it will communicate with the WCF service. This example
demonstrated communicating with the WCF service synchronously (that is, the UI thread was paused
until a response had been received from the server), but this has the disadvantage of making your
application unresponsive to the user until the response from the service had been received. Though
calling the service synchronously is easy code to write, it doesn’t provide for a very nice user experience.
Fortunately, you can also call WCF services asynchronously. This allows the client to make a request to
a service, and continue on running without waiting for the response. When a response has been received,
an event will be raised that can be handled by the application from which it can act upon that response.
fiGure 31-10
698 .
chaPter 31 WindoWS communicATion FoundATion (WcF)
Silverlight clients only support asynchronous service calls.
To enable the asynchronous methods to be created on the service proxy you must specifically
request them by selecting the Generate Asynchronous Operations checkbox in the Configure Service
Reference dialog (detailed later in this section). To call the WCF service asynchronously you create
an instance of the service, handle the Completed event for the associated operation, and then call
the operation method that is suffixed with Async:
Vb
Dim service As New CustomerService
AddHandler service.GetCustomerListCompleted, _
AddressOf service_GetCustomerListCompleted
service.GetCustomerListAsync()
c#
CustomerService service = new CustomerService();
service.GetCustomerListCompleted += service_GetCustomerListCompleted;
service.GetCustomerListAsync();
The operation call will return immediately, and the event handler specified will be called when the
operation is complete. The data that has been returned from the service will be passed into the event
handler via e.Results:
Vb
Private Sub service_GetCustomerListCompleted(ByVal sender As Object, _
ByVal e As
GetCustomerListCompletedEventArgs)
customerDataBindingSource.DataSource = e.Result
End Sub
c#
private void service_GetCustomerListCompleted(object sender,
GetCustomerListCompletedEventArgs e)
{
customerDataBindingSource.DataSource = e.Result;
}
When you add a reference to the WCF service to your rich client application you will notice that an
App.config file was added to the project (if it didn’t already exist). In either case, if you take a look
at this file you’ll see that it now contains a system.serviceModel element that contains bindings
and client elements. Within the bindings element you can see that there is a wsHttpBinding element
(this is the default WCF binding), which defines how to communicate with the WCF service. Here
you can see that the subelements override some of the default values. The Client element contains
an endpoint element. This element defines the Address (which in this case is a URL), a Binding
(which references the customized wsHttpBinding defined in the bindings element), and a Contract
summary .
699
(which is the CustomerServices.ICustomerService interface of the WCF service that is to be called).
Because this information is all defined in the configuration file, if any of these elements changes (for
example, the URL of the endpoint) you can just modify the configuration file instead of having to
recompile the entire application.
When you make changes to the service you will need to update the service proxy that was created by
Visual Studio when you added the service reference to your project (otherwise it will remain out of
date and not show new operations added to it, and so on). You can do this by simply right-clicking
the service reference (under the Service References node in your project) and selecting the Update
Service Reference item from the context menu.
If you right-click a service reference (under
the Service References node in your project)
you will also find a Configure Service
Reference option. This will bring up the
dialog shown in Figure 31-11 (which can also
be accessed from the Add Service Reference
dialog by clicking the Advanced button).
This dialog allows you to configure how the
service proxy is generated, with a variety
of options available. Of particular interest
is the Reuse types in referenced assemblies
option. This option (when enabled) means
that if the service reference generator finds
that a type (that is, class/object) consumed/
returned by the service is defined in an
assembly referenced by the client, the proxy
code generated will return/accept objects of
that type instead of creating a proxy class
for it. The big benefit of this is where you manage both ends of the system (both server and client)
and want to pass objects between them that have associated business logic (such as validation logic,
business rules, and so on). The usual process is to (on the client side) copy the property values from
a proxy object into a business object (when requesting data), and then copy property values from
a business object into a proxy object (to pass data back to the server). However, this option means
that you can have both the server and the client reference an assembly that contains the types to be
passed between them (with corresponding business logic code for both ends), and simply pass the
objects backward and forward between the server and the client without requiring a proxy class as
an intermediary (on the client side). This saves you from having to write a lot of property mapping