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 one where a service is located, how to communicate with it, and what it will do.

Those three things are exactly what one specifies in building software communication facilities with the Windows Communication Foundation Service Model: where the software 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 acronym a, b, c can serve as a reminder of the key terms of the Windows Communication Foundation Service Model and, thereby, as a reminder to 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 over a network is a service, a service has one or more endpoints to which communications can be directed, and an endpoint consists of an address, a binding, and a contract. 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 that are 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 is done by writing an interface in a .NET programming language,

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


and then 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 to and from the service type from outside 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.

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:

string httpBaseAddress = "http://localhost:8000/EchoService/"; string tcpBaseAddress = "net.tcp://localhost:8080/EchoService/"; Uri[] baseAddresses = new Uri[] {     new Uri(httpBaseAddress),     new Uri(tcpBaseAddress) }; using (ServiceHost host = new ServiceHost(typeof(Service), baseAddresses )) {     host.Open();     Console.WriteLine("The service is ready.");     Console.ReadKey();     host.Close(); }


Next, an administrator specifies an address and a binding for the service. An editing tool, shown in Figure 2.1, is provided for that purpose.

Figure 2.1. Defining an address and a binding.


As indicated in Figure 2.2, the administrator can also use the editing tool to add behaviors to control how the Windows Communication Foundation moves data to and from the 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, and generates the necessary components by which the service can receive and respond to communications from the Channel Layer.

Figure 2.2. Adding behaviors to a service.


Among what it generates is WSDL to define the address, bindings, and contracts of the service. A programmer developing an application to communicate with the service can download that WSDL, and generate code for contacting the service, as well as an application configuration file with the address and binding information. That can be done with a single command:

svcutil http://localhost:8000/EchService/Echo


Then the programmer can use the generated code to communicate with the service:

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


The preceding steps are all that is involved in using the Windows Communication Foundation. The value of using it is in the administrator being able to modify how the service communicates simply by modifying the binding, without the code having to be changed, and by the administrator being able to make the service communicate in an unlimited variety of ways. When the service's host executes again, the Windows Communication Foundation generates the communications infrastructure for the new or modified endpoints. At last, the promise of model-driven development has actually yielded something tangible: a software factory template by which the communications system of an application can be manufactured from a model.

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:\WCFHandsOn\Fundamentals, as shown in Figure 2.3.

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.



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 DerivativesCalculatorService {     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 several new class libraries that the Windows Communication Foundation adds to the .NET Framework Class Library 2.0.

    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 DerivativesCalculatorService {     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 DerivativesCalculatorService {     [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. One 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

    One 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.

    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.

    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 be able 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, 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 have 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.

    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.

    Listing 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);             string httpBaseAddress =                 ConfigurationManager.AppSettings["HTTPBaseAddress"];             string tcpBaseAddress =                 ConfigurationManager.AppSettings["TCPBaseAddress"];             Uri httpBaseAddressUri = new Uri(httpBaseAddress);             Uri tcpBaseAddressUri = new Uri(tcpBaseAddress);             Uri[] baseAdresses = new Uri[] {                 httpBaseAddressUri,                 tcpBaseAddressUri};             using(ServiceHost host = new ServiceHost(                 serviceType,                 baseAdresses))             {                 host.Open();                 Console.WriteLine(                     "The derivatives calculator service is available."                 );                 Console.ReadKey();                 host.Close();             }         }     } }

    The key lines in that code are these:

    using(ServiceHost host = new ServiceHost(     serviceType,     baseAdresses)) {     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. The constructor is also given an array of Uniform Resource Identifiers (URIs). Those URIs are Windows Communication Foundation base addresses from which the actual addresses of each hosted Windows Communication Foundation endpoint will be derived. In this particular case, two base addresses are provided, and those base addresses are retrieved from the application's configuration file. Consequently, a configuration file with those base addresses must be created.

  5. 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.

    Figure 2.9. Adding an application configuration file.

  6. Modify the contents of the app.config file in this way:

    <?xml version="1.0" encoding="utf-8" ?> <configuration>      <appSettings>             <add key="HTTPBaseAddress"                     value="http://localhost:8000/Derivatives/"/>             <add key="TCPBaseAddress"                     value="net.tcp://localhost:8010/Derivatives/"/>      </appSettings> </configuration>

    Here, the URIs used as base addresses are http://localhost:8000/Derivatives/ and net.tcp://localhost:8010/Derivatives/. The expression preceding the initial colon of a URI is called the schema, so the schemas of these URIs are http and tcp. In providing base addresses to the Windows Communication Foundation ServiceHost, the URI for each base address must have a unique schema.

  7. 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. The alternative is to specify them in configuring the host.

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

  1. Modify the app.config file of the Host project to look as shown in Listing 2.3.

    Listing 2.3. Adding an Address and a Binding

    <?xml version="1.0" encoding="utf-8" ?> <configuration>     <appSettings>         <add key="HTTPBaseAddress" value="http://localhost:8000/Derivatives/"/>         <add key="TCPBaseAddress" value="net.tcp://localhost:8010/Derivatives/"/>     </appSettings>     <system.serviceModel>         <services>             <service type= "DerivativesCalculator.DerivativesCalculatorServiceType,               DerivativesCalculatorService">                 <endpoint                        address="Calculator"                        binding="basicHttpBinding"                        contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"                 />             </service>         </services>     </system.serviceModel> </configuration>

  2. Choose Build, Build Solution from the Visual Studio 2005.

In the XML in Listing 2.3,

<service type= "DerivativesCalculator.DerivativesCalculatorServiceType,               DerivativesCalculatorService">


identifies the configuration of the DerivativesCalculatorServiceType hosted by the Host application. The expression

"DerivativesCalculator.DerivativesCalculatorServiceType,               DerivativesCalculatorService"


is the name of the DerivativesCalculatorServiceType in a standard .NET format, which is called the assembly-qualified name format. In the expression, DerivativesCalculator is the namespace of the service type, DerivativesCalculatorServiceType is the name of the service type itself, and DerivativesCalculatorService is the display name of the assembly that contains the service type.

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.

The contract constituent is identified by giving the assembly-qualified name of the interface that defines the service contract implemented by the service type, DerivativesCalculatorServiceType. That interface is IDerivativesCalculator, which is in the DerivativesCalculatorService assembly:

contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"


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 is a combination 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, which may be provided by Microsoft, or its partners, or by any software developer. Later chapters show how to program custom message-encoding binding elements and custom transport protocol binding elements.

Now, a Windows Communication Foundation binding is a collection of binding elements that must include at least one transport protocol binding element, one or more message-encoding protocol binding elements, and zero or more other binding elements. Bindings may 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 may be 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 from the class System.ServiceModel.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 via HTTP in conformity with WS-* protocols.

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.

One 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,               DerivativesCalculatorService">       <endpoint            address="Calculator"            binding="basicHttpBinding"            bindingConfiguration="bindingSettings"            contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"       />     </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 provided to the host of a service is the base address for a given endpoint 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 Visual Studio 2005 Extensions for WinFX have been installed, that XML Schema file should be \Program Files\Microsoft Visual Studio 8\Xml\Schemas\DotNetConfig.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.

    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.

  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 provided to the ServiceHost: http://localhost:8000/Derivatives/. A page like the one shown in Figure 2.11 should be opened in the browser.

    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.

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

    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 January 2006 WinFX CTP, 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 Microsoft Windows Vista DEBUG Build Environment 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 Microsoft Windows Vista DEBUG Build Environment prompt.

  3. Enter

    C:

    and then

    cd c:\WCFHandsOn\Fundamentals\DerivativesCalculatorSolution

    at that prompt to make to 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.

    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 scheme http, the Service Metadata Tool can retrieve the WSDL for the service and other associated metadata and, by default, generate the C# code for a class that can serve as a proxy for communicating with the service. It also generates, by default, 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:\WCFHandsOn\Fundamentals\DerivativesCalculatorSolution, to the Client project, as shown in Figure 2.14. Those are the files that should have been emitted by the Service Metadata Tool.

    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.4.

    Listing 2.4. 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();             decimal result = 0;             using (DerivativesCalculatorProxy proxy =                 new DerivativesCalculatorProxy("CalculatorEndpoint"))             {                 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();         }     } }

    In Listing 2.4, the statement

    DerivativesCalculatorProxy proxy =              new DerivativesCalculatorProxy("CalculatorEndpoint")

    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, CalculatorEndpoint, 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, one must identify an endpoint definition in the configuration file 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"                   bindingConfiguration="BasicHttpBinding_IDerivativesCalculator"                   binding="customBinding" contract="IDerivativesCalculator" /> </client>

    Why does the binding look different here than it does in the configuration file for the service? The Service Metadata Tool does not know about the predefined bindings, which the Windows Communication Foundation provides as a convenience for humans. The Service Metadata Tool examines the metadata for the service and configures a custom binding to match the substance of the binding described in the metadata.

  10. Modify the endpoint definition so that it has the name of the endpoint definition passed to the constructor of the proxy class in the foregoing C# code, the name CalculatorEndpoint:

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

  11. 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.

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

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

  13. 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 may vary from the value shown in Figure 2.16, due to variations in prevailing market conditions over time.

    Figure 2.16. Using the derivatives calculator via a service.

  14. 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.5.

Listing 2.5. Generated Proxy Class

public partial class DerivativesCalculatorProxy :     System.ServiceModel.ClientBase<IDerivativesCalculator>,     IDerivativesCalculator {     public DerivativesCalculatorProxy()     {     }     public DerivativesCalculatorProxy(string endpointConfigurationName) :             base(endpointConfigurationName)     {     }     public DerivativesCalculatorProxy(string endpointConfigurationName,         string remoteAddress) :             base(endpointConfigurationName, remoteAddress)     {     }     public DerivativesCalculatorProxy(string endpointConfigurationName,         System.ServiceModel.EndpointAddress remoteAddress) :             base(endpointConfigurationName, remoteAddress)     {     }     public DerivativesCalculatorProxy(System.ServiceModel.Binding binding,         System.ServiceModel.EndpointAddress remoteAddress) :             base(binding, remoteAddress)     {     }     public decimal CalculateDerivative(string[] symbols,         decimal[] parameters,         string[] functions)     {         return base.InnerProxy.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 InnerProxy property of ClientBase<T>:

public partial class DerivativesCalculatorProxy :     ClientBase<IDerivativesCalculator>,     IDerivativesCalculator {     public decimal CalculateDerivative(string[] symbols,         decimal[] parameters,         string[] functions)     {         return base.InnerProxy.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>("CalculatorEndpoint").   CreateChannel(); proxy.CalculateDerivative(...); ((IChannel)proxy).Close();


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 metadata while executing. Listing 2.6 shows how to do that using the Windows Communication Foundation's MetadataResolver class. A MetadataResolver instance is provided with a location for the metadata for the derivatives calculator service, the same metadata shown earlier in Figure 2.12. Then the RetrieveEndpointsUsingHttpGet() method of the MetadataResolver instance is used to download that metadata and generate a collection of ServiceEndpoint objects that describe the service endpoints defined in the metadata. Each ServiceEndpoint object is used to configure a proxy variable that is then able to be used for communicating with the service.

Listing 2.6. Retrieving Metadata Dynamically

using System; using System.Collections.Generic; using System.ServiceModel; using System.ServiceModel.Design; using System.Text; namespace Client {     class Program     {         static void Main(string[] args)         {             Console.WriteLine("Press any key when the service is ready.");             Console.ReadKey();             MetadataResolver metadataResolver = new MetadataResolver(                 new EndpointAddress(                 @"http://localhost/Metadata/DerivativesCalculatorService.wsdl"));             ServiceEndpointCollection endpoints =                 metadataResolver.RetrieveEndpointsUsingHttpGet();             IDerivativesCalculator proxy = null;             foreach (ServiceEndpoint endpoint in endpoints)             {                 proxy = new ChannelFactory<IDerivativesCalculator>(                     endpoint.Binding, endpoint.Address).CreateChannel();                 proxy.CalculateDerivative(                     3,                     new string[] { "MSFT" },                     new string[] { });                 ((IChannel)proxy).Close();             }             Console.WriteLine("Press any key to exit.");             Console.ReadKey();         }     } }

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 standard 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.

One 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.7. Figure 2.17 shows the application executing within the Eclipse 3.1 development environment, which is available from http://eclipse.org/downloads/.

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


Listing 2.7. 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)         {         }     } }

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 bindings for communicating using HTTP can be hosted within IIS 5.1 and IIS 6, those being 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 one 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 these directives:

<%@Service  %> <%@Assembly Name="DerivativesCalculatorService" %>


The Service directive identifies the service type of the service that IIS is to host, and the Assembly directive indicates which assembly contains that service type.

Now, by default, a file with these directives, telling IIS to host a Windows Communication Foundation service, must have the extension .svc. In the February CTP and earlier releases of WinFX, that default cannot be modified, but it will be possible to modify it in subsequent releases. Specifically, one will be able to specify any number of extensions by adding the appropriate entries to the system's web.config file, which should be in the CONFIG subdirectory of the .NET Framework installation folder. For example, entries like these 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>     ...     <buildProviders>       ...       <add         extension=".asmx"         type="System.ServiceModel.ServiceBuildProvider,                 System.ServiceModel, ... " />       <add         extension=".svc"         type="System.ServiceModel.ServiceBuildProvider,                 System.ServiceModel, ..." />     </buildProviders>       ...   </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. One 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 URI with a path containing an .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 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:\WCFHandsOn\Fundamentals\DerivativesCalculatorSolution\DerivativesCalculatorService

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

  6. 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.

The creation of the IIS virtual directory is complete. Here are the remaining steps for having IIS host the derivatives calculator service:

1.

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

1.

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

<%@Service  %> <%@Assembly Name="DerivativesCalculatorService" %>


Those directives tell IIS to host the Windows Communication Foundation service type DerivativesCalculator.DerivativesCalculatorServiceType that is in the assembly DerivativesCalculatorService. IIS will be looking for that assembly 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.18.

Figure 2.18. 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.

5.

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

6.

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 type= "DerivativesCalculator.DerivativesCalculatorServiceType,    DerivativesCalculatorService">                 <endpoint                     address=""                     binding="basicHttpBinding"                     contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"                 />            </service>         </services>     </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: The value provided for the address of the service's endpoint is an empty string. The reason is that the address of any endpoint of a 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 complete. The availability of the service can be confirmed in this way:

  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/DerivativesCalculatorService/Service.svc"

  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 may vary from the value shown in Figure 2.16, due to variations in prevailing market conditions over time.

  6. Close the Client executable.

Securing the Service

The only provision that the WS-I Basic Profile 1.1 makes for securing communications is the use of HTTPS. Because that protocol was never applied to the derivatives calculator service, one should not expect that transmissions to and from the service are being kept confidential at this point.

The following steps will prove that the transmissions are not being kept confidential. They will also demonstrate 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 Web.config file of the DerivativesCalculatorService project to look as shown in Listing 2.8, 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.

Listing 2.8. 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:\logs\message.log" />                 </listeners>             </source>         </sources>         <trace autoflush="true" />     </system.diagnostics>     <system.serviceModel>         <diagnostics>             <messageLogging logEntireMessage="true"                             maxMessagesToLog="300"                             logMessagesAtServiceLevel="false"                             logMalformedMessages="true"                             logMessagesAtTransportLevel="true" />         </diagnostics>         <services>             <service type= "DerivativesCalculator.DerivativesCalculatorServiceType,    DerivativesCalculatorService">                 <endpoint                     address=""                     binding="basicHttpBinding"                     contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"                 />             </service>         </services>     </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 hosted in IIS, as shown earlier in Figure 2.16.

5.

Close the Client executable.

6.

Open the file c:\logs\Message.log in Notepad. Search for the string MSFT, which, as should be apparent from Listing 2.4, 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 communications with the derivatives calculator service are not being kept confidential.

The Windows Communication Foundation provides at least two principal ways of remedying that problem. One is to secure the transmissions by using a secure transport protocol, substituting HTTPS for HTTP, for example. The other is to encrypt the messages before transporting them, as provided for by the WS-Security protocol, for example.

Securing the Service with a Secure Transport Protocol

The HTTPS protocol uses the Secure Socket Layer/Transport Layer Security (SSL/TLS) protocol. Instructions for configuring the SSL/TLS protocol on IIS are available at http://www.microsoft.com/smallbusiness/support/articles/sec_IIS_6_0.mspx#EDAA.

Assuming that the SSL/TLS protocol has been configured on the IIS hosting the derivatives calculator service, secure transmissions between the client and the service via the HTTPS protocol can be accomplished simply by replacing the contents of the Web.config file in the DerivativesCalculatorService project of the derivatives calculator solution with the configuration in Listing 2.9, and by replacing the contents of the app.config file the Client project with the configuration in Listing 2.10.

Listing 2.9. Secure Service Configuration

<?xml version="1.0" encoding="utf-8" ?> <configuration>     <system.serviceModel>         <services>             <service type= "DerivativesCalculator.DerivativesCalculatorServiceType,   DerivativesCalculatorService">                 <endpoint                     address=""                     binding="basicHttpBinding"                     bindingConfiguration="SecureBasicHttpBinding"                     contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"                 />             </service>         </services>         <bindings>             <basicHttpBinding>                 <binding name="SecureBasicHttpBinding">                     <security mode="Transport">                         <transport clientCredentialType="None"/>                     </security>                 </binding>             </basicHttpBinding>         </bindings>     </system.serviceModel> </configuration>

Listing 2.10. Secure Client Configuration

<?xml version="1.0" encoding="utf-8"?> <configuration>     <system.serviceModel>         <client>             <endpoint             name="CalculatorEndpoint"             address="https://localhost/DerivativesCalculatorService/Service.svc"             bindingConfiguration="SecureBasicHttpBinding"             binding="basicHttpBinding" contract="IDerivativesCalculator" />         </client>         <bindings>         <basicHttpBinding>             <binding name="SecureBasicHttpBinding">                 <security mode="Transport">                     <transport clientCredentialType="None"/>                 </security>             </binding>         </basicHttpBinding>         </bindings>     </system.serviceModel> </configuration>

Both configurations incorporate these two lines:

binding="basicHttpBinding" bindingConfiguration="SecureBasicHttpBinding"


The first line should be familiar from the foregoing: It simply says that the standard Windows Communication Foundation BasicHttpBinding is the binding for the derivatives calculator endpoint. The second line is new. It says that the properties of the standard BasicHttpBinding are to be modified somewhat from their default values, and that the set of modifications are labeled SecureBasicHttpBinding. Elsewhere within the System.ServiceModel element of the configuration, there is this sub-element:

<bindings>     <basicHttpBinding>         <binding name="SecureBasicHttpBinding">             <security mode="Transport">                 <transport clientCredentialType="None"/>             </security>         </binding>     </basicHttpBinding> </bindings>


That sub-element could contain any number of different sets of modifications to the default settings of any number of different standard bindings. In this case, it contains just one set of modifications, which is the set with the label SecureBasicHttpBinding, the set to which the line

bindingConfiguration="SecureBasicHttpBinding"


referred. The modifications to the default settings specify that transmissions are to be secured by the transport protocol. Note that the only modifications that the Windows Communication provides for the standard BasicHttpBinding are modifications that are permitted by the WS-I Basic Profile 1.1 specification.

The only other important change in the configurations is this alteration, in Listing 2.10, to the client configuration:

address="https://localhost/DerivativesCalculatorService/Service.svc"


It uses the scheme https in the URI for the service, thereby directing the request via IIS's SSL/TLS socket.

Encrypting Messages Before Transporting Them

WS-Security is a standard protocol for ensuring the confidentiality of communications through the encryption of messages. Although the WS-Security protocol is widely accepted and despite there being several implementations, it is, nonetheless, not included in the WS-I Basic Profile Specification 1.1, which was meant to ensure interoperability by incorporating only the most fundamental protocols. Yet although the use of a transport security protocol like HTTPS to ensure confidentiality tends to provide better performance, the use of a protocol like WS-Security that works by encrypting the messages before transporting them offers more flexibility. For example, whereas the use of HTTPS presupposes having a Web server like IIS that supports HTTPS, the Windows Communication makes it very simple to apply the WS-Security protocol in scenarios with or without IIS. Follow these steps to see how it is done:

1.

Modify the app.config file of the Host project in the derivatives calculator solution to look like the configuration in Listing 2.11.

Listing 2.11. Configuring for Message Security

<?xml version="1.0" encoding="utf-8" ?> <configuration>     <appSettings>         <add key="HTTPBaseAddress" value="http://localhost:8000/Derivatives/"/>         <add key="TCPBaseAddress" value="net.tcp://localhost:8010/Derivatives/"/>     </appSettings>     <system.diagnostics>         <sources>             <source                 name="System.ServiceModel.MessageLogging"                 switchValue="Verbose">                 <listeners>                     <add                         name="xml"                         type="System.Diagnostics.XmlWriterTraceListener"                         initializeData="c:\logs\message.log" />                 </listeners>             </source>         </sources>         <trace autoflush="true" />     </system.diagnostics>     <system.serviceModel>         <services>  <diagnostics>             <messageLogging logEntireMessage="true"                             maxMessagesToLog="300"                             logMessagesAtServiceLevel="false"                             logMalformedMessages="true"                             logMessagesAtTransportLevel="true" />         </diagnostics>             <service type= "DerivativesCalculator.DerivativesCalculatorServiceType,   DerivativesCalculatorService">                 <endpoint                     address="Calculator"                     binding="wsHttpBinding"                     contract= "DerivativesCalculator.IDerivativesCalculator,DerivativesCalculatorService"                 />             </service>         </services>     </system.serviceModel> </configuration>

This change to the configuration file of the .NET application for hosting the derivatives calculator service substitutes the standard binding WSHttpBinding for the standard binding BasicHttpBinding that had been used before. WSHttpBinding is a standard binding that, by default, uses the WS-Security protocol.

The new configuration also has the service log the messages it receives. Specifically, the service is to log the messages to the file message.log in the folder c:\logs. Change that setting to point to a different file and folder if necessary.

2.

Ensure that whatever file is referred to in the configuration for logging the messages does not exist, or has been deleted. Having a fresh log will serve to highlight the effects of the new configuration clearly.

3.

Change the app.config file in the Client project to look like this, with a description of the derivatives calculator endpoint matching the description in the server's configuration:

<?xml version="1.0" encoding="utf-8"?> <configuration>     <system.serviceModel>         <client>             <endpoint             name="SelfHostedEndpoint"             address="http://localhost:8000/Derivatives/Calculator" binding="wsHttpBinding" contract="IDerivativesCalculator" />         </client>     </system.serviceModel> </configuration>


4.

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

5.

When there is activity in the console for the Host application, enter a keystroke into the console for the Client application. The client should again obtain an estimate of the value of a derivative from the derivatives calculator service, as shown earlier in Figure 2.16.

6.

Stop debugging.

7.

Open the file c:\logs\Message.log in Notepad. Search for the string MSFT, which, as mentioned before, is a stock symbol that the client transmits to the server in its request to calculate the value of a derivative. That string will not be found in the file, because now the messages exchanged with the derivatives calculator service are being kept confidential through encryption.

8.

Modify the CalculateDerivative() method of the DerivativesCalculatorServiceType in the DerivativesCalculatorService project to look like this:

decimal IDerivativesCalculator.CalculateDerivative(             string[] symbols,             decimal[] parameters,             string[] functions) { Console.WriteLine(                "Message received from {0}.",                System.ServiceModel.                OperationContext.                Current.ServiceSecurityContext.                WindowsIdentity.Name.ToString());                 return new Calculator().CalculateDerivative(                    symbols, parameters, functions); }


9.

Reexecute steps 4, 5, and 6. This time, the console application window of the Host application should show the identity of the user of the client application. That is possible because, by default, the WSHttpBinding uses the Windows identity of the user of the client application to authenticate a client to a service. The Windows Communication Foundation Service Model's OperationContext class provides static properties for retrieving information about the context in which a method of a service is being invoked, and, in the new code for the CalculateDerivative() method, it is the information about the identity of the client that is retrieved and displayed.

The Windows Communication Foundation's OperationContext class may seem familiar to programmers used to Microsoft Transaction Server, COM+, and Enterprise Services programming. The OperationContext class is similar to the ContextUtil class of those earlier programming interfaces.

Debugging

The Windows Communication Foundation's facility for logging messages has already been demonstrated earlier in this chapter. That is a powerful tool for diagnosing problems with services in production, and it should be welcomed by anyone who has attempted the challenging task of logging messages to or from ASP.NET Web Services. Other potent instruments for administering Windows Communication Foundation solutions in production are covered in Chapter 12.

To diagnose problems with Windows Communication Foundation solutions in development, the most important tool is the Visual Studio 2005 debugger. Generally, one can simply set breakpoints in the code for a client or service, and start debugging one's code.

In the case of a service, what happens when one starts debugging it within Visual Studio 2005 is that Visual Studio automatically attaches its debugger to the host process. When the service is being hosted within IIS, one must attach the Visual Studio 2005 debugger to the host process manually. Doing so requires two steps.

The first step is to cause IIS to actually have the service loaded into an application domain. That can be done either by having a client invoke the service, or by browsing to the location of the service's .svc file to view the service's help page.

The remaining step is to actually attach the Visual Studio debugger to the host process. One begins doing that by choosing Debug, Attach to Process from the Visual Studio menus. Then, on Windows Server 2003 one selects w3wp.exe from the list in the Attach to Process dialog, and on Windows XP one selects aspnet_wp.exe, those being the processes in which IIS hosts Windows Communication Foundation services. Finally, one clicks on the Attach button. Then, any breakpoint set in the code for the service can provide a starting point for stepping through it.

Evidently, although it is not especially difficult to debug services hosted in IIS, it is a little more challenging. Therefore, it is recommended to follow the approach shown in this chapter of first hosting the service within one's own .NET application, and thoroughly debugging it within that process, before proceeding to host the service within IIS.




Presenting Microsoft Communication Foundation. Hands-on.
Microsoft Windows Communication Foundation: Hands-on
ISBN: 0672328771
EAN: 2147483647
Year: 2006
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net