Chapter 2. The Fundamentals

<feature><title>In This Chapter</title> </feature>

Background

Dealing with something as an integrated whole is self-evidently easier than having to understand and manipulate all of its parts. Thus, to make programming easier, it is commonplace to define classes that serve as integrated wholes, keeping their constituents hidden. Doing so is called encapsulation, which is characteristic of what is known as object-oriented programming.

The C++ programming language provided syntax for encapsulation that proved very popular. In C++, one can write a class like this one:

class Stock
{
private:
    char symbol[30];
    int number;
    double price;
    double value;
    void SetTotal()
    {
        this->value = this->number * this->price;
    }
public:
    Stock(void);
    ~Stock(void);
    void Acquire(const char* symbol, int number, double
price);
    void Sell(int number, double price);
};

The class hides away its data members—symbol, number, price, and value—as well as the method SetTotal(), but exposes the methods Acquire() and Sell() for use.

Some refer to the exposed surface of a class as its interface, and to invocations of the methods of a class as messages. David A. Taylor does so in his book Object-Oriented Information Systems: Planning and Integration (1992, 118).

Using C++ classes to define interfaces and messages has an important shortcoming, however, as Don Box explains in Essential COM (1998, 11). There is no standard way for C++ compilers to express the interfaces in binary format. Consequently, sending a message to a class in a dynamic link library (DLL) is not guaranteed to work if the calling code and the intended recipient class were built using different compilers.

That shortcoming is significant because it restricts the extent to which the class in the DLL can be reused in code written by other programmers. The reuse of code written by one programmer within code written by another is fundamental not only to programming productivity, but also to software as a commercial enterprise, to being able to sell what a programmer produces.

Two important solutions to the problem were pursued. One was to define interfaces using C++ abstract base classes. An abstract base class is a class with pure virtual functions, and, as Box explained, “[t]he runtime implementation of virtual functions in C++ takes the [same] form[...]in virtually all production compilers” (1998, 15). You can write, in C++, the code given in Listing 2.1.

Example 2.1. Abstract Base Class

//IStock.h
class IStock
{
public:
      virtual void DeleteInstance(void);
      virtual void Acquire(const char* symbol, int number, double price) = 0;
    virtual void Sell(int number, double price) = 0;
};

extern "C"
IStock* CreateStock(void);

//Stock.h
#include "IStock.h"

class Stock: public IStock
{
private:
    char symbol[30];
    int number;
    double price;
    double value;
    void SetTotal()
    {
        this->value = this->number * this->price;
    }
public:
    Stock(void);
    ~Stock(void);
    void DeleteInstance(void);
    void Acquire(const char* symbol, int number, double price);
    void Sell(int number, double price);
};

In that code, IStock is an interface defined using a C++ abstract virtual class. IStock is an abstract virtual class because it has the pure virtual functions Acquire() and Sell(), their nature as pure virtual functions being denoted by having both the keyword, virtual, and the suffix, = 0, in their declarations. A programmer wanting to use a class with the IStock interface within a DLL can write code that retrieves an instance of such a class from the DLL using the global function CreateStock() and sends messages to that instance. That code will work even if the programmer is using a different compiler than the one used by the programmer of the DLL.

Programming with interfaces defined as C++ abstract virtual classes is the foundation of a Microsoft technology called the Component Object Model, or COM. More generally, it is the foundation of what became known as component-oriented programming.

Component-oriented programming is a style of software reuse in which the interface of the reusable class consists of constructors, property getter and setter methods, methods, and events. Programmers using the class “...follow[] a pattern of instantiating a type with a default or relatively simple constructor, setting some instance properties, and finally, [either] calling simple instance methods” or handling the instance’s events (Cwalina and Abrams 2006, 237).

Another important solution to the problem of there being no standard way for C++ compilers to express the interfaces of classes in binary format is to define a standard for the output of compilers. The Java Virtual Machine Specification defines a standard format for the output of compilers, called the class file format (Lindholm and Yellin 1997, 61). Files in that format can be translated into the instructions specific to a particular computer processor by a Java Virtual Machine. One programmer can provide a class in the class file format to another programmer who will be able to instantiate that class and send messages to it using any compiler and Java Virtual Machine compliant with the Java Virtual Machine Specification.

Similarly, the Common Language Infrastructure Specification defines the Common Intermediate Language as a standard format for the output of compilers (ECMA International 2005). Files in that format can be translated into instructions to a particular computer processor by Microsoft’s Common Language Runtime, which is the core of Microsoft’s .NET technology, as well as by Mono.

Despite these ways of making classes written by one programmer reusable by others, the business of software was still restricted. The use of COM and .NET is widespread, as is the use of Java, and software developed using Java cannot be used together easily with software developed using COM or .NET. More importantly, the component-oriented style of software reuse that became prevalent after the introduction of COM, and which was also widely used by Java and .NET programmers, is grossly inefficient when the instance of the class that is being reused is remote, perhaps on another machine, or even just in a different process. It is so inefficient because, in that scenario, each operation of instantiating the object, of assigning values to its properties, and of calling its methods or handling its events, requires communication back and forth across process boundaries, and possibly also over the network.

“Since [the two separate processes] each have their own memory space, they have to copy the data [transmitted between them] from one memory space to the other. The data is usually transmitted as a byte stream, the most basic form of data. This means that the first process must marshal the data into byte form, and then copy it from the first process to the second one; the second process must unmarshal the data back into its original form, such that the second process then has a copy of the original data in the first process.” (Hohpe and Woolf 2004, 66).

Besides the extra work involved in marshalling data across the process boundaries,

“...security may need to be checked, packets may need to be routed through switches. If the two processes are running on machines on opposite sides of the globe, the speed of light may be a factor. The brutal truth is that that any inter-process call is orders of magnitude more expensive than an in-process call—even if both processes are on the same machine. Such a performance effect cannot be ignored.” (Fowler 2003, 388).

The Web Services Description Language (WSDL) provided a general solution to the first restriction, the problem of using software developed using Java together with software developed using COM or .NET. WSDL provides a way of defining software interfaces using the Extensible Markup Language (XML), a format that is exceptionally widely adopted, and for which processors are readily available. Classes that implement WSDL interfaces are generally referred to as services.

Concomitantly, an alternative to component-oriented programming that is suitable for the reuse of remote instances of classes became progressively more common in practice, although writers seem to have had a remarkably difficult time formalizing its tenets. Thomas Erl, for instance, published two vast books ostensibly on the subject, but never managed to provide a noncircuitous definition of the approach in either of them (Erl 2004, 2005). That alternative to component-oriented programming is service-oriented programming.

Service-oriented programming is a style of software reuse in which the reusable classes are services—classes that implement WSDL interfaces—and the services are designed so as to minimize the number of calls to be made to them, by packaging the data to be transmitted back and forth into messages. A message is a particular kind of data transfer object. A data transfer object is

“...little more than a bunch of fields and the getters and setters for them. The value of [this type of object] is that it allows you to move several pieces of information over a network in a single call—a trick that’s essential for distributed systems. [...] Other than simple getters and setters, the data transfer object is [...] responsible for serializing itself into some format that will go over the wire.” (Fowler 2003, 401—403).

Messages are data transfer objects that consist of two parts: a header that provides information pertinent to the operation of transmitting the data and a body that contains the actual data to be transmitted. Crucially, the objects into which the content of a message is read on the receiving side are never assumed to be of the same type as the objects from which the content of the message was written on the sending side. Hence, the sender and the receiver of a message do not have to share the same types, and are said to be loosely coupled by their shared knowledge of the format of the message, rather than tightly coupled by their shared knowledge of the same types (Box 2004). By virtue of being loosely coupled, the sender and the receiver of the message can evolve independently of one another.

A definition of the term service-oriented architecture is warranted here for the sake of disambiguation. Service-oriented architecture is an approach to organizing the software of an enterprise by providing service facades for all of that software, and publishing the WSDL for those services in a central repository. The repository is typically a Universal Description Discovery and Integration (UDDI) registry. Having interfaces to all the software of an enterprise expressed in a standard format and catalogued in a central repository is desirable because then, in theory, its availability for reuse can be known. Also, policies defining requirements, capabilities, and sundry other properties of a service can be associated with the service using WSDL or by making suitable entries in the registry. That fact leads enterprise architects to anticipate the prospect of the registry serving as a central point of control through which they could issue decrees about how every software entity in their organization is to function by associating policies with the services that provide facades for all of their other software resources. Furthermore, measurements of the performance of the services can be published in the registry, too, so the registry could also serve as a monitoring locus.

Note that service-oriented architecture does not refer to the process of designing software that is to be composed from parts developed using service-oriented programming. There are at least two reasons why not. The first is simply because that is not how the term is actually used, and Ludwig Wittgenstein established in his Philosophical Investigations that the meaning of terms is indeed determined by how they are customarily used by a community (Wittgenstein 1958, 93). The second reason is that the community really could not use the term to refer to a process of designing software composed from parts developed using service-oriented programming because the process of doing that is in no way distinct from the process of designing software composed using parts developed in some other fashion. More precisely, the correct patterns to choose as guides in designing the solution would be the same regardless of whether or not the parts of the solution were developed using service-oriented programming.

Now, Microsoft provided support for service-oriented programming to COM programmers with the Microsoft SOAP Toolkit, and to .NET programmers with the classes in the System.Web.Services namespace of the .NET Framework Class Library. Additions to the latter were provided by the Web Services Enhancements for Microsoft .NET. Java programmers can use Apache Axis for service-oriented programming.

Yet service-oriented programming has been limited by the lack of standard ways of securing message transmissions, handling failures, and coordinating transactions. Standards have now been developed, and the Windows Communication Foundation provides implementations thereof.

So, the Windows Communication Foundation delivers a more complete infrastructure for service-oriented programming than was available to .NET software developers. Providing that infrastructure is important because service-oriented programming transcends limits on the reuse of software between Java programmers and COM and .NET programmers that had been hampering the software business.

Today, even with the Windows Communication Foundation, service-oriented programming is still suitable only for interactions with remote objects, just as component-oriented programming is suitable only for interacting with local objects. A future goal for the team that developed the Windows Communication Foundation is to extend the technology to allow the service-oriented style of programming to be equally efficient for both scenarios.

Even so, to understand the Windows Communication Foundation as merely being Microsoft’s once and future infrastructure for service-oriented programming severely underestimates its significance. The Windows Communication Foundation provides something far more useful than just another way of doing service-oriented programming. It provides a software factory template for software communication.

The concept of software factory templates is introduced by Jack Greenfield and Keith Short in their book Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools (Greenfield and others 2004). It provides a new approach to model-driven software development.

The notion of model-driven software development has been popular for many years. It is the vision of being able to construct a model of a software solution from which the software itself can be generated after the model has been scrutinized to ensure that it covers all the functional and nonfunctional requirements. That vision has been pursued using general-purpose modeling languages, the Unified Modeling Language (UML) in particular.

A serious shortcoming in using general-purpose modeling languages for model-driven software development is that general-purpose modeling languages are inherently imprecise. They cannot represent the fine details of requirements that can be expressed in a natural language such as English. They also are not sufficiently precise to cover things such as memory management, thread synchronization, auditing, and exception management. If they were, they would be programming languages, rather than general-purpose modeling languages, yet memory management, thread synchronization, auditing, and exception management are precisely the sorts of things that bedevil programmers.

Greenfield and Short argue that progress in model-driven development depends on eschewing general-purpose modeling languages in favor of domain-specific languages, or DSLs. A DSL models the concepts found in a specific domain. DSLs should be used in conjunction with a corresponding class framework, a set of classes specifically designed to cover the same domain. Then, if the DSL is used to model particular ways in which those classes can be used, it should be possible to generate the software described in the model from the class framework (Greenfield and others 2004, 144).

The combination of a DSL and a corresponding class framework constitute the core of a software factory template (Greenfield and others 2004, 173). Software factory templates serve as the software production assets of a software factory from which many varieties of the same software product can be readily fabricated.

A fine example of a software factory template is the Windows Forms Designer in Microsoft Visual Studio .NET and subsequent versions of Microsoft Visual Studio. In that particular case, the Windows Forms Designer is the DSL, the Toolbox and Property Editor being among the terms of the language, and the classes in the System.Windows.Forms namespace of the .NET Framework Class Library constitute the class framework. Users of the Windows Forms Designer use it to model software that is generated from those classes.

Programmers have been using the Windows Forms Designer and tools like it in other integrated development environments for many years to develop software user interfaces. So, Greenfield and Short, in introducing the concept of software factory templates, are not proposing a new approach. Rather, they are formalizing one that has already proven to be very successful, and suggesting that it be used to develop other varieties of software besides user interfaces.

The Windows Communication Foundation is a software factory template for software communication. It consists of a DSL, called the Service Model, and a class framework, called the Channel Layer. The Service Model consists of the classes of the System.ServiceModel namespace, and an XML configuration language. The Channel Layer consists of the classes in the System.ServiceModel.Channel namespace. Developers model how a piece of software is to communicate using the Service Model, and the communication components they need to have included in their software are generated from the Channel Layer, in accordance with their model. Later, if they need to change or supplement how their software communicates, they make alterations to their model, and the modifications or additions to their software are generated. If they want to model a form of communication that is not already supported by the Channel Layer, they can build or buy a suitable channel to add to the Channel Layer, and proceed to generate their software as usual, just as a user of the Windows Forms Designer can build or buy controls to add to the Windows Forms Designer’s Toolbox.

That the Windows Communication Foundation provides a complete infrastructure for service-oriented programming is very nice because sometimes programmers do need to do that kind of programming, and service-oriented programming will likely remain popular for a while. However, software developers are always trying to get pieces of software to communicate, and they always will need to do that because software is reused by sending and receiving data, and the business of software depends on software reuse. So, the fact that the Windows Communication Foundation provides a software factory template for generating, modifying, and supplementing software communication facilities from a model is truly significant.

The Service Model

The key terms in the language of the Windows Communication Foundation Service Model correspond closely to the key terms of WSDL. In WSDL, a piece of software that can respond to communications over a network is called a service. A service is described in an XML document with three primary sections:

  • The service section indicates where the service is located.

  • The binding section specifies which of various standard communication protocols the service understands.

  • The third primary section, the portType section, lists all the operations that the service can perform by defining the messages that it will emit in response to messages it receives.

Thus, the three primary sections of a WSDL document tell you where a service is located, how to communicate with it, and what it will do.

Those three things are exactly what you specify in using the Windows Communication Foundation Service Model to model a service: where it is, how to communicate with it, and what it will do. Instead of calling those things service, binding, and portType, as they are called in the WSDL specification, they are named address, binding, and contract in the Windows Communication Foundation Service Model. Consequently, the handy abbreviation a, b, c can serve as a reminder of the key terms of the Windows Communication Foundation Service Model and, thereby, as a reminder of the steps to follow in using it to enable a piece of software to communicate.

More precisely, in the Windows Communication Foundation Service Model, a piece of software that responds to communications is a service. A service has one or more endpoints to which communications can be directed. An endpoint consists of an address, a binding, and a contract. How a service handles communications internally, behind the external surface defined by its endpoints, is determined by a family of control points called behaviors.

This chapter explains, in detail, how to use the Windows Communication Foundation Service Model to enable a piece of software to communicate. Lest the details provided obscure how simple this task is to accomplish, here is an overview of the steps involved.

A programmer begins by defining the contract. That simple task is begun by writing an interface in a .NET programming language:

public interface IEcho
{
    string Echo(string input);
}

It is completed by adding attributes from the Service Model that designate the interface as a Windows Communication Foundation contract, and one or more of its methods as being included in the contract:

[ServiceContract]
public interface IEcho
{
    [OperationContract]
    string Echo(string input);
}

The next step is to implement the contract, which is done simply by writing a class that implements the interface:

public class Service : IEcho
{
    public string Echo(string input)
    {
        return input;
    }
}

A class that implements an interface that is designated as a Windows Communication Foundation contract is called a service type. How the Windows Communication Foundation conveys data that has been received from the outside via an endpoint to the service type can be controlled by adding behaviors to the service type definition using the ServiceBehavior attribute:

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class Service : IEcho
{
    public string Echo(string input)
    {
        return input;
    }
}

For example, the concurrency mode behavior attribute controls whether the Windows Communication Foundation can convey data to the service type on more than one concurrent thread. This behavior is set via an attribute because it is one that a programmer, as opposed to an administrator, should control. After all, it is the programmer of the service type who would know whether the service type is programmed in such a way as to accommodate concurrent access by multiple threads.

The final step for the programmer is to provide for hosting the service within an application domain. IIS can provide an application domain for hosting the service, and so can any .NET application. Hosting the service within an arbitrary .NET application is easily accomplished using the ServiceHost class provided by the Windows Communication Foundation Service Model:

using (ServiceHost host = new ServiceHost(typeof(Service))
{
    host.Open();

    Console.WriteLine("The service is ready.");
    Console.ReadKey(true);

    host.Close();
}

Now the administrator takes over. The administrator defines an endpoint for the service type by associating an address and a binding with the Windows Communication Foundation contracts that the service type implements. An editing tool, called the Service Configuration Editor, shown in Figure 2.1, that also includes wizards, is provided for that purpose.

Defining an address and a binding.

Figure 2.1. Defining an address and a binding.

Whereas the programmer could use attributes to modify the behaviors that a programmer should control, the administrator, as shown in Figure 2.2, can use the Service Configuration Editor to modify the behaviors that are properly within an administrator’s purview. All output from the tool takes the form of a .NET application configuration file.

Adding behaviors to a service.

Figure 2.2. Adding behaviors to a service.

Now that the address, binding, and contract of an endpoint have been defined, the contract has been implemented, and a host for the service has been provided, the service can be made available for use. The administrator executes the host application. The Windows Communication Foundation examines the address, binding, and contract of the endpoint that have been specified in the language of the Service Model, as well as the behaviors, and generates the necessary components by which the service can receive and respond to communications from the Channel Layer.

One of the behaviors that the administrator can control is whether the service exposes WSDL to describe its endpoints for the outside world. If the administrator configures the service to do so, the Windows Communication Foundation will automatically generate the WSDL and offer it up in response to requests for it. A programmer developing an application to communicate with the service can download the WSDL, and generate code for exchanging data with the service, as well as an application configuration file with the endpoint information. That can be done with a single command

svcutil http://localhost:8000/EchoService?wsdl

wherein svcutil is the name of the Windows Communication Foundation’s Service Model Metadata Tool, and http://localhost:8000/EchoService?wsdl is the address from which the metadata of a service can be downloaded. Having employed the tool to produce the necessary code and configuration, the programmer can proceed to use them to communicate with the service:

using(EchoProxy echoProxy = new EchoProxy())
{
   echoProxy.Open();

   string response = echoProxy.Echo("Hello, World!");

   echoProxy.Close();
}

The preceding steps are all that is involved in using the Windows Communication Foundation. In summary, those simple steps are merely these:

  1. The service programmer defines a contract using a .NET interface.

  2. The service programmer implements that interface in a class, a service type.

  3. The service programmer optionally modifies Windows Communication Foundation behaviors by applying attributes to the service type or to its methods.

  4. The service programmer makes provisions for the service to be hosted. If the service is to be hosted within a .NET application, the programmer develops that application.

  5. The service administrator uses the Service Configuration Editor to configure the service’s endpoints by associating addresses and bindings with the contracts implemented by the service type.

  6. The service administrator optionally uses the Service Configuration Editor to modify Windows Communication Foundation behaviors.

  7. The programmer of a client application uses the Service Model Metadata Tool to download WSDL describing the service and to generate code and a configuration file for communicating with the service.

  8. The programmer of the client application uses generated code and configuration to exchange data with the service.

At last, the promise of model-driven development might have actually yielded something tangible: a software factory template by which the communications system of an application can be manufactured from a model. The value of using this technology is at least threefold.

First, developers can use the same simple modeling language provided by the Service Model to develop solutions to all kinds of software communications problems. Until now, a .NET developer would typically use .NET web services to exchange data between a .NET application and a Java application, but use .NET Remoting for communication between two .NET applications, and the classes of the System.Messaging namespace to transmit data via a queue. The Windows Communication Foundation provides developers with a single, easy-to-use solution that works well for all of those scenarios. Because, as will be shown in Part V, “Extending the Windows Communication Foundation,” the variety of bindings and behaviors supported by the Windows Communication Foundation is indefinitely extensible, the technology will also work as a solution for any other software communication problem that is likely to occur. Consequently, the cost and risk involved in developing solutions to software communications problems decreases because rather than expertise in a different specialized technology being required for each case, the developers’ skill in using the Windows Communication Foundation is reusable in all of them.

Second, in many cases, the administrator is able to modify how the service communicates simply by modifying the binding, without the code having to be changed, and the administrator is thereby able to make the service communicate in a great variety of significantly different ways. The administrator can choose, for instance, to have the same service communicate with clients on the internal network they all share in a manner that is optimal for those clients, and can also have it communicate with Internet clients in a different manner that is suitable for them. When the service’s host executes again after any modifications the administrator has made to the binding, the Windows Communication Foundation generates the communications infrastructure for the new or modified endpoints. Thus, investments in software built using the Windows Communications Foundation yield increased returns by being adaptable to a variety of scenarios.

Third, as will be shown in Part VII, “The Lifecycle of Windows Communication Foundation Applications,” the Windows Communication Foundation provides a variety of powerful tools for managing applications built using the technology. Those tools reduce the cost of operations by saving the cost of having to develop custom management solutions, and by reducing the risk, frequency, duration, and cost of downtime.

The foregoing provides a brief overview of working with the Windows Communication Foundation Service Model. Read on for a much more detailed, step-by-step examination. That account starts right from the beginning, with building some software with which one might like other software to be able to communicate. To be precise, it starts with developing some software to calculate the value of derivatives.

A Software Resource

A derivative is a financial entity whose value is derived from that of another. Here is an example. The value of a single share of Microsoft Corporation stock was $24.41 on October 11, 2005. Given that value, one might offer for sale an option to buy 1,000 of those shares, for $25 each, one month later, on November 11, 2005. Such an option, which is known as a call, might be purchased by someone who anticipates that the price of the shares will rise above $25 by November 11, 2005, and sold by someone who anticipates that the price of the shares will drop. The call is a derivative, its value being derived from the value of Microsoft Corporation stock.

Pricing a derivative is a complex task. Indeed, estimating the value of derivatives is perhaps the most high-profile problem in modern microeconomics.

In the foregoing example, clearly the quantity of the stock and the current and past prices of the Microsoft Corporation stock are factors to consider. But other factors might be based on analyses of the values of quantities that are thought to affect the prices of the stock, such as the values of various stock market indices, or the interest rate of the U.S. Federal Reserve Bank. In fact, one can say that, in general, the price of a derivative is some function of one or more quantities, one or more market values, and the outcome of one or more quantitative analytical functions.

Although actually writing software to calculate the value of derivatives is beyond the scope of this book, one can pretend to do so by following these steps:

  1. Open Microsoft Visual Studio 2005, choose File, New, Project from the menus, and create a new blank solution called DerivativesCalculatorSolution in the folder C:WCFHandsOnFundamentals, as shown in Figure 2.3.

    Creating a blank Visual Studio solution.

    Figure 2.3. Creating a blank Visual Studio solution.

  2. Choose File, New, Project again, and add a C# Class Library project called DerivativesCalculator to the solution, as shown in Figure 2.4.

    Adding a Class Library project to the solution.

    Figure 2.4. Adding a Class Library project to the solution.

  3. Rename the class file Class1.cs in the DerivativesCalculator project to Calculator.cs, and modify its content to look like this:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public class Calculator
        {
            public decimal CalculateDerivative(
    string[] symbols,
    decimal[] parameters,
    string[] functions)
            {
                //Pretend to calculate the value of a derivative.
                return (decimal)(System.DateTime.Now.Millisecond);
            }
        }
    }
    

This simple C# class purports to calculate the value of derivatives, and will serve to represent a piece of software with which one might like other software to be able to communicate. Certainly, if the class really could calculate the value of derivatives, its capabilities would be in extraordinary demand, and one could quickly earn a fortune by charging for access to it.

Building a Service for Accessing the Resource

To allow other software to communicate with the class, one can use the Windows Communication Foundation Service Model to add communication facilities to it. One does so by building a Windows Communication Foundation service with an endpoint for accessing the facilities of the derivatives calculator class. Recall that, in the language of the Windows Communication Foundation Service Model, an endpoint consists of an address, a binding, and a contract.

Defining the Contract

In using the Windows Communication Foundation Service Model, one usually begins by defining the contract. The contract specifies the operations that are available at the endpoint. After the contract has been defined, the next step is to implement the contract, to actually provide the operations it defines.

Defining and implementing Windows Communication Foundation contracts is simple. To define a contract, one merely writes an interface in one’s favorite .NET programming language, and adds attributes to it to indicate that the interface is also a Windows Communication Foundation contract. Then, to implement the contract, one simply programs a class that implements the .NET interface that one has defined:

  1. Choose File, New, Project from the Visual Studio 2005 menus again, and add another C# Class Library project to the solution, called DerivativesCalculatorService.

  2. Rename the class file Class1.cs in the DerivativesCalculatorService project to IDerivativesCalculator.

  3. Modify the contents of the IDerivatesCalculator.cs file to look like so:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public interface IDerivativesCalculator
        {
            decimal CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions);
            void DoNothing();
        }
    }
    

    IDerivativesCalculator is an ordinary C# interface, with two methods, CalculateDerivative() and DoNothing(). Now it will be made into a Windows Communication Foundation contract.

  4. Choose Project, Add Reference from the Visual Studio 2005 menus. Select System.ServiceModel from the assemblies listed on the .NET tab of the Add Reference dialog that appears, as shown in Figure 2.5, and click on the OK button. System.ServiceModel is the most important of the new .NET class libraries included in the Windows Communication Foundation.

    Adding a reference to the System.ServiceModel assembly.

    Figure 2.5. Adding a reference to the System.ServiceModel assembly.

  5. Modify the IDerivativesCalculator interface in the IDerivativesCalculator.cs module to import the classes in the System.ServiceModel namespace that is incorporated in the System.ServiceModel assembly:

    using System;
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public interface IDerivativesCalculator
        {
            decimal CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions);
    
          void DoNothing();
        }
    }
    
  6. Now designate the IDerivativesCalculator interface as a Windows Communication Foundation contract by adding the ServiceContract attribute that is included in the System.ServiceModel namespace:

    using System;
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        [ServiceContract]
        public interface IDerivativesCalculator
        {
            decimal CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions);
    
          void DoNothing();
        }
    }
    
  7. Use the OperationContract attribute to designate the CalculateDerivative() method of the IDerivativesCalculator interface as one of the methods of the interface that is to be included as an operation in the Windows Communication Foundation contract:

    using System;
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        [ServiceContract]
        public interface IDerivativesCalculator
        {
            [OperationContract]
            decimal CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions);
    
          void DoNothing();
        }
    }
    

    By default, the namespace and name of a Windows Communication Foundation contract are the namespace and name of the interface to which the ServiceContract attribute is added. Also, the name of an operation included in a Windows Communication Foundation contract is the name of the method to which the OperationContract attribute is added. You can alter the default name of a contract using the Namespace and Name parameters of the ServiceContract attribute, as in

    [ServiceContract(Namespace="MyNamespace",Name="MyContract")]
    public interface IMyInterface
    

    You can alter the default name of an operation with the Name parameter of the OperationContract attribute:

    [OperationContract(Name="MyOperation"]
    string MyMethod();
    
  8. Returning to the derivatives calculator solution in Visual Studio 2005, now that a Windows Communication Foundation contract has been defined, the next step is to implement it. In the DerivativesCalculatorService project, choose Project, Add, New Class from the Visual Studio 2005 menus, and add a class called DerivativesCalculatorServiceType.cs to the project, as shown in Figure 2.6.

    Adding a class to a project.

    Figure 2.6. Adding a class to a project.

  9. Modify the contents of the DerivativesCalculatorServiceType.cs class file to look like this:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public class DerivativesCalculatorServiceType: IDerivativesCalculator
        {
            #region IDerivativesCalculator Members
            decimal IDerivativesCalculator.CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions)
            {
                throw new Exception(
                   "The method or operation is not implemented.");
            }
    
            void IDerivativesCalculator.DoNothing()
            {
                throw new Exception(
                   "The method or operation is not implemented.");
            }
            #endregion
        }
    }
    

    As mentioned earlier, in the language of the Windows Communication Foundation, the name service type is used to refer to any class that implements a service contract. So, in this case, the DerivativesCalculatorServiceType is a service type because it implements the IDerivativesCalculator interface, which has been designated as a Windows Communication Foundation service contract.

    A class can be a service type not only by implementing an interface that is a service contract, but also by having the ServiceContract attribute applied directly to the class. However, by applying the ServiceContract attribute to an interface and then implementing the interface with a class, as in the foregoing, one yields a service contract that can be implemented with any number of service types. In particular, one service type that implements the service contract can be discarded in favor of another. If the service contract attribute is instead applied directly to a class, that class and its descendants will be the only service types that can implement that particular service contract, and discarding the class will mean discarding the service contract.

  10. At this point, the DerivativesCalculatorServiceType implements the IDerivativesCalculator interface in name only. Its methods do not actually perform the operations described in the service contract. Rectify that now by returning to the DerivativesCalculatorService project in Visual Studio 2005, and choosing Project, Add Reference from the menus. Select the Projects tab, select the entry for the DerivativesCalculator project, shown in Figure 2.7, and click on the OK button.

    Adding a reference to the DerivativesCalculator project.

    Figure 2.7. Adding a reference to the DerivativesCalculator project.

  11. Now program the CalculateDerivative() method of the DerivativesCalculatorServiceType to delegate the work of calculating the value of a derivative to the Calculator class of the DerivativesCalculator project, which was the original class with which other pieces of software were to communicate. Also modify the DoNothing() method of the DerivativesCalculatorServiceType so that it no longer throws an exception:

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public class DerivativesCalculatorServiceType: IDerivativesCalculator
        {
            #region IDerivativesCalculator Members
            decimal IDerivativesCalculator.CalculateDerivative(
                string[] symbols,
                decimal[] parameters,
                string[] functions)
            {
                return new Calculator().CalculateDerivative(
                     symbols, parameters, functions);
            }
    
            void IDerivativesCalculator.DoNothing()
            {
                return;
            }
            #endregion
        }
    }
    
  12. Choose Build, Build Solution from the Visual Studio 2005 menu to ensure that there are no programming errors.

Hosting the Service

Recall that the purpose of this exercise has been to use the Windows Communication Foundation to provide a means by which other software can make use of the facilities provided by the derivatives calculator class written at the outset. That requires making a Windows Communication Foundation service by which the capabilities of the derivatives calculator class are made available. Windows Communication Foundation services are collections of endpoints, with each endpoint consisting of an address, a binding, and a contract. At this point, the contract portion of an endpoint for accessing the facilities of the derivatives calculator has been completed, the contract having been defined and implemented.

The next step is to provide for hosting the service within an application domain. Application domains are the containers that Microsoft’s Common Language Runtime provides for .NET assemblies. So, in order to get an application domain to host a Windows Communication Foundation service, some Windows process will need to initialize the Common Language Runtime on behalf of the service. Any .NET application can be programmed to do that. IIS can also be made to have Windows Communication Foundation services hosted within application domains. To begin with, the derivatives calculator service will be hosted in an application domain within a .NET application, and then, later, within an application domain in IIS:

  1. Choose File, New, Project from the Visual Studio 2005 menus, and add a C# console application called Host to the derivatives calculator solution, as shown in Figure 2.8.

    Adding a host console application to the solution.

    Figure 2.8. Adding a host console application to the solution.

  2. Select Project, Add Reference from Visual Studio 2005 menus, and, from the .NET tab of the Add Reference dialog, add a reference to the System.ServiceModel assembly, as shown earlier in Figure 2.5. Add a reference to the System.Configuration assembly in the same way.

  3. Choose Project, Add Reference from the Visual Studio 2005 menus, and, from the Projects tab, add a reference to the DerivativesCalculatorService project.

  4. Modify the contents of the Program.cs class module in the Host project to match Listing 2.2.

    Example 2.2. A Host for a Service

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.ServiceModel;
    using System.Text;
    
    namespace DerivativesCalculator
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                Type serviceType = typeof(DerivativesCalculatorServiceType);
    
                using(ServiceHost host = new ServiceHost(
                     serviceType))
                {
                     host.Open();
    
                     Console.WriteLine(
                         "The derivatives calculator service is available."
                     );
                     Console.ReadKey(true);
    
                     host.Close();
                }
            }
        }
    }
    

    The key lines in that code are these:

    using(ServiceHost host = new ServiceHost(
        serviceType))
    {
        host.Open();
    
        ...
        host.Close();
    }
    

    ServiceHost is the class provided by the Windows Communication Foundation Service Model for programming .NET applications to host Windows Communication Foundation endpoints within application domains. In Listing 2.2, a constructor of the ServiceHost class is given information to identify the service type of the service to be hosted.

  5. Choose Build, Build Solution from the Visual Studio 2005 menu to ensure that there are no programming errors.

Specifying an Address and a Binding

A Windows Communication Foundation endpoint consists of an address, a binding, and a contract. A contract has been defined and implemented for the endpoint that will be used to provide access to the derivatives calculator class. To complete the endpoint, it is necessary to provide an address and a binding.

Specifying an address and a binding for an endpoint does not require writing any code, and is customarily the work of an administrator rather than a programmer. Providing an address and a binding can be done in code. However, that would require having to modify the code in order to change the address and the binding of the endpoint. A key innovation of the Windows Communication Foundation is to separate how software is programmed from how it communicates, which is what the binding specifies. So, generally, one avoids the option of specifying the addresses and bindings of endpoints in code, and instead specifies them in configuring the host.

As indicated previously, an editing tool, the Service Configuration Editor, is provided, by which administrators can do the configuration. The use of that tool is covered in detail in Chapter 19, “Manageability.” Here, to facilitate a detailed understanding of the configuration language, the configuration will be done by hand:

  1. Use the Project, Add Item menu to add an application configuration file named app.config to the DerivativesCalculatorService project, as shown in Figure 2.9.

    Adding an application configuration file.

    Figure 2.9. Adding an application configuration file.

  2. Modify the contents of the app.config file to look as shown in Listing 2.3.

    Example 2.3. Adding an Address and a Binding

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
          <services>
            <service name=
     "DerivativesCalculator.DerivativesCalculatorServiceType">
              <host>
                <baseAddresses>
                <add baseAddress=
                     "http://localhost:8000/Derivatives/"/>
                   <add baseAddress=
                     "net.tcp://localhost:8010/Derivatives/"/>
                </baseAddresses>
              </host>
              <endpoint
                address="Calculator"
                binding="basicHttpBinding"
                contract=
     "DerivativesCalculator.IDerivativesCalculator"
              />
            </service>
          </services>
        </system.serviceModel>
    </configuration>
    
  3. Choose Build, Build Solution from Visual Studio 2005.

In the XML in Listing 2.3,

<service name=
"DerivativesCalculator.DerivativesCalculatorServiceType">

identifies the service type hosted by the Host application to which the configuration applies. By default, the name by which the service type is identified in the configuration file is matched to the name of a .NET type compiled into the host assembly. In this case, it will be matched to the name of the DerivativesCalculatorServiceType class in the DerivativesCalculator namespace.

Why isn’t the service type identified by the name of a type in the standard .NET format, which is called the assembly-qualified name format? That format identifies a class not only by its name and namespace, but also by the display name of the assembly containing the type. Those assembly display names consist of the name of the assembly, the version number, a public key token, and a culture identifier. So, the assembly-qualified name of a class might look like this (.NET Framework Class Library 2006):

TopNamespace.SubNameSpace.ContainingClass+NestedClass, MyAssembly,
Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089

The assembly-qualified names for types are the standard mechanism for unambiguously identifying a type to be loaded by reflection from any assembly that the Common Language Runtime Loader can locate. Also, they are commonly used in .NET configuration languages for identifying types. Nonetheless, assembly-qualified names are terribly unwieldy to use, for they are not only long, difficult to remember, and easy to mistype, but any errors in entering them also go undetected by the compiler. So, it is a blessing that the Windows Communication Foundation has mostly eschewed their use in its configuration language, and it is to be hoped that the designers of other .NET libraries will follow that example. Furthermore, although the names used to identify service types in the Windows Communication Foundation configuration language are matched, by default, to the names of types, they are really just strings that custom service hosts can interpret in any fashion, not necessarily treating them as the names of .NET types.

This section of the configuration supplies base addresses for the service host in the form of Uniform Resource Identifiers (URIs):

<host>
        <baseAddresses>
                 <add baseAddress=
                 "http://localhost:8000/Derivatives/"/>
                 <add baseAddress=
                 "net.tcp://localhost:8010/Derivatives/"/>
        </baseAddresses>
</host>

The addresses provided for the service’s endpoints will be addresses relative to these base addresses. The term preceding the initial colon of a URI is called the scheme, so the schemes of the two URIs provided as base addresses in this case are http and tcp. Each base address provided for Windows Communication Foundation services must have a different scheme.

The configuration defines a single endpoint at which the facilities exposed by the service type will be available. The address, the binding, and the contract constituents of the endpoint are all specified:

<endpoint
        address="Calculator"
        binding="basicHttpBinding"
        contract=
"DerivativesCalculator.IDerivativesCalculator"
/>

The contract constituent is identified by giving the name of the interface that defines the service contract implemented by the service type. That interface is

IDerivativesCalculator.

The binding constituent of the endpoint is specified in this way:

binding="basicHttpBinding"

To understand what that signifies, one must understand Windows Communication Foundation bindings. A Windows Communication Foundation binding defines a combination of protocols for communicating with a service. Each protocol is represented by a single binding element, and a binding is simply a collection of binding elements. Binding elements are the primary constituents provided by the Windows Communication Foundation’s Channel Layer.

One special category of binding element consists of those that implement protocols for transporting messages. One of those is the binding element that implements the Hypertext Transport Protocol (HTTP). Another is the binding element that implements the Transmission Control Protocol (TCP).

Another special category of binding element consists of those that implement protocols for encoding messages. The Windows Communication Foundation provides three such binding elements. One is for encoding SOAP messages as text. Another is for encoding SOAP messages in a binary format. The third is for encoding SOAP messages in accordance with the SOAP Message Transmission Optimization Mechanism (MTOM), which is suitable for messages that incorporate large quantities of binary data.

Examples of Windows Communication Foundation binding elements that are neither transport protocol binding elements nor message-encoding binding elements are the binding elements that implement the WS-Security protocol and the WS-ReliableMessaging protocol. One of the most important ways in which the capabilities of the Windows Communication Foundation can be extended is with the addition of new binding elements that might be provided by Microsoft, or its partners, or by any software developer. Later chapters show how to program custom binding elements, including custom message-encoding binding elements and custom transport protocol binding elements.

A Windows Communication Foundation binding is a set of binding elements that must include at least one transport protocol binding element and zero or more other binding elements. If no message-encoding binding element is specified, the transport protocol binding element will apply its default message-encoding protocol.

Bindings can be defined by selecting individual binding elements, either in code or in configuration. However, the Windows Communication Foundation provides several classes that represent common selections of binding elements. Those classes are referred to as the predefined bindings.

One of the predefined bindings is the BasicHttpBinding. The BasicHttpBinding represents the combination of the HTTP transport binding element and the binding element for encoding SOAP messages in text format. The BasicHttpBinding class configures those binding elements in accordance with the WS-I Basic Profile Specification 1.1, which is a combination of web service specifications chosen to promote interoperability among web services and consumers of web services on different platforms.

All the current predefined bindings are listed in Table 2.1. They each derive, directly or indirectly, from the class System.ServiceModel.Channels.Binding.

Table 2.1. Windows Communication Foundation Predefined Bindings

Name

Purpose

BasicHttpBinding

Maximum interoperability through conformity to the WS-BasicProfile 1.1

WSHttpBinding

HTTP communication in conformity with WS-* protocols

WSDualHttpBinding

Duplex HTTP communication, by which the receiver of an initial message will not reply directly to the initial sender, but may transmit any number of responses over a period

WSFederationBinding

HTTP communication, in which access to the resources of a service can be controlled based on credentials issued by an explicitly identified credential provider

NetTcpBinding

Secure, reliable, high-performance communication between Windows Communication Foundation software entities across a network

NetNamedPipeBinding

Secure, reliable, high-performance communication between Windows Communication Foundation software entities on the same machine

NetMsmqBinding

Communication between Windows Communication Foundation software entities via Microsoft Message Queuing (MSMQ)

MsmqIntegrationBinding

Communication between a Windows Communication Foundation software entity and another software entity via MSMQ

NetPeerTcpBinding

Communication between Windows Communication Foundation software entities via Windows Peer-to-Peer Networking

This specification, in the configuration of the endpoint for the DerivativesCalculatorService in Listing 2.3

binding="basicHttpBinding"

identifies the BasicHttpBinding as the binding for that endpoint. The lowercase of the initial letter, b, is in conformity with a convention of using camel-casing in configuration files.

You can adjust the settings of a predefined binding by adding a binding configuration to the definition of the endpoint like so:

<system.serviceModel>
    <services>
     <service type=
"DerivativesCalculator.DerivativesCalculatorServiceType">
       <endpoint
         address="Calculator"
         binding="basicHttpBinding"
         bindingConfiguration="bindingSettings"
         contract=
"DerivativesCalculator.IDerivativesCalculator"
       />
     </service>
    </services>
    <bindings>
     <basicHttpBinding>
       <binding name="bindingSettings" messageEncoding="Mtom"/>
     </basicHttpBinding>
    </bindings>
</system.serviceModel>

In this case, the settings for the predefined BasicHttpBinding are adjusted so as to use the MTOM message-encoding binding element rather than the default text message-encoding binding element.

The address specified for the endpoint in the configuration of the DerivativesCalculatorService in Listing 2.3 is Calculator. That address for the endpoint is relative to a base address. Which of the base addresses defined for a service is the base address for the endpoint? It is determined based on the scheme of the base address and the transport protocol implemented by the transport-binding element of the endpoint, as shown in Table 2.2. The transport protocol implemented by the transport-binding element of the endpoint is the HTTP protocol, so, based on the information in Table 2.2, the base address for the endpoint is http://localhost:8000/Derivatives/. Therefore, the absolute address for the endpoint is http://localhost:8000/Derivatives/Calculator.

Table 2.2. Mapping of Base Address Schemes to Transport Protocols

Base Address Scheme

Transport Protocol

http

HTTP

net.tcp

TCP

net.pipe

Named Pipes

net.msmq

MSMQ

Anyone who would like to know the complete Windows Communication Foundation configuration language should study the XML Schema file containing the definition of the configuration language. Assuming that the “Orcas” Development Tools that are among the multiple constituents of the .NET Framework 3.0 have been installed, that XML Schema file should be Program FilesMicrosoft Visual Studio 8XmlSchemasDotNetConfig.xsd, on the disc where Visual Studio 2005 is installed. If that file seems to be missing, search for a file with the extension .xsd, containing the expression system.serviceModel.

Deploying the Service

Now an address, a binding, and a contract have been provided for the Windows Communication Foundation endpoint at which the facilities of the derivatives calculator class will be made available. An application domain for hosting the service incorporating that endpoint has also been provided, or, to be more precise, it will be provided as soon as the Host console application is executed:

  1. Execute that application now by right-clicking on the Host entry in the Visual Studio 2005 Solution Explorer, and selecting Debug, Start New Instance from the context menu. After a few seconds, the console application window of the host should appear, as in Figure 2.10.

    The Host console application running.

    Figure 2.10. The Host console application running.

    The Windows Communication Foundation has examined the code in the Host and DerivativesCalculatorService assemblies, as well as the contents of the Host assembly’s configuration file. The code and the configuration use the Windows Communication Foundation’s Service Model to define a service for accessing the derivatives calculator class. From that code and that configuration, the Windows Communication Foundation generates and configures the service using the programming framework constituted by the classes of the Channel Layer. In particular, it employs the binding element classes used by the BasicProfileBinding class that was selected as the binding for the service. Then the Windows Communication Foundation loads the service into the default application domain of the Host console application.

    This is the step at which folks using the Vista operating system with a version of Visual Studio 2005 that does not have the Vista compatibility update installed could run into difficulty. They might encounter a namespace reservation exception, due to their service being denied the right to use the address they have specified for its endpoint. In that case, it will be necessary for them to grant permission to have a service use the address to the NETWORK SERVICE user account. The official tool for that purpose is Microsoft’s Httpcfg.exe. A more usable one is Steve Johnson’s HTTP configuration utility, which, unlike the Microsoft tool and several others for the same job, sports a graphical user interface. His utility is available at http://www.StevesTechSpot.com.

  2. Confirm that the Windows Communication Foundation service for accessing the capabilities of the derivatives calculator class is available by directing a browser to the HTTP base address that was specified for the service in the host’s application configuration file: http://localhost:8000/Derivatives/. A page like the one shown in Figure 2.11 should be opened in the browser.

    Help page for a service.

    Figure 2.11. Help page for a service.

    A similar page can be retrieved for any Windows Communications Foundation service with a host that has been provided with a base address with the scheme http. It is not necessary that the service have any endpoints with addresses relative to that base address. Note, though, that the page cautions that metadata publishing for the service is disabled. Metadata publishing is disabled by default for the sake of maximizing security so that nothing is made known about a service except what is deliberately chosen by its developers and administrators. To deliberately opt to have the service publish its metadata, it will be necessary to reconfigure it.

  3. Choose Debug, Stop Debugging from the Visual Studio 2005 menus to terminate the instance of the Host console application so that its configuration can be modified.

  4. The configuration needs to be modified to include a behavior setting by which metadata publishing is activated. Edit the app.config file in the Host project of the DerivativesCalculator Solution so that its content matches that of Listing 2.4.

    Example 2.4. Enabling Metadata Publication

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
       <system.serviceModel>
        <services>
          <service name=
    "DerivativesCalculator.DerivativesCalculatorServiceType"
            behaviorConfiguration=
              "DerivativesCalculatorService">
            <host>
              <baseAddresses>
                <add baseAddress=
                   "http://localhost:8000/Derivatives/"/>
                <add baseAddress=
                   "net.tcp://localhost:8010/Derivatives/"/>
              </baseAddresses>
            </host>
            <endpoint
              address="Calculator"
              binding="basicHttpBinding"
              contract=
    "DerivativesCalculator.IDerivativesCalculator"
            />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name=
              "DerivativesCalculatorService">
              <serviceMetadata
                httpGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
    </configuration>
    

    The additions to the configuration of the Windows Communication Foundation service signify that behaviors that apply to a service, rather than to one of its endpoints, are being modified:

    <behaviors>
            <serviceBehaviors>
                     ...
            </serviceBehaviors>
    </behaviors>
    

    The modification is made to the service’s ServiceMetadata behavior, and the nature of the modification is to have the service generate its metadata in response to a request for it in the form of an HTTP GET:

    <serviceMetadata httpGetEnabled="true" />
    

    To associate this behavior configuration with the DerivativesCalculator service, the behavior is given a name

    <behavior name="DerivativesCalculatorService">
            ...
    </behavior>
    

    and identified by that name as a behavior configuration that applies to the service:

    <service name=
    "DerivativesCalculator.DerivativesCalculatorServiceType"
     behaviorConfiguration="DerivativesCalculatorService">
            ...
    </service>
    
  5. Execute the Host console application again by right-clicking on the Host entry in the Visual Studio 2005 Solution Explorer, and selecting Debug, Start New Instance from the context menu.

  6. Add the query wsdl to the URI at which the browser is pointing, by aiming the browser at http://localhost:8000/Derivatives/?wsdl, as in Figure 2.12, and the WSDL for the service should be displayed.

    Examining the WSDL for a service.

    Figure 2.12. Examining the WSDL for a service.

Using the Service

Now a Windows Communication Foundation service is available for accessing the facilities of the derivatives calculator class. The Windows Communication Foundation can be employed to construct a client for the derivatives calculator, a software entity that uses the facilities of the derivatives calculator via the service. Different ways to build the client with the Windows Communication Foundation are shown, as well as ways to build a client in Java for the same Windows Communication Foundation service.

Using the Service with a Windows Communication Foundation Client

For the following steps, access to the tools provided with the Windows Communication Foundation from a .NET command prompt will be required. Assuming a complete and normal installation of the Microsoft Windows SDK for the .NET Framework 3.0, that access is provided by a command prompt that should be accessible from the Windows Start menu by choosing All Programs, Microsoft Windows SDK, CMD Shell. That command prompt will be referred to as the SDK Command Prompt. From that prompt, the Windows Communication Foundation’s Service Metadata Tool, SvcUtil.exe, will be used to generate components of the client for the derivatives calculator:

  1. If the Host console application had been shut down, start an instance of it, as before.

  2. Open the SDK Command Prompt.

  3. Enter

    C:
    

    and then

    cd c:WCFHandsOnFundamentalsDerivativesCalculatorSolution
    

    at that prompt to make the derivatives calculator solution folder the current directory.

  4. Next, enter

    svcutil http://localhost:8000/Derivatives/ /out:Client.cs /config:app.config
    

    The output should be as shown in Figure 2.13.

    Using the Service Metadata Tool.

    Figure 2.13. Using the Service Metadata Tool.

    The command executes the Windows Communication Foundation’s Service Metadata Tool, passing it a base address of a service that has the scheme http. In this case, it is passed the base address of the derivatives calculator service constructed by the earlier steps in this chapter. Given a base address of a Windows Communication Foundation service, provided it is an address with the scheme http, and provided metadata publishing via HTTP GET is enabled for the service, the Service Metadata Tool can retrieve the WSDL for the service and other associated metadata. By default, it also generates the C# code for a class that can serve as a proxy for communicating with the service, as well as a .NET application-specific configuration file containing the definition of the service’s endpoints. The switches /out:Client.cs and /config:app.config used in the foregoing command specify the names to be used for the file containing the C# code and for the configuration file. In the next few steps, the output from the Service Metadata Tool will be used to complete the client for the derivatives calculator.

  5. Choose Debug, Stop Debugging from the Visual Studio 2005 menus to terminate the instance of the Host console application so that the solution can be modified.

  6. Select File, New, Project from Visual Studio 2005 menus to add a C# Console Application project called Client to the DerivativesCalculator solution.

  7. Choose Project, Add Reference from the Visual Studio 2005 menus, and add a reference to the Windows Communication Foundation’s System.ServiceModel .NET assembly to the client project.

  8. Select Project, Add Existing Item from the Visual Studio 2005 menus, and add the files Client.cs and app.config, in the folder C:WCFHandsOnFundamentalsDerivativesCalculatorSolution, to the Client project, as shown in Figure 2.14. Those are the files that should have been emitted by the Service Metadata Tool.

    Adding output from the Service Metadata Tool to a project.

    Figure 2.14. Adding output from the Service Metadata Tool to a project.

  9. Alter the code in the Program.cs file of the Client project of the derivatives calculator solution to use the class generated by the Service Metadata Tool as a proxy for communicating with the derivatives calculator service. The code in the Program.cs file should be the code in Listing 2.5.

    Example 2.5. Using the Generated Client Class

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Client
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                Console.WriteLine("Press any key when the service is ready.");
                Console.ReadKey(true);
    
                decimal result = 0;
                using (DerivativesCalculatorProxy proxy =
                     new DerivativesCalculatorProxy(
                        "BasicHttpBinding_IDerivativesCalculator"))
                {
                     proxy.Open();
                     result = proxy.CalculateDerivative(
                         new string[] { "MSFT" },
                         new decimal[] { 3 },
                         new string[] { });
                     proxy.Close();
                }
                Console.WriteLine(string.Format("Result: {0}", result));
    
                Console.WriteLine("Press any key to exit.");
                Console.ReadKey(true);
    
            }
        }
    }
    

    In Listing 2.5, the statement

    DerivativesCalculatorProxy proxy =
                     new DerivativesCalculatorProxy(
                        "BasicHttpBinding_IDerivativesCalculator"))
    

    creates an instance of the class generated by the Service Metadata Tool to serve as a proxy for the derivatives calculator service. The string parameter passed to the constructor of the class, BasicHttpBinding_IDerivativesCalculator, identifies which definition of an endpoint in the application’s configuration file is the definition of the endpoint with which this instance of the class is to communicate. Therefore, an endpoint definition in the configuration file must be named accordingly.

    The app.config file added to the Client project in step 8 should contain this definition of an endpoint, with a specification of an address, a binding, and a contract:

    <client>
            <endpoint
                     address="http://localhost:8000/Derivatives/Calculator"
                     binding="basicHttpBinding"
                     bindingConfiguration="BasicHttpBinding_IDerivativesCalculator"
                     contract="IDerivativesCalculator"
                     name="BasicHttpBinding_IDerivativesCalculator" />
    </client>
    

    Notice that the name provided for this endpoint definition matches the name that is passed to the constructor of the proxy class.

    The binding configuration named BasicHttpBinding_IDerivativesCalculator to which this endpoint configuration refers, explicitly specifies the default values for the properties of the predefined BasicHttpBinding:

    <basicHttpBinding>
        <binding
            name="BasicHttpBinding_IDerivativesCalculator"
            closeTimeout="00:01:00"
            openTimeout="00:01:00"
            receiveTimeout="00:10:00"
            sendTimeout="00:01:00"
            allowCookies="false"
            bypassProxyOnLocal="false"
            hostNameComparisonMode="StrongWildcard"
            maxBufferSize="65536"
            maxBufferPoolSize="524288"
            maxReceivedMessageSize="65536"
            messageEncoding="Text"
            textEncoding="utf-8"
            transferMode="Buffered"
            useDefaultWebProxy="true">
            <readerQuotas
                             maxDepth="32"
                             maxStringContentLength="8192"
                             maxArrayLength="16384"
                maxBytesPerRead="4096"
                maxNameTableCharCount="16384" />
            <security mode="None">
                <transport
                                      clientCredentialType="None"
                                      proxyCredentialType="None"
                     realm="" />
                <message
                                      clientCredentialType="UserName"
                                      algorithmSuite="Default" />
            </security>
        </binding>
    </basicHttpBinding>
    

    Those default values were left implicit in the service’s configuration of the endpoint. The Service Metdata Tool diligently avoided the assumption that the configuration of the binding that it derived from the metadata is the default configuration.

  10. Prepare to have the client use the derivatives calculator by modifying the startup project properties of the derivatives calculator solution as shown in Figure 2.15.

    Startup project properties of the derivatives calculator solution.

    Figure 2.15. Startup project properties of the derivatives calculator solution.

  11. Choose Debug, Start Debugging from the Visual Studio 2005 menus.

  12. When there is activity in the console for the Host application, enter a keystroke into the console for the Client application. The client should obtain an estimate of the value of a derivative from the derivatives calculator service, as shown in Figure 2.16. Note that the value shown in the Client application console might vary from the value shown in Figure 2.16 due to variations in prevailing market conditions over time.

    Using the derivatives calculator via a service.

    Figure 2.16. Using the derivatives calculator via a service.

  13. In Visual Studio 2005, choose Debug, Stop Debugging from the menus.

Different Ways of Coding Windows Communication Clients

In the preceding steps for building a client for the derivatives calculator service, the code for the client was generated using the Windows Communication Foundation’s Service Metadata Tool. The generated code consists of a version of the IDerivativesProxy interface, and the code of a proxy class for communicating with the derivatives calculator service. The latter code is in Listing 2.6.

Example 2.6. Generated Proxy Class

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute(
        "System.ServiceModel", "3.0.0.0")]
public partial class DerivativesCalculatorClient :
        System.ServiceModel.ClientBase<IDerivativesCalculator>,
        IDerivativesCalculator
{

    public DerivativesCalculatorClient()
    {
    }

    public DerivativesCalculatorClient(
                 string endpointConfigurationName) :
            base(endpointConfigurationName)
    {
    }

    public DerivativesCalculatorClient(
                 string endpointConfigurationName,
                 string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public DerivativesCalculatorClient(
                 string endpointConfigurationName,
                 System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public DerivativesCalculatorClient(
                 System.ServiceModel.Channels.Binding binding,
                 System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
    {
    }

    public decimal CalculateDerivative(
                 string[] symbols,
                 decimal[] parameters,
                 string[] functions)
    {
        return base.Channel.CalculateDerivative(
                         symbols,
                         parameters,
                         functions);
    }
}

Naturally, one can write such a class instead of generating it with the Service Metadata Tool. To do so, one simply defines a class that inherits from the Windows Communication Foundation’s ClientBase<T> generic, and that implements the contract for the service:

  [ServiceContract]
public interface IDerivativesCalculator
{
     [OperationContract]
     decimal CalculateDerivative(
            string[] symbols,
            decimal[] parameters,
            string[] functions);
     ...
}

public partial class DerivativesCalculatorProxy :
     ClientBase<IDerivativesCalculator>,
     IDerivativesCalculator
{
     ...
}

Then, in the class’s implementations of the contract, one simply delegates to the methods of the Channel property of ClientBase<T>:

public partial class DerivativesCalculatorProxy :
    ClientBase<IDerivativesCalculator>,
    IDerivativesCalculator
{
    public decimal CalculateDerivative(string[] symbols,
        decimal[] parameters,
        string[] functions)
    {
        return base.Channel.CalculateDerivative(symbols,
            parameters,
            functions);
    }
}

This way of writing a Windows Communication Foundation client for the derivatives calculator service is one of at least three ways of doing so. The other way of writing a client for the service, given a definition of the IDerivativesCalculator contract, would simply be to write

IDerivativesCalculator proxy =
new ChannelFactory<IDerivativesCalculator>("BasicHttpBinding_IDerivativesCalcula-
tor").
      CreateChannel();
proxy.CalculateDerivative(...);
((IChannel)proxy).Close();

The ChannelFactory<T> generic is defined in the System.ServiceModel.Channels namespace. Whereas the first method for writing clients yields a reusable proxy class, this second method merely yields a proxy variable.

A third option for writing the client would be to program it in such a way that it downloads the metadata for the service and configures a proxy in accordance with that meta-data while executing. Listing 2.7 shows how to do that using the Windows Communication Foundation’s MetadataExchangeClient class. A MetadataExchangeClient object is provided with a location for the metadata for the derivatives calculator service, the same metadata shown earlier in Figure 2.12. Then the GetMetadata() method of the MetadataExchangeClient object is used to download that metadata, which is represented in the form of a MetadataSet object. A WsdlImporter object is constructed from that MetadataSet object. A collection of ServiceEndpoint objects that describe the service endpoints defined in the metadata is obtained using the WsdlImporter object’s ImportAllEndpoints() method. Each ServiceEndpoint object is used to configure a proxy variable that can then be used for communicating with the service.

Example 2.7. Retrieving Metadata Dynamically

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;

namespace Client
{
     class Program
     {
         static void Main(string[] args)
         {
             Console.WriteLine("Press any key when the service is ready.");
             Console.ReadKey(true);

             MetadataExchangeClient metadataExchangeClient =
                  new MetadataExchangeClient(
                  new Uri(
                      "http://localhost:8000/Derivatives/?wsdl"),
                  MetadataExchangeClientMode.HttpGet);

             MetadataSet metadataSet =
                  metadataExchangeClient.GetMetadata();
             WsdlImporter importer =
                  new WsdlImporter(metadataSet);
             ServiceEndpointCollection endpoints =
                  importer.ImportAllEndpoints();
             IDerivativesCalculator proxy = null;
             foreach (ServiceEndpoint endpoint in endpoints)
             {
                  proxy = new ChannelFactory<IDerivativesCalculator>(
                      endpoint.Binding, endpoint.Address).CreateChannel();
                  ((IChannel)proxy).Open();
                  Console.WriteLine(proxy.CalculateDerivative(
                      new string[] { "MSFT" },
                      new decimal[] { 3 },
                      new string[] { }));
                  ((IChannel)proxy).Close();
             }
             Console.WriteLine("Press any key to exit.");
             Console.ReadKey(true);
         }
     }
}

Using the Service with a Java Client

The service by which the facilities of the derivatives calculator class are made available for use by other software entities, is configured to use the Windows Communication Foundation’s predefined BasicProfileBinding. That binding conforms to the WS-I Basic Profile Specification 1.1. Therefore, the service can be used not only by clients built using the Windows Communication Foundation, but by any clients that can consume services that comply with that specification.

The Apache Foundation provides a web services development toolkit for Java programmers called Axis. Axis incorporates a tool called WSDL2Java, which, like the Windows Communication Foundation’s Service Metadata Tool, will download the WSDL for a service and generate the code of a class that can be used as a proxy for the service. Whereas the Windows Communication Foundation’s Service Metadata Tool can generate code in the C#, Visual Basic .NET, VBScript, JScript, JavaScript, Visual J#, and C++ programming languages, the WSDL2Java tool generates code only in the Java programming language.

You can download Axis from http://ws.apache.org/axis/. After it has been installed correctly, and the Host console application of the derivatives calculator solution is running, one can issue this command from a command prompt:

java org.apache.axis.wsdl.WSDL2Java http://localhost/Derivatives/?wsdl

That command should cause WSDL2Java to download the WSDL for the Windows Communication Foundation derivatives calculator service and generate Java code for accessing the service.

The quantity of that code will be much larger than the quantity of code emitted by the Windows Communication Foundation’s Service Metadata Tool. The code for a proxy class for the derivatives calculator service generated by the WSDL2Java tool is 18KB in size, whereas the code for a proxy class for the same service emitted by the Windows Communication Foundation’s tool is about 3KB in size.

Given the code emitted by the WSDL2Java tool, one can write a Java application to use the derivatives calculator service. The code for such an application is in Listing 2.8. Figure 2.17 shows the application executing within the Eclipse 3.1 development environment, which is available from http://eclipse.org/downloads/.

Example 2.8. WSDL2Java Proxy

import org.tempuri.*;
import java.math.*;

public class Client
{
    public static void main(String[] arguments)
    {
        try
        {
            String[] symbols = new String[1];
            symbols[0] = "MSFT";

            BigDecimal[] parameters = new BigDecimal[1];
            parameters[0] = new BigDecimal(3);

            String[] functions = new String[1];
            functions[0] = "TechStockProjections";

            DerivativesCalculatorServiceTypeLocator locator =
                 new DerivativesCalculatorServiceTypeLocator();
            IDerivativesCalculator stub =
                 locator.getBasicHttpBinding_IDerivativesCalculator_port();
            BigDecimal[] values = new BigDecimal[1];
            values[0] = stub.calculateDerivative(symbols,parameters,functions);


            System.out.println(String.format("Result: %f", values));
        }
        catch(Exception e)
        {
            System.out.println("Error: " + e.getMessage());
        }

        try
        {
            System.in.read();
        }
        catch(Exception e)
        {
        }
    }
}
Using the derivatives calculator service using a Java Client.

Figure 2.17. Using the derivatives calculator service using a Java Client.

Hosting the Service in IIS

Recall that IIS can be made to provide application domains for hosting Windows Communication Foundation services. Having IIS provide hosts for Windows Communication Foundation services is beneficial for several reasons:

  • IIS is a scalable host. Its scalability features include central processing unit (CPU) affinity and web gardening.

  • IIS is a reliable host. Its reliability features include health management, process isolation, and application domain isolation.

  • IIS is a fault-tolerant host. If an unhandled exception occurs in a service, IIS automatically restarts it.

  • The security of IIS has been arduously tested, found wanting, and reinforced. Although IIS is notorious for having been the victim of a number of successful attacks in the past, it now incorporates lessons learned from that experience, making it far more trustworthy than untried alternatives.

Only services of which all the endpoints have HTTP bindings can be hosted within IIS 5.1 and IIS 6. Those are the versions of IIS provided for Windows XP and Windows Server 2003. IIS 7 incorporates a new facility, called the Windows Activation Service, for routing messages received using any transport protocol to hosted .NET assemblies. Thus, Windows Communication Foundation services can be hosted within IIS 7 regardless of their transport protocols. Even custom transport protocols added to the Windows Communication Foundation’s Channel Layer can be supported in IIS 7 through customizations to the Windows Activation Service.

To have IIS host a Windows Communication Foundation service, one must simply identify the service type of the service to IIS. That is done in a file with content very similar to the contents of the .asmx file that you would use in creating an ASP.NET web service. For example, to have the derivatives calculator service hosted within IIS, one would use a file containing this directive

<%@ServiceHost Service="DerivativesCalculator.DerivativesCalculatorServiceType" %>

which identifies the service type of the service that IIS is to host.

Now, by default, a file with this directive, telling IIS to host a Windows Communication Foundation service, must have the extension .svc. However, one can specify any number of alternative extensions by adding the appropriate entry to the system’s web.config file, which should be in the CONFIG subdirectory of the .NET Framework subfolder of the system directory. For example, an entry like the following would specify that not only the .svc extension, but also the .asmx extension should be treated as containing directives for the hosting of Windows Communication Foundation services:

<system.web>
        <compilation>
                 <compilation debug="true">
                         <buildProviders>
                                  <remove extension=".asmx"/>
                                  <add extension=".asmx"
                                     type="System.ServiceModel.ServiceBuildProvider,
                                     System.ServiceModel,
                                     Version= 3.0.0.0,
                                     Culture=neutral,
                                     PublicKeyToken= b77a5c561934e089" />
                         </buildProviders>
                 </compilation>
        </compilation>
</system.web>

Having files with the .asmx extension treated as files with directives for hosting Windows Communication Foundation services would be useful in rewriting ASP.NET web services as Windows Communication Foundation services. You could rewrite the ASP.NET services as Windows Communication Foundation services and have clients of the original services still be able to refer to those services using URIs with paths containing the .asmx extension.

Up to this point, the Windows Communication Foundation service for accessing the facilities of the derivatives calculator class has been hosted within a console application. The steps for hosting the service within IIS begin with these steps for creating an IIS virtual directory by which IIS will map a URI to the location of the derivatives calculator service:

  1. Choose Control Panel, Administrative Tools, Internet Information Services (IIS) Manager from the Windows Start menu.

  2. Expand the nodes of the tree control in the left pane until the node named Default Web Site becomes visible.

  3. Right-click on that node, and choose New, Virtual Directory from the context menu that appears.

  4. In the Virtual Directory Creation Wizard, enter DerivativesCalculator in the Virtual Directory alias screen.

  5. Enter

    c:WCFHandsOnFundamentalsDerivativesCalculatorSolutionDerivativesCalculatorService
    

    as the path on the Web Site Content Directory screen of the wizard.

    Select the Read, Run Scripts, and Execute permissions on the wizard’s Virtual Directory Access Permissions screen; then click Next and follow the instructions to exit the wizard.

    Right-click on the node representing the new DerivativesCalculator virtual directory under the Default Web Site node, and choose Properties from the context menu that appears. Select the ASP.NET tab, and ensure that the ASP.NET version chosen for the virtual directory is 2.0.50727 or higher, as shown in Figure 2.18.

    Selecting the .NET 2.0 Common Language Runtime for use with a virtual directory.

    Figure 2.18. Selecting the .NET 2.0 Common Language Runtime for use with a virtual directory.

The creation of the IIS virtual directory is complete. These next few steps deploy the Windows Communication Foundation service in that virtual directory:

  1. Add a text file named Service.svc to the DerivativesCalculatorService project.

  2. Add content to that file so that it looks like this:

    <%@ServiceHost Service= "DerivativesCalculator.DerivativesCalculatorServiceType" %>
    

    This directive tells IIS to host the Windows Communication Foundation service type DerivativesCalculator.DerivativesCalculatorServiceType. IIS will be looking for that type among the assemblies in the bin subdirectory of the folder in which the file referring to the assembly is located. Therefore, it is necessary to ensure that the asssembly is located there. The next two steps will accomplish that task.

  3. Select the DerivativesCalculatorService project of DerivativesCalculatorSolution in the Visual Studio 2005 Solution Explorer. Choose Project, DerivativesCalculatorService Properties from the Visual Studio menus. Select the Build tab, and set the value of the Output path property to refer to the bin subdirectory of the project directory, as shown in Figure 2.19.

    Altering the build properties of the DerivativesCalculatorService project.

    Figure 2.19. Altering the build properties of the DerivativesCalculatorService project.

  4. Select Build, Build Solution from the Visual Studio 2005 menus.

The remaining two steps are for configuring the service. In hosting the service within the Host console application, the configuration for the service was incorporated into the configuration file for that application. Now that the service is to be hosted within IIS, the configuration information must be a configuration file named Web.config in the same directory as the file with the directives telling IIS to host the service. Follow these steps to create the configuration file:

  1. Add an application configuration file named Web.config to the DerivativesCalculatorService project in the derivatives calculator solution.

  2. Modify the contents of that file in this way, before saving the file:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
             <system.serviceModel>
                      <services>
                              <service name=
    "DerivativesCalculator.DerivativesCalculatorServiceType"
      behaviorConfiguration="DerivativesCalculatorService">
                                     <endpoint
                                              address="Calculator"
                                              binding="basicHttpBinding"
                                              contract=
    "DerivativesCalculator.IDerivativesCalculator"
                                       />
                              </service>
                      </services>
                      <behaviors>
                              <serviceBehaviors>
                                       <behavior name="DerivativesCalculatorService">
                                          <serviceMetadata httpGetEnabled="true" />
                                       </behavior>
                              </serviceBehaviors>
                      </behaviors>
             </system.serviceModel>
    </configuration>
    

    There is just one difference between this configuration information and the information that was in the application configuration file of the Host console application: no base addresses are specified. Base addresses are not required because the base address of a Windows Communication Foundation service hosted within IIS is the URI of the file containing the directives telling IIS to host the service.

The work required for hosting the derivatives calculator service in IIS is now complete. To confirm the availability of the service, follow these steps:

  1. Choose Run from the Windows Start menu, and enter

    http://localhost/DerivativesCalculator/Service.svc
    

    Internet Explorer should open and display a page similar to the one shown earlier in Figure 2.11. Now that the service is available, the client can be modified to use the derivatives calculator service hosted within IIS.

  2. Modify the app.config file in the Client project of the derivatives calculator solution to refer to the address of the endpoint hosted within IIS by changing this entry in the file

    address="http://localhost:8000/Derivatives/Calculator"
    

    to this:

    address="http://localhost/DerivativesCalculator/Service.svc/Calculator"
    
  3. Choose Build, Build Solution from the Visual Studio 2005 menus.

  4. Right-click on the Client entry in the Visual Studio 2005 Solution Explorer, and select Debug, Start New Instance from the context menu.

  5. When the console application window of the host appears, enter a keystroke into the console. The client obtains an estimate of the value of a derivative from the derivatives calculator service hosted in IIS, with output like that shown earlier in Figure 2.16. Note, again, that the value shown in the Client application console might vary from the value shown in Figure 2.16 due to variations in prevailing market conditions over time.

  6. Close the Client executable.

Changing How the Service Communicates

This chapter has introduced the Windows Communication Foundation as a software factory template that provides a simple modeling language, the Service Model, for describing how a piece of software is to communicate. The key terms of that language are address, binding, and contract. The Windows Communication Foundation examines the software communication model provided for an application using those terms, and builds runtime components from the Windows Communication Foundation Channel Layer to implement the model when the application prepares to communicate. The binding included in the model specifies the transmission protocols by which the application can send and receive messages. The claim was made that by simply changing the binding, you can alter the transmission protocols that the application uses, and, moreover, that the alteration can be made solely within the configuration for the application, without any code having to be changed. That claim will now be corroborated.

The steps that follow will have the client communicating with the derivatives calculator service hosted within the .NET application. Prepare for that by altering the client application’s configuration file so that the client directs its transmissions to the appropriate address by following these steps:

  1. Modify the app.config file in the Client project of the derivatives calculator solution to refer to the address of the endpoint hosted within the .NET application by changing this entry in the file

    address="http://localhost/DerivativesCalculator/Service.svc/Calculator"
    

    back to this:

    address="http://localhost:8000/Derivatives/Calculator"
    
  2. Choose Build, Build Solution from the Visual Studio 2005 menus.

These next steps will serve to capture the communications directed to the service hosted by the .NET application, making use of just one of the Windows Communications Foundation’s many features for administering services: its facility for logging messages.

  1. Provide an empty folder to which the Windows Communication Foundation can log messages. In the following steps, that folder will be assumed to be c:logs.

  2. Modify the app.config file of the Host project of the derivatives calculator solution to look as shown in Listing 2.9, which configures a standard .NET diagnostics trace listener to listen for trace information emanating from the Windows Communication Foundation’s message-logging facility, System.ServiceModel.MessageLogging. The configuration also turns that logging facility on with the diagnostics element within the System.ServiceModel element.

    Example 2.9. Message Logging Configuration

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
            <system.diagnostics>
                     <sources>
                             <source
                                      name="System.ServiceModel.MessageLogging"
                                      switchValue="Verbose">
                                      <listeners>
                                               <add
                                             name="xml"
                              type="System.Diagnostics.XmlWriterTraceListener"
                                             initializeData="c:logsmessage.log" />
                                      </listeners>
                             </source>
                     </sources>
                     <trace autoflush="true" />
            </system.diagnostics>
            <system.serviceModel>
                     <diagnostics>
                             <messageLogging logEntireMessage="true"
                                             maxMessagesToLog="300"
                                             logMessagesAtServiceLevel="false"
                                             logMalformedMessages="false"
                                             logMessagesAtTransportLevel="true" />
                     </diagnostics>
                     <services>
                             <service name=
    "DerivativesCalculator.DerivativesCalculatorServiceType"
     behaviorConfiguration="DerivativesCalculatorService">
                                      <host>
                                               <baseAddresses>
                                                       <add
          baseAddress="http://localhost:8000/Derivatives/"/>
                                                       <add
          baseAddress="net.tcp://localhost:8010/Derivatives/"/>
                                               </baseAddresses>
                                      </host>
                                      <endpoint
                                               address="Calculator"
                                               binding="basicHttpBinding"
                                               contract=
    "DerivativesCalculator.IDerivativesCalculator"
                                      />
                             </service>
                     </services>
                     <behaviors>
                             <serviceBehaviors>
                                      <behavior name="DerivativesCalculatorService">
                                         <serviceMetadata httpGetEnabled="true" />
                                      </behavior>
                             </serviceBehaviors>
                     </behaviors>
            </system.serviceModel>
    </configuration>
    
  3. Build the solution.

  4. Start an instance of the Client executable, and enter a keystroke into the console for the Client application. The client should obtain an estimate of the value of a derivative from the derivatives calculator service, as shown earlier in Figure 2.16.

  5. Enter a keystroke into the console of the client application to terminate it.

  6. Enter a keystroke into the console of the service’s host application to terminate it.

  7. Open the file c:logsMessage.log in Notepad. Search for the string MSFT, which, as should be apparent from Listing 2.5, is a stock symbol that the client transmits to the server in its request to calculate the value of a derivative. That string will be found in the file because the communications are being transmitted in accordance with the WS-I Basic Profile 1.1, which stipulates the sending of plain text XML via HTTP.

  8. Delete the file c:logsMessage.log.

  9. Use Notepad to open the file Host.exe.config, which should be in the folder C:WCFHandsOnFundamentalsDerivativesCalculatorSolutionHostinDebug.

  10. Make a single modification to that file, changing

    binding="basicHttpBinding"
    

    to

    binding="netTcpBinding"
    
  11. Save the file.

  12. Use Notepad to open the file Client.exe.config, which should be in the folder C:WCFHandsOnFundamentalsDerivativesCalculatorSolutionClientinDebug.

  13. Modify the endpoint configuration in that file so that it looks like this:

    <endpoint address="net.tcp://localhost:8010/Derivatives/Calculator"
         binding="netTcpBinding"
         contract="IDerivativesCalculator"
    
         name="BasicHttpBinding_IDerivativesCalculator"/>
    
  14. Save the file.

  15. Start an instance of the Client executable, and enter a keystroke into the console for the Client application. The client should obtain an estimate of the value of a derivative from the derivatives calculator service as usual.

  16. Enter a keystroke into the console of the client application to terminate it.

  17. Enter a keystroke into the console of the service’s host application to terminate it.

  18. Open the file c:logsMessage.log in Notepad. Search for the string MSFT. That string will not be found in the file because this time the protocol used for transmission was the Windows Communication Foundation’s own TCP protocol, which encrypts messages by default.

Thus, without even recompiling either the client or the service, the manner in which those applications communicate with each other has been altered considerably. The only changes that were made were to the description of the endpoints in the Service Model’s configuration language.

Summary

The Windows Communication Foundation provides a software factory template for software communication, consisting of a modeling language called the Service Model, and a programming framework called the Channel Layer. The Service Model incorporates a class library and a configuration language by which services are described simply as collections of endpoints defined by an address, a binding, and a contract. Descriptions of software communication solutions expressed in the language of the Service Model are used as input for generating the components of the solution from the lower-level class library that is the Channel Layer. Using the software factory template for communication among applications that the Windows Communication Foundation provides, one can quickly adapt code to new scenarios. For instance, as demonstrated in the foregoing, one can host the same service within a .NET console application or within IIS without modifying the code for the service at all. One can also easily change how a client and a service communicate, making the communication between them confidential, for example. Being able to adapt software to diverse scenarios with little effort has always been the promise of model-driven development. With the Windows Communication Foundation, that promise is realized for software communications.

References

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

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