36.1. Windows Communication Foundation

Within the .NET Framework there are a variety of ways that you can communicate among applications, such as Remoting, Web Services, and a myriad of networking protocols. This has often frustrated application developers who not only had to pick the appropriate technology to use, but also had to write plumbing code that would allow their applications to use different technologies depending on the runtime environment. For example, when users are connected directly to the intranet it is better for them to use a Remoting or direct TCP/IP connection. However, this would cause security issues if done from outside the corporate firewall, in which case a secured web service would be preferable, despite being slower.

The Windows Communication Foundation (WCF) provides a uniform way to build messaging applications that are technology-agnostic. Clearly there will still be application requirements, such as that the message should be set asynchronously, or that a return value is expected, or that the message should or should not be part of a transaction. However, WCF abstracts the choice of technology away from the application so that it can be defined at runtime via configuration files.

Without going into too much detail, since one could write an entire book on WCF alone, there are three main components in a WCF service: the A(ddress), B(inding) and C(ontract) of WCF. In the context of a traditional web service, the address would be the web service URL, the binding would be SOAP, and the contract would be the web service method signature. This is a very simplistic interpretation of these three components, and as you start to work with WCF you will see that it really is a powerful communication framework.

You will see through the following example how you can use the visual designers in Visual Studio 2008 to define the ABCs of WCF for a particular service. Let's start by creating a new WCF project using the Visual Basic WCF Service Library template, as shown in Figure 36-1.

Figure 36.1. Figure 36-1

If you look in the Web folder, you will see that there is also a WCF Service Application template that allows you to define a WCF service that is already configured to be hosted within an ASP.NET web application. Doing this is a lot like creating a more traditional ASP.NET web service application, except that it uses the WCF framework.

By default, a new WCF Service Library will include IService1.vb and Service1.vb, which define the interface and the implementation of a basic service, respectively. We will start by replacing the contents of IService1.vb with the following code:

<ServiceContract()> _
Public Interface IService1

    <OperationContract()> _
    Function CreateNewCustomer(ByVal c As Customer) As Guid

End Interface

<DataContract()> _
Public Class Customer
    Private mFirstName As String
    Private mLastName As String
    Private mEmail As String
    Private mPhone As String
    <DataMember()> _
    Public Property Phone() As String
        Get
            Return mPhone

End Get
        Set(ByVal value As String)
            mPhone = value
        End Set
    End Property
    <DataMember()> _
    Public Property Email() As String
        Get
            Return mEmail
        End Get
        Set(ByVal value As String)
            mEmail = value
        End Set
    End Property
    <DataMember()> _
    Public Property LastName() As String
        Get
            Return mLastName
        End Get
        Set(ByVal value As String)
            mLastName = value
        End Set
    End Property
    <DataMember()> _
    Public Property FirstName() As String
        Get
            Return mFirstName
        End Get
        Set(ByVal value As String)
            mFirstName = value
        End Set
    End Property
End Class

What you can see from this code is that we are defining a service called IService1 (we will rename it in a minute) that exposes the operation CreateNewCustomer. IService1 and CreateNewCustomer are identified by the ServiceContract and OperationContract attributes, respectively. In addition, there is a Customer class that is marked with a DataContract attribute and that contains properties marked with the DataMember attribute. This class represents, as the attribute name suggests, a data contract that is to be shared, along with the service contract, between the caller and the service. In this case, the class will be used to marshal the argument for the CreateNewCustomer method call from the caller into the service.

Although this is not strictly required, we recommend that you keep your data contract classes separate from your other application classes and that you use them only for passing data in and out of services. This way you minimize the dependencies between your application and the services that it exposes or calls.

In Service1.vb you will also have to replace the initial code with the appropriate implementation of IService1. For simplicity, we are just going to return a new GUID that might represent the ID of the customer once he or she has been approved and added to the company database.

Public Class Service1
    Implements IService1

    Public Function CreateNewCustomer(ByVal c As Customer) _
                                     As Guid Implements IService1.CreateNewCustomer
        'for the moment return a new guid to indicate the id of the added customer
        Return Guid.NewGuid
    End Function
End Class

With these changes made, build and run the WCF Service Library. Unlike a normal class library, a WCF service library can be "run," because Visual Studio 2008 ships with the WcfSvcHost utility. This is an application that can be used to host WCF services for the purpose of debugging. Figure 36-2 shows this utility appearing in the taskbar.

Figure 36.2. Figure 36-2

As the balloon in Figure 36-2 indicates, clicking the balloon or the taskbar icon will bring up a dialog showing more information about the service that is running. In actuality, this dialog will not be very informative about a correctly running WCF service, but as you will see later, when the service doesn't start correctly the dialog can help you work out what is going wrong.

As part of running the WCF Service Library, in addition to hosting your WCF service Visual Studio 2008 also launches the WCF Test Client utility, as you can see in Figure 36-3. This utility automatically detects the running services and provides a simple tree representation of them and their corresponding operations.

Figure 36.3. Figure 36-3

When you click a service operation you will see that the tab on the right-hand side of the dialog changes to indicate 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 relatively complex WCF Services. In Figure 36-4, you can see that in the Request section the input argument, c, has been broken down into its respective elements — Email, FirstName, LastName, and Phone, as defined by the DataMember attributes seen earlier. You can edit any of these elements via this dialog before hitting the "Invoke" button. Figure 36-4 also shows that any return value will be displayed in a similar layout in the Response section of the tab.

Figure 36.4. Figure 36-4

If you are trying to isolate an issue, it may be important 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 36-5 shows the body XML for both the request and the response. You will notice that, particularly for the response, there is a lot of additional XML that can significantly degrade the performance of the service request.

Figure 36.5. Figure 36-5

At this stage, we still have a service contact called IService1. In the interest of writing more maintainable and understandable code, we should go ahead and rename this ICustomerService, and rename the corresponding implementation CustomerService. To do this, select the IService1.vb item in the Solution Explorer tool window, press F2, and rename the file. This will not only rename the file but also the interface name and any other references. Repeat this procedure with Service1.vb.

You read earlier about the ABCs of WCF services. Well, the interface class with the ServiceContract attributes defines the service contract. The remaining elements, Address and Binding, are defined in the application configuration file, which is used by the WCF runtime when it exposes the service. In the previous step where you renamed the service interface, you will have broken the application configuration, as it is now referencing a nonexistent service contract, IService1. To fix this you can use the new WCF Service Configuration Editor. This editor can be launched from the Tools WCF Service Configuration Editor menu item. After selecting this menu item you will have to browse to open the app.config file in your WCF Service Library. Alternatively, you can right-click the app.config file in the Solution Explorer and select Edit WCF Configuration. In either case, a configuration editor will be launched that looks similar to what is shown in Figure 36-6.

Figure 36.6. Figure 36-6

The items that you need to change are:

  • Services — CustomerServices.Service1: Change Name to CustomerServices.CustomerService

  • Services — CustomerServices.CustomerService — Host: Change BaseAddress to http://localhost:90/CustomerServices/CustomerService/

  • Services — CustomerServices.CustomerService — Endpoints — (Empty Name) (first item): Change Contact to CustomerServices.ICustomerService

  • Advanced — Service Behaviors — CustomerServices.Service1Behavior: Change Name to CustomerServices.CustomerServiceBehavior

Essentially, all you have done here is fix the application configuration file to use the adjusted service contact and change the address to use a different port and base directory. Now when you run the WCF Service it will have the correct configuration information to be able to configure the necessary WCF service endpoints. Depending on your computer configuration you may end up with the WCF Service Host (which you were introduced to earlier when it was running silently in the taskbar), prompting you with an error relating to the registration of the URL you specified in the configuration file, as seen in Figure 36-7.

Figure 36.7. Figure 36-7

Although you can't see the full error message in Figure 36-7, there is actually a help URL that provides additional information on how you can resolve this issue. The issue is a result of security policies on the computer that are preventing the WCF Service Host from registering the URL you have specified. In this case, you can resolve this by executing the following command using an elevated permissions command prompt (i.e., while running as administrator).

netsh http add urlacl url=http://+:90/CustomerServices user=<username>

This command will allow the specified user to register URLs that match the URL prefix. When you again try to run your WCF Service Library, it should start successfully, and the WCF Test Client utility should be presented as before.

36.1.1. Consuming a WCF Service

Now that you have successfully created your WCF service, it is time to use it within an application. To do this, let's begin by adding the rich client application we built in Chapter 35. If you recall, this is a Windows Forms application that uses a WPF control bound to a Customer object. In order to add this application, you need to use the File Add Existing Project menu item to add first the WPF project, CustomerManagement, and then the Windows Forms project, Customers, to your solution.

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 will open the dialog shown in Figure 36-8, 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.

Figure 36.8. Figure 36-8

Select the ICustomerService node in the Services tree, change the namespace to CustomerServices, and press "OK" to complete the process of adding a service reference to your application. With this reference added, we simply need to modify the code of the "Submit" button so that it creates an instance of the WCF service and then calls the CreateNewCustomer operation. This is illustrated in the following code snippet.

Private Sub btnSubmit_Click(ByVal sender As Object, _
                             ByVal e As System.EventArgs)
   Handles btnSubmit.Click
    MsgBox(String.Format("Adding the new customer '{0} {1}'
   with email address {2} and phone number {3}",
   mNewCustomer.FirstName, mNewCustomer.LastName, _
                       mNewCustomer.Email,
   mNewCustomer.Phone))
    'Call webservice or WCF service to add the new customer
   or kick off a workflow
    Dim customerservice As New
   CustomerServices.CustomerServiceClient
    Dim serviceC = PopulaterServiceCustomer(mNewCustomer)
    Dim newCustomerId As Guid =
   customerservice.CreateNewCustomer(serviceC)
    MsgBox("New customer added with Id '" &
   newCustomerId.ToString & "'")
End Sub

Private Function PopulaterServiceCustomer(ByVal c As Customer) _
                                                       As CustomerServices.Customer
    Dim serviceC As New CustomerServices.Customer

serviceC.FirstName = c.FirstName
    serviceC.LastName = c.LastName
    serviceC.Email = c.Email
    serviceC.Phone = c.Phone
    Return serviceC
End Function

You now have a rich client application that can be used to specify the details of a new customer, which will be passed to a WCF service. Although the WCF service currently simply returns a new GUID, it could potentially do data validation, request approval, and any other steps that are required before the insertion of a new customer record.

When you added a reference to the WCF service to your rich client application, you will have noticed 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 sub-elements override some of the default values. The other element, Client, contains an endpoint element. This element defines the Address, which in this case is a URL; Binding, which references the customized wsHttpBinding defined in the bindings element; and Contract, 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), instead of having to recompile the entire application you can just modify the configuration file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.189.251