Share via


Introduction to Windows Communication Foundation

Robert Green
MCW Technologies

Download

Articles in this series

Introduction

There are a number of existing approaches to building distributed applications. These include Web services, .NET Remoting, Message Queuing (MSMQ) and COM+/Enterprise Services. Windows Communication Foundation (WCF) unifies these into a single framework for building and consuming services. Microsoft originally introduced WCF as part of the .NET Framework 3.0 and has continued to enhance it for the .NET Framework 3.5 and Visual Studio 2008. (For more information on WCF, drop by the portal site here: https://msdn.microsoft.com/en-us/netframework/aa663324.aspx).

In this series of tutorials, you’ll see how to use WCF to build distributed applications. This first tutorial introduces the basics of building, hosting and calling a WCF service. Along the way, you’ll learn the basics of WCF, including the role of endpoints, which consists of addresses, bindings and contracts. You’ll also see a variety of techniques you can use for controlling the behavior of your services. (These tutorials assume that you have Visual Studio 2008 installed, along with the .NET Framework 3.5. You can choose to work in either Visual Basic or C#--the steps listed here call out specific differences between the languages, when necessary.)

WCF is a unified programming model for building service-oriented applications. Before you build a WCF service, you will explore what that means.

Build Applications with a Unified Programming Model

Consider the following scenario. You are building a product management system. Basic product information, such as product name, description and price, is stored in a SQL Server database. You have built a front-end application to work with that data.

The distribution center, which is in the building next door, manages inventory. They have a server that hosts the Inventory database and a server that hosts the Inventory component you wrote to manage inventory. What technology will you use to talk to the Inventory component from your front -end application? They are on the same network, so you might choose to use .NET Remoting.

It is now a year later. Your company acquires another company and decides to merge the two distribution centers. The distribution center is now halfway across the country. Your first thought is to continue to use .NET Remoting and simply move the component to a different server.

However, you learn that you also need to make the Inventory component available to a variety of partners, not all of whom are using .NET applications. That rules out .NET Remoting. You could use .NET Remoting for internal clients and Web services for external clients. You could stop using .NET Remoting and use only Web services. Both of these options involve a significant rewrite and testing to upgrade a currently working application.

One of the primary motivations behind Windows Communication Foundation is to provide a single model for building distributed applications. If you built the Inventory component as a WCF service, your front-end could communicate using HTTP. If the distribution center moved back in house a year later, you could simply switch to using TCP. This change would be a simple configuration issue, not an architecture issue.

Build Service Oriented Applications

The application in this scenario is connected. The leading approach to building connected applications is service orientation. No doubt, you have heard of Service Oriented Architecture (SOA), but what is a service-oriented application?

A service is a program that performs a task and that a client application can communicate with through well-defined messages. To call a Web or WCF service, the client passes it a message, which consists of XML. The message will typically include a request for the service to perform an action, such as retrieve or update the inventory information for a product. If the service returns data to the client, it passes back a message, also consisting of XML.

The client and the service need to agree on what the XML will look like. The most common message format is Simple Object Access Protocol (SOAP). SOAP defines the format of XML request and reply messages and how clients and services encode the data in the messages.

In object-oriented programming, objects are tightly coupled. To call the Inventory component, a client application creates an instance of the component and therefore, controls its lifetime. In a service-oriented application, services and clients are loosely coupled. To call the Inventory service, a client does not instantiate an instance of a component. It simply passes a message to the service and may receive a message in return.

Service-oriented applications are loosely coupled. All communication occurs through messages. SOAP defines the format of messages. Contracts define the contents of messages. A service will publish a contract that specifies what methods clients can call, what arguments those methods take and what, if anything, the methods return. The contract can also specify security requirements and whether a transaction is required.

Why Use Windows Communication Foundation?

A distributed application built with Web services is a service-oriented application. ASP.NET Web Services (ASMX) has been available for building Web services since .NET was first released.  Why then do you need Windows Communication Foundation? WCF provides a number of benefits over ASP.NET Web Services, including:

  • Support for sending messages using not only HTTP, but also TCP and other network protocols.
  • The ability to switch message protocols with minimal effort.
  • Support for hosting services on hosts other than a Web server.
  • Built-in support for the latest Web services standards (SOAP 1.2 and WS-*) and the ability to easily support new ones.
  • Support for security, transactions and reliability.
  • Support for sending messages using formats other than SOAP, such as Representational State Transfer (REST).

You now have some context and a high-level overview of WCF. Now, it’s time to build, host and call a WCF service.

Investigate the WCF Templates

To get started, in Visual Studio 2008 select File | New | Project to display the New Project dialog box. In the list of project types, select WCF, displaying the list of templates shown in Figure 1.

Figure 1 - Visual Studio 2008 provides these WCF templates.

If you want to create a basic WCF service, you can select the WCF Service Library project template. You will use this template more often than not when building services. If you want to create a sequential or state machine workflow and expose it as a WCF service, you can select the Sequential Workflow Service Library or State Machine Workflow Service Library template. If you want to create a service that publishes information in the RSS or Atom format, you can select the Syndication Service Library template.

Create a WCF Service Project

For this demonstration, select the WCF Service Library template. Name your project InventoryServiceLibrary. Name your solution IntroToWCFDemo and select an appropriate folder for the project. Click OK to create the project.

At this point, the project contains two files: IService1 and Service1. It also contains a reference to System.ServiceModel. This namespace contains the classes, enumerations, and interfaces you need to build and call a WCF service.

The IService1 file contains the following code:

[ServiceContract]

public interface IService1

 [OperationContract]

 string GetData(int value);

 [OperationContract]

 CompositeType GetDataUsingDataContract(CompositeType composite);

 // TODO: Add your service operations here

<ServiceContract()> _

Public Interface IService1

  <OperationContract()> _

  Function GetData(ByVal value As Integer) As String

  <OperationContract()> _

  Function GetDataUsingDataContract( _

    ByVal composite As CompositeType) As CompositeType

  ' TODO: Add your service operations here

End Interface

This interface defines the service’s contract. The Service1 file contains the code that implements this interface. The contract specifies the methods clients can call, any arguments the methods take and any values the methods return. The ServiceContract attribute identifies this interface as a service contract. To expose a method to clients, you use the OperationContract attribute.

The IService1 file also contains the following code:

[DataContract]

public class CompositeType

 bool boolValue = true;

 string stringValue = "Hello ";

 [DataMember]

 public bool BoolValue

 {

   get { return boolValue; }

   set { boolValue = value; }

 }

 [DataMember]

 public string StringValue

 {

   get { return stringValue; }

   set { stringValue = value; }

 }

}

<DataContract()> _

Public Class CompositeType

  Private boolValueField As Boolean

  Private stringValueField As String

  <DataMember()> _

  Public Property BoolValue() As Boolean

    Get

      Return Me.boolValueField

    End Get

    Set(ByVal value As Boolean)

      Me.boolValueField = value

    End Set

  End Property

  <DataMember()> _

  Public Property StringValue() As String

    Get

      Return Me.stringValueField

    End Get

    Set(ByVal value As String)

      Me.stringValueField = value

    End Set

  End Property

End Class

Clients and services exchange data using XML messages. The WCF runtime uses the Data Contract Serializer to serialize (convert to XML) and deserialize (convert from XML) data. This serializer has the ability to work with basic .NET types such as strings, integers, DateTime, etc. However, it does not have the built-in ability to work with classes and other complex types. To make a class serializable, you can create a data contract by adding the DataContract attribute to the class definition and by adding the DataMember attribute to each member of the class you want to serialize.

To sum up, the service contract describes what the service can do. A data contract defines the data the client and service can exchange.

Before continuing, in the Solution Explorer, rename the IService1 file to IInventoryService. Click Yes when Visual Studio prompts you to rename all references. Then rename Service1 to InventoryService.

Create the Service and Data Contract

To define the service contract for the tutorial’s service, modify the definition of the IInventoryService interface as follows:

[ServiceContract]

public interface IInventoryService

{

  [OperationContract]

  short GetInStock(int productId);

  [OperationContract]

  Product GetProduct(int productId);

  [OperationContract]

  bool UpdateProduct(Product product);

}

<ServiceContract()> _

Public Interface IInventoryService

  <OperationContract()> _

  Function GetInStock(ByVal productId As Integer) As Short

  <OperationContract()> _

  Function GetProduct(ByVal productId As Integer) As Product

  <OperationContract()> _

  Function UpdateProduct(ByVal _product As Product) As Boolean

End Interface

The service provides the GetInStock method to retrieve the current units in stock for a product. This simple method receives an int and returns a short.

The service also provides the GetProduct and UpdateProduct methods. GetProduct receives a product id and returns an instance of the Product class containing more information on a product. UpdateProduct receives an instance of the Product class and returns a boolean. You will call this method to update inventory information for a product. It will return true if the update succeeded.

To define the Product class and the data contract for this service, replace the definition of the CompositeType class with the following:

[DataContract]

public class Product

{

  [DataMember]

  public int ProductId { get; set; }

  [DataMember]

  public string ProductName { get; set; }

  [DataMember]

  public decimal UnitPrice { get; set; }

  [DataMember]

  public short UnitsInStock { get; set; }

  [DataMember]

  public short UnitsOnOrder { get; set; }

}

Public Class Product

  Private productIdValue As Integer

  <DataMember()> _

  Public Property ProductId() As Integer

    Get

      Return productIdValue

    End Get

    Set(ByVal value As Integer)

      productIdValue = value

    End Set

  End Property

  Private productNameValue As String

  <DataMember()> _

  Public Property ProductName() As String

    Get

      Return productNameValue

    End Get

    Set(ByVal value As String)

      productNameValue = value

    End Set

  End Property

  Private unitPriceValue As Decimal

  <DataMember()> _

  Public Property UnitPrice() As Decimal

    Get

      Return unitPriceValue

    End Get

    Set(ByVal value As Decimal)

      unitPriceValue = value

    End Set

  End Property

  Private unitsInStockValue As Short

  <DataMember()> _

  Public Property UnitsInStock() As Short

    Get

      Return unitsInStockValue

    End Get

    Set(ByVal value As Short)

      unitsInStockValue = value

    End Set

  End Property

  Private unitsOnOrderValue As Short

  <DataMember()> _

  Public Property UnitsOnOrder() As Short

    Get

      Return unitsOnOrderValue

    End Get

    Set(ByVal value As Short)

      unitsOnOrderValue = value

    End Set

  End Property

End Class

The Product class has properties for product id, name, price, units in stock, and units on order. When the client wants inventory information on a product, it can create a new instance of this class with the ProductId property set. The client can call the GetProduct method and pass the Product class instance. The service will query a database, set the remaining properties and pass the Product object back to the client.

Implement the Service’s Interface

Next, you will write the code that runs when clients call methods of the service. The service will work with data from the Northwind SQL Server database. If you do not have the Northwind database installed, you can download it from https://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034\&displaylang=en. The download provides scripts for creating the Northwind sample databases.

To create a connection string, select Project | InventoryServiceLibrary Properties to display the Project Designer and select the Settings tab.  If you are using Visual C#, select the This project does not contain a default settings file link.

In the first row of the grid, enter NorthwindConnectionString in the Name column. Select (Connection string) from the Type drop-down list. Click in the Value column and then click the ellipsis () in that column to display the Choose Data Source dialog box.

Select Microsoft SQL Server in the Data source list box if it has not already been selected. Make sure that .Net Framework Data Provider for SQL Server is selected in the Data provider drop down list box and click Continue. The Connection Properties dialog is displayed. In the Server name field, enter localhost, or a period if you are using SQL Server, or .\SQLEXPRESS if you are using SQL Server Express. SQL Server Express is installed by default with Visual Studio 2008.

In the Select or enter a database name drop-down list, select Northwind. Click Test Connection to verify that you created the connection correctly. Click OK to dismiss the dialog box. Close the Project Designer and save your changes if Visual Studio prompts you to do so.

In the Solution Explorer, double click InventoryService. Add the following code to the top of the code file:

using System.Data;

using System.Data.SqlClient;

Imports System.Data

Imports System.Data.SqlClient

Delete the code for the GetData and GetDataUsingDataContract methods. Modify the class so that it implements the IInventoryService interface. If you are using Visual C#, right-click the interface name and select Implement Interface | Implement Interface from the context menu. If you are using Visual Basic, put the cursor at the end of the Implements IInventoryService line and press Enter. Visual Studio adds the GetInStock, GetProduct, and UpdateProduct methods for you.

Modify the GetInStock method so that it retrieves the units in stock for a product. Use the following code:

short unitsInStock = 0;

using (var cnn = new SqlConnection(

  Properties.Settings.Default.NorthwindConnectionString))

{

  using (var cmd = new SqlCommand(

    "SELECT UnitsInStock FROM Products " +

    "WHERE ProductId = @productId", cnn))

  {

    cmd.Parameters.Add(new SqlParameter("@productId", productId));

    cnn.Open();

    using (SqlDataReader dataReader =

      cmd.ExecuteReader())

    {

      while (dataReader.Read())

      {

        unitsInStock = dataReader.GetInt16(0);

      }

    }

  }

}

return unitsInStock;

Dim unitsInStock As Short = 0

Using cnn As New SqlConnection( _

  My.Settings.NorthwindConnectionString)

  Using cmd As New SqlCommand( _

    "SELECT UnitsInStock FROM Products " & _

    "WHERE ProductId = @productId", cnn)

    cmd.Parameters.Add(New SqlParameter("@productId", productId))

    cnn.Open()

    Using dataReader = cmd.ExecuteReader()

      While (dataReader.Read())

        unitsInStock = dataReader.GetInt16(0)

      End While

    End Using

  End Using

End Using

Return unitsInStock

Modify the GetProduct method so that it retrieves the full set of information for a product. Use the following code:

var product = new Product();

using (var cnn = new SqlConnection(

  Properties.Settings.Default.NorthwindConnectionString))

{

  using (var cmd = new SqlCommand(

    "SELECT ProductName, UnitPrice, " +

    "UnitsInStock, UnitsOnOrder FROM Products " +

    "WHERE ProductId = @productId", cnn))

  {

    cmd.Parameters.Add(new SqlParameter(

      "@productId", productId));

    cnn.Open();

    using (SqlDataReader dataReader = cmd.ExecuteReader())

    {

      while (dataReader.Read())

      {

        product.ProductId = productId;

        product.ProductName = dataReader.GetString(0);

        product.UnitPrice = dataReader.GetDecimal(1);

        product.UnitsInStock = dataReader.GetInt16(2);

        product.UnitsOnOrder = dataReader.GetInt16(3);

      }

    }

  }

}

return product;

Dim _product As New Product

Using cnn As New SqlConnection( _

  My.Settings.NorthwindConnectionString)

  Using cmd As New SqlCommand( _

    "SELECT ProductName, UnitPrice, " & _

    "UnitsInStock, UnitsOnOrder FROM Products " & _

    "WHERE ProductId = @productId", cnn)

    cmd.Parameters.Add(New SqlParameter( _

      "@productId", productId))

    cnn.Open()

    Using dataReader As SqlDataReader = cmd.ExecuteReader()

      While dataReader.Read()

        _product.ProductId = productId

        _product.ProductName = dataReader.GetString(0)

        _product.UnitPrice = dataReader.GetDecimal(1)

        _product.UnitsInStock = dataReader.GetInt16(2)

        _product.UnitsOnOrder = dataReader.GetInt16(3)

      End While

    End Using

  End Using

End Using

Return _product

Modify the UpdateProduct method so that it updates the inventory information for a product. Use the following code:

int rowsChanged = 0;

using (var cnn = new SqlConnection(

  Properties.Settings.Default.NorthwindConnectionString))

{

  using (var cmd = new SqlCommand(

    "UPDATE Products " +

    "SET UnitsInStock = @unitsInStock, " +

    "UnitsOnOrder = @unitsOnOrder " +

    "WHERE ProductId = @productId", cnn))

  {

    cmd.Parameters.Add(new SqlParameter(

      "@unitsInStock", product.UnitsInStock));

    cmd.Parameters.Add(new SqlParameter(

      "@unitsOnOrder", product.UnitsOnOrder));

    cmd.Parameters.Add(new SqlParameter(

      "@productId", product.ProductId));

    cnn.Open();

    rowsChanged = (int)cmd.ExecuteNonQuery();

  }

}

return (rowsChanged != 0);

Dim rowsChanged As Integer = 0

Using cnn As New SqlConnection( _

  My.Settings.NorthwindConnectionString)

  Using cmd As New SqlCommand( _

    "UPDATE Products " & _

    "SET UnitsInStock = @unitsInStock, " & _

    "UnitsOnOrder = @unitsOnOrder " & _

    "WHERE ProductId = @productId", cnn)

    cmd.Parameters.Add(New SqlParameter( _

      "@unitsInStock", _product.UnitsInStock))

    cmd.Parameters.Add(New SqlParameter( _

      "@unitsOnOrder", _product.UnitsOnOrder))

    cmd.Parameters.Add(New SqlParameter( _

      "@productId", _product.ProductId))

    cnn.Open()

    rowsChanged = CType(cmd.ExecuteNonQuery(), Integer)

  End Using

End Using

Return rowsChanged <> 0

Test the WCF Service

You just wrote a WCF service. Shortly, you will build a Web project to host the service and a Windows client project that calls it. Before you do that, you should test the service. The quickest and easiest way to do that is to use the WCF Test Client application.

Save your changes and build the solution. Press F5. You should see the popup shown in Figure 2 on the Windows taskbar and the WCF Test Client (see Figure 3).

Figure 2 - When you press F5, you will see this popup.

Figure 3 - You can use the WCF Test Client to test your service.

The WCF Test Client displays the service and its methods (service operations). You can double click each method and test it. To call a service, it must be hosted. When you press F5, the WCF Service Host application starts and hosts the service. To see this, double click the WCF Service Host icon in the Notification Area (see Figure 2) to display the WCF Service Host (see Figure 4).

Figure 4 - The WCF Service Host hosts your service so you can test it.

Return to the WCF Test Client. Double click GetInStock. To retrieve the units in stock for product 1, enter 1 in the Value column in the Request section of the right-hand pane and click Invoke. Click OK to dismiss the security warning. You should see the units in stock in the Response section of the right-hand pane (see Figure 5). Click the XML tab to see the message the client sent and the message the service returned (see Figure 6).

Figure 5 -  You have tested a method that returns a value.

Figure 6 - This is the XML the client sent and the service returned.

Double-click the GetProduct method. Enter 1 in the productId row’s Value column and click Invoke. Click OK to dismiss the security warning. You should see the product’s information in the Response section of the right-hand pane (see Figure 7). Close the WCF Test Client.

Figure 7 -  You have tested a method that returns an object.

Build a Host Application

The WCF Service Host application is handy for quickly hosting services so you can test them. For more robust testing and for production purposes, you will create a host application. The role of the host application is to start and stop the service, listen for requests from clients, direct those requests to the service and send responses back to the clients.

You can host a WCF service in any Windows process that support managed code, including:

  • Internet Information Services (IIS) version 5.1 or above.
  • Windows Process Activation Service (WAS) running on Windows Vista, Windows 7 or Windows Server 2008.
  • A managed application such as a console application, a Windows Forms application or a Windows Presentation Foundation application.

The next tutorial in this series explores the various options you have for hosting a WCF service. In this tutorial, you will host the service using a Web server.

In the Solution Explorer, right-click the IntroToWCFDemo solution and select Add | New Web Site to display the Add New Web Site dialog box. Select WCF Service in the Templates list. Select File System from the Location drop-down list. Select Visual Basic or Visual C# from the Language drop-down list. In the Location text box, enter the solution’s folder and then append \WebHost to the folder name. Click OK.

In the Solution Explorer, expand the App_Code folder. Visual Studio created the IService and Service files. IService contains the same boilerplate interface you saw when you create the InventoryServiceLibrary project and Service contains code to implement that interface. You can include the service’s code in the hosting project and, in fact, that is the default behavior of the WCF Service template. However, you should create the service in a separate project, as you just did. This provides for maximum reuse. Delete the IService and Service files from the WebHost project.

In the Solution Explorer, right-click the WebHost project, and select Add Reference from the context menu. In the Projects tab of the Add Reference dialog box, select InventoryServiceLibrary. Click OK to add the reference to the service.

Rename the Service1.svc file to InventoryService.svc. Right click the file and select View Markup. This is the service definition file and currently specifies the name of the service, the file that contains the code and the language the service is implemented in. If you defined the service in the project, this file would be correct. Since you are referencing the existing service, change the contents of this file to the following:

<%@ ServiceHost Service=

"InventoryServiceLibrary.InventoryService" %>

This file now specifies the service’s class and instructs IIS where to find the service’s code.

In the Solution Explorer, double-click Web.config. In the system.web section, make the following change in bold to enable debugging of the service at runtime:

<compilation debug="true">

<compilation debug="true" strict="false" explicit="true">

Scroll down to the system.serviceModel section. Make the following changes in bold:

<services>

  <service name="InventoryServiceLibrary.InventoryService"

           behaviorConfiguration="ServiceBehavior">

    <endpoint

       address="" binding="wsHttpBinding"

       contract="InventoryServiceLibrary.IInventoryService">

      <identity>

        <dns value="localhost"/>

      </identity>

    </endpoint>

    <endpoint address="mex" binding="mexHttpBinding"

              contract="IMetadataExchange"/>

  </service>

</services>

In order to listen for client requests, the host application provides an endpoint. An endpoint consists of an address, a binding and a contract. The address identifies where clients can find the service. The binding specifies how the client and service communicate. The contract specifies what operations the service supports.

In the XML above, the address is empty, indicating that clients can use the following address:

http://<computername>/WebHost/InventoryService.svc

Bindings specify how clients and services communicate. A binding specifies the transport protocol clients and services use to send messages. WCF supports HTTP, TCP and MSMQ. The binding can also specify security or transaction requirements. WCF includes a number of predefined bindings. Visual Studio uses the WsHttpBinding binding by default. This binding is compatible with ASMX Web services and adds a basic level of security.

If you want to call the service and execute an operation, you will use the first endpoint specified in the Web.config file. If you want to add a Service Reference from within Visual Studio, you will use the second endpoint (also called a metadata exchange endpoint) to retrieve metadata about the service. Adding a Service Reference is similar to adding a Web Reference to work with a Web service. You will add a Service Reference in the next section.

Save your changes and build the solution. In the Solution Explorer, right-click on InventoryService.svc and select View in Browser. You should see the service test page in your browser (see Figure 8). You can click the link and view the service’s WSDL.

Figure 8 - The browser displays the service test page.

Build a Client Application

The final step in this tutorial is to build a client application that will call the WCF service. In the Solution Explorer, right-click the IntroToWCFDemo solution and select Add | New Project to display the Add New Project dialog box. Select Windows in the Project Types list and Windows Forms Application in the Templates list. Name the project WindowsClient and click OK. In the solution explorer, right-click WindowsClient and select Set as Startup Project.

You will next add a reference to the service so you can call its methods. In the Solution Explorer, right-click on WindowsClient and select Add ServiceReference to display the Add Service Reference dialog box. Click Discover to search for services that the current solution contains. You can also enter the service’s URL in the Address text box and click Go.

In the Services pane, select WebHost/InventoryService.svc. Expand the WebHost/InventoryService.svc node. Expand the InventoryService node and select IInventoryService. You should see the available operations/methods in the Operations pane (see Figure 9).

Figure 9 - Select the WCF service that you want to use.

Two services appear in the dialog box because in the solution there are two configuration files that define endpoints. The first is the app.config file in the WCF service library project. The WCF Service Host and WCF Test Client applications use the endpoints defined in that configuration file. The second configuration file is the Web.config file in the WebHost project you just created.

Enter InventoryService in the Namespace text box and click OK. In the Solution Explorer, double-click the WindowsClient project’s app.config file. You should see the following XML:

<client>

    <endpoint

      address="https://localhost:2831/WebHost/InventoryService.svc"

      binding="wsHttpBinding"

      bindingConfiguration="WSHttpBinding_IInventoryService"

      contract="InventoryService.IInventoryService"

      name="WSHttpBinding_IInventoryService">

        <identity>

            <dns value="localhost" />

        </identity>

    </endpoint>

</client>

Notice that the address, binding and contract match the address, binding and contract defined in the WebHost project’s Web.config file. The client and service can communicate only if the endpoints match.

In the Solution Explorer, delete Form1. Right-click the project and select Add Existing Item to display the Add Existing Item dialog box. Navigate to the folder where you downloaded the tutorial’s sample code. Navigate to the Starter Code folder and select Form1.cs or Form1.vb. Click Add to add the form. If you are doing this tutorial in C#, open the program.cs file in the WindowsClient project and add the following using statement to the top of the file.

using WindowsFormsApplication15

You do not need to do this for a VB project. This statement is needed in C# because the Form class you just added is defined in the WindowsFormsApplication15 namespace. In VB the class is in the default namespace.

In the Solution Explorer, double-click Form1, opening the form in the form designer (see Figure 10).

Figure 10 - Use this form to call the WCF service.

Double-click the form’s title bar, creating the Form1_Load event handler. At the top of the file, add the following statements:

using System.ServiceModel;

using WindowsClient.InventoryService;

Imports System.ServiceModel

Imports WindowsClient.InventoryService

In the form’s class, add the following variable declarations:

private Product product = null;

private InventoryServiceClient proxy = null;

private decimal inStockValue = 0M;

private decimal onOrderValue = 0M;

Private _product As Product = Nothing

Private proxy As InventoryServiceClient = Nothing

Private inStockValue As Decimal = 0D

Private onOrderValue As Decimal = 0D

When you added the Service Reference, Visual Studio generated the InventoryServiceClient class. This is a proxy class you can use to call the WCF service. The operations of the service appear as methods of the proxy class.

In the Form1_Load event handler, add the following code to create a new instance of the proxy class:

proxy = new InventoryServiceClient(

  "WSHttpBinding_IInventoryService");

proxy = New InventoryServiceClient( _

  "WSHttpBinding_IInventoryService")

In the code above, you pass to the proxy class the name of the endpoint in the app.config file. This ensures you are using the correct address, binding and contract.

Select View | Designer. Double-click the Get in stock button, creating the Click event handler. In the Click event handler, add the following code to retrieve the units in stock for a product:

inStockLabel.Text = string.Format("{0} units are in stock",

  proxy.GetInStock(Convert.ToInt32(productIdTextBox.Text)));

inStockLabel.Text = String.Format("{0} units are in stock", _

  proxy.GetInStock(Convert.ToInt32(productIdTextBox.Text)))

Select View | Designer. Double-click the Get product button, creating the Click event handler. In the Click event handler, add the following code to retrieve additional information for a product:

product = new Product();

product = proxy.GetProduct(

  Convert.ToInt32(productIdTextBox.Text));

productNameLabel.Text = product.ProductName;

unitPricelabel.Text = product.UnitPrice.ToString("C");

inStockTextBox.Text = product.UnitsInStock.ToString();

inStockValue=product.UnitPrice *

  Convert.ToDecimal(product.UnitsInStock);

inStockValueLabel.Text = inStockValue.ToString("C");

onOrderTextBox.Text = product.UnitsOnOrder.ToString();

onOrderValue=product.UnitPrice *

  Convert.ToDecimal(product.UnitsOnOrder);

onOrderValueLabel.Text = onOrderValue.ToString("C");

_product = New Product

_product = proxy.GetProduct( _

  Convert.ToInt32(productIdTextBox.Text))

productNameLabel.Text = _product.ProductName

unitPricelabel.Text = _product.UnitPrice.ToString("C")

inStockTextBox.Text = _product.UnitsInStock.ToString()

inStockValue = _product.UnitPrice * _

  Convert.ToDecimal(_product.UnitsInStock)

inStockValueLabel.Text = inStockValue.ToString("C")

onOrderTextBox.Text = _product.UnitsOnOrder.ToString()

onOrderValue = _product.UnitPrice * _

  Convert.ToDecimal(_product.UnitsOnOrder)

onOrderValueLabel.Text = onOrderValue.ToString("C")

Select View | Designer. Double-click the Update product button, creating the Click event handler. In the Click event handler, add the following code to update inventory information for a product:

product.UnitsInStock = Convert.ToInt16(inStockTextBox.Text);

product.UnitsOnOrder = Convert.ToInt16(onOrderTextBox.Text);

if (proxy.UpdateProduct(product))

{

  MessageBox.Show("Your changes were saved");

  inStockValue = product.UnitPrice *

    Convert.ToDecimal(product.UnitsInStock);

  inStockValueLabel.Text = inStockValue.ToString("C");

  onOrderValue = product.UnitPrice *

    Convert.ToDecimal(product.UnitsOnOrder);

  onOrderValueLabel.Text = onOrderValue.ToString("C");

}

else

{

  MessageBox.Show("Your changes were not saved");

}

_product.UnitsInStock = Convert.ToInt16(inStockTextBox.Text)

_product.UnitsOnOrder = Convert.ToInt16(onOrderTextBox.Text)

If proxy.UpdateProduct(_product) Then

  MessageBox.Show("Your changes were saved")

  inStockValue = _product.UnitPrice * _

    Convert.ToDecimal(_product.UnitsInStock)

  inStockValueLabel.Text = inStockValue.ToString("C")

  onOrderValue = _product.UnitPrice * _

    Convert.ToDecimal(_product.UnitsOnOrder)

  onOrderValueLabel.Text = onOrderValue.ToString("C")

Else

  MessageBox.Show("Your changes were not saved")

End If

Save your changes and build the solution. Press F5 to run the application. In the Manage Inventory form, enter 1 in the Product text box and click Get in stock. The form calls the GetInStock method of the WCF service and displays the units in stock on the form (see Figure 11).

Figure 11 - You called the WCF service to retrieve the units in stock for a product.

Click Get product. The form calls the GetProduct method of the WCF service, passing in a new instance of the Product class. The service retrieves the product’s information, populates the Product object and returns it to the client, which then displays the product information on the form (see Figure 12).

Figure 12 - You called the WCF service to retrieve additional information for a product.

Enter 10 in the On Order text box and click Update product. Dismiss the dialog box informing you your changes were saved. Close the form. Press F5 to run the application again. In the Manage Inventory form, enter 1 in the Product text box and click Get product. You should see that 10 units are on order for this product. Close the form. To stop the Web server, right-click the ASP.NET Development Server icon in the Notification Area and select Stop (see Figure 13).

Figure 13 - Shut down the ASP.NET Development Server.

Conclusion

This tutorial provided you with an introduction to Windows Communication Foundation (WCF), a unified programming model for building service-oriented applications. You first saw an overview of how WCF is a unified programming model and what it means to be a service-oriented application. You then built, hosted, and called a WCF service.

If you have used Web services, the techniques you saw in this tutorial should be very familiar. It was clearly a design goal of Visual Studio to make it easy to build and call WCF services. What you haven’t seen yet is how WCF differs from Web services. In upcoming tutorials in this series, you will see things like how to host a WCF service in managed applications as well as Web servers, how to communicate with services using TCP in addition to HTTP and how to easily switch from one protocol to another.

About the Author

Robert Green is a developer, writer, and trainer. He is a senior consultant with MCW Technologies. Robert is a Visual Studio Tools for the Office system MVP and is a co-author of AppDev courseware for Microsoft Visual Basic, Microsoft Visual C#, LINQ and Microsoft Windows Workflow Foundation. Before joining MCW, Robert worked at Microsoft as a Product Manager and also a Program Manager.