< Chap 11 TOC: XML Web Service & Network | Main | ASP .NET, C# Web Service Program Example & IIS >

 


 

 

Chapter 11 Part 1:

XML Web Services and the Network

 

 

What do we have in this chapter 11 Part 1?

  1. Web Services

  2. Interacting with the Network

  3. Web Services and HTTP

  4. Extending Your Service

  5. Controlling the HTTP Request-Response Pair

  6. C# Code Snippet

  7. Visual Basic .NET Code Snippet

  8. C++ Code Snippet

 

 

This chapter won’t dwell on what Web services are in the .NET Framework. Instead, we’ll look at how Web services interact with the lower-level network aspects of the stack. We’ll start this chapter by examining the components that make up a Web service in the .NET Framework. Then we’ll dive into the details of controlling how Web services interact with the Hypertext Transfer Protocol (HTTP) and how to override a Web service request to change the protocol. Next we’ll talk about how to get the best performance and scalability out of your Web service applications while avoiding some of the common pitfalls. Finally, we’ll talk about the future of Web services and how to design your applications such that they will continue to work well as Web services evolve.

 

Web Services

 

In version 1.1 of the Microsoft Windows .NET Framework, Web services are exposed in the form of matching client and server technologies that map to the HTTP request-response model. Figure 11-1 illustrates the flow of a message as it travels from client to server and back.

 

Figure 11-1: Web service message flow over HTTP in the .NET Framework

 

A client application issues a request by calling a method on a class that represents a client “proxy” for the server. The .NET Framework takes care of serializing that call into a SOAP message and sending it in an HTTP POST command to the server. On the server side, Internet Information Server (IIS) receives the request and passes it up through ASP.NET, where it gets deserialized and exposed to the server application code in the form of a method call. The method is then called. When the method completes, the server responds, and the response data gets serialized and sent back to the client application.

 

Interacting with the Network

 

There are two critical points to bear in mind as you consider how Web services interact with the network. First, it’s important to understand the relationship between a Web service call and the underlying transport used to flow that call from one location to another. It’s also necessary to understand the APIs available to help control the flow of a message as it originates from the client, gets transported and processed on the server, and is received back in the form of a response.

 

Web Services and HTTP

 

From a network perspective, it’s important to understand that Web services in version 1.1 of the .NET Framework use the HTTP protocol. Most production Web services use HTTP, but because SOAP is transport-protocol independent, you can expect more services to use SOAP in the future. The Web services implementation in the framework allows an application to call a Web service, using either the HTTP POST verb or the HTTP GET verb. In practice, most applications use HTTP POST because it passes a SOAP envelope to the server within a request body, as opposed to including it as part of the query string parameters. This approach is more in line with the design of the HTTP protocol and, therefore, is better understood by the HTTP infrastructure that handles the message, which makes it more efficient and reliable.

HTTP protocol bindings for a Web service are specified in two locations: in the machine.config file stored in the config subdirectory within the .NET Framework version directory on the machine, as shown in the following Figure for .NET framework version 1.1.x and 2.0.x.

 

 

Or in a Web.config file associated with a particular application on the server as shown in the following search result Figure.

 

 

The following code sample demonstrates using the configuration settings in the System.Web section of the configuration system to control these bindings:

 

<configuration>

  <system.Web>

    <WebServices>

      <protocols>

        <add name="HttpSoap1.2"/>

        <!-- reserved for future use -->

        <add name="HttpSoap"/>

        <!-- <add name="HttpPost"/> -->

        <!-- <add name="HttpGet"/> -->

        <add name="HttpPostLocalhost” />"

        <add name="Documentation" />

      </protocols>

    </WebServices>

  </system.Web>

</configuration>

 

Notice that HttpPost and HttpGet are disabled by default. This is because they are intended for certain interoperability scenarios and do not offer the same level of control or efficiency as the HttpSoap binding. Although the HttpSoap binding uses an HTTP POST to send the data, it’s different from the HttpPost binding because HttpSoap sends a SOAP message in the HTTP payload, whereas HttpPost simply sends form-encoded XML data in the HTTP payload. The original intent of HttpPost was for interoperability with XML and RPC (Remote Procedure Call) services that didn’t understand SOAP. The SOAP protocol is now common, however, and HttpPost is rarely needed. Documentation provides the documentation page that comes up when you hit the service URL with a browser. POST on the local host enables you to locally test a service with basic types such as int or string by typing values into an auto-generated HTML page in the browser and hitting a button.

Understanding the dependency that exists between Web services and the HTTP infrastructure is important as it will help you to realize that Web services can be managed, monitored, debugged, and so on using the same or similar models as those used for Web sites in general. A critical difference, however, is the role that the client plays in the conversation. In the world of static or dynamically generated HTML and the browser, most of the control over network-related elements in an application is given to the developer and administrators on the server only. In the world of Web services decisions made by the application developer, both the client and the server can have a significant influence over the end-user experience in terms of performance, scalability, and security.

 

Extending Your Service

 

Web services in the .NET Framework include an extensibility model that enables an application to gain access to a message before and after it gets serialized or deserialized by the framework. This model is known as a SOAP extension. SOAP extensions make it possible for an application to modify the stream used to represent the message body to add support for features such as encryption, custom logging, and compression.

The good examples of SOAP extensions are available online at SoapExtension Class.

 

Controlling the HTTP Request-Response Pair

 

In addition to extending a SOAP message, the framework provides a way for an application to control the actual HTTP protocol being emitted by the client request. This functionality is when you want to add custom HTTP headers. This is often done in cases in which infrastructure, or other parts of the system, rely on certain patterns or values in the HTTP message, and these values must be added to the Web service call so that it can interoperate with these systems. The following code demonstrates how you can use access to the HTTP headers to send custom HTTP information to the server:

 

C# Code Snippet

using System;

using System.Net;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace WebServiceClientCS

{

    /// <summary>

    /// Sample class that demonstrates calling a Web service

    /// with a custom HTTP header.

    /// </summary>

    class WebServicesMathClient

    {

        [STAThread]

        static void Main(string[] args)

        {

            // Get x,y from the console

            Console.Write("X:");

            int x = int.Parse(Console.ReadLine());

            Console.Write("Y:");

            int y = int.Parse(Console.ReadLine());

 

            // Instantiate the derived math service

            MyMathService mathService = new MyMathService();

            // Call the add method and print the result

            float result = mathService.Add(x, y);

            Console.WriteLine(x + " + " + y + " = " + result);

        }

    }

 

    /// <summary>

    /// MyMathService gets a WebRequest and sets the default credentials

    /// and a custom header on the request.  If you need control over the

    /// HTTP semantics of a Web service request it is much better to override

    /// the auto generated proxy class so that you don't lose the changes when

    /// the proxy gets re-generated.

    /// </summary>

    class MyMathService : WebServiceClientCS.localhost.Service1

    {

        // GetWebRequest is called before the SOAP request is sent

        protected override WebRequest GetWebRequest(Uri url)

        {

            // Create a request based on the supplied URI

            WebRequest request = WebRequest.Create(url);

            // Set default credentials                  

            request.Credentials = CredentialCache.DefaultCredentials;

            // Set a custom header value on the request

            request.Headers["custom-header"] = "custom-value";

 

            return request;

        }

    }

}

 

 

Visual Basic .NET Code Snippet

Imports System

Imports System.Net

'Sample class that demonstrates calling a Web service

'with a custom HTTP header.

Module Module1

 

    Sub Main()

        'Get x,y from the console

        Console.WriteLine("Please input two values to be multiplied")

        Console.Write("First number:")

        Dim x As Integer = Integer.Parse(Console.ReadLine())

        Console.Write("Second number:")

        Dim y As Integer = Integer.Parse(Console.ReadLine())

 

        'Instantiate the derived math service

        Dim mathService As MyMathService = New MyMathService

        'Call the add method and print the result

        Dim result = mathService.Multiply(x, y)

 

        Console.WriteLine(x & " * " & y & " = " & result)

    End Sub

End Module

 

'MyMathService gets a WebRequest and sets the default credentials

'and a custom header on the request.  If you need control over the

'HTTP semantics of a Web service request it is much better to override

'the auto generated proxy class so that you don't lose the changes when

'the proxy gets re-generated.

Class MyMathService

    'WebServiceClientCS.localhost.Service1

    Inherits WebServiceClientVB.localhost.Service1

    'GetWebRequest is called before the SOAP request is sent

    Protected Overrides Function GetWebRequest(ByVal url As Uri) As WebRequest

        'Create a request based on the supplied URI

        Dim request As WebRequest = WebRequest.Create(url)

        'Set default credentials            

        request.Credentials = CredentialCache.DefaultCredentials

        'Set a custom header value on the request

        request.Headers("custom-header") = "custom-value"

        Return request

    End Function

End Class

C++ Code Snippet

// WebServiceClientCP.cpp : main project file.

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Net;

 

/// <summary>

/// MyMathService gets a WebRequest and sets the default credentials

/// and a custom header on the request.  If you need control over the

/// HTTP semantics of a Web service request it is much better to override

/// the auto generated proxy class so that you don't lose the changes when

/// the proxy gets re-generated.

/// </summary>

public ref class MyMathService:localhost::Service1

{

    // GetWebRequest is called before the SOAP request is sent

            protected:

                        virtual WebRequest^ GetWebRequest(System::Uri^ url) override

        {

            // Create a request based on the supplied URI

                                    WebRequest^ request = WebRequest::Create(url);

            // Set default credentials

                                    request->Credentials = CredentialCache::DefaultCredentials;

            // Set a custom header value on the request

                                    request->Headers["custom-header"] = "custom-value";

 

            return request;

        }

    };

 

[STAThread]

int main(array<System::String ^> ^args)

{

            float result;

           // Get x,y from the console, just a demo for addition operation

            Console::WriteLine("Please provide the x and y values to be added");

            Console::Write("X:");

            int x = int::Parse(Console::ReadLine());

            Console::Write("Y:");

            int y = int::Parse(Console::ReadLine());

 

            // Instantiate the derived math service

            Console::WriteLine("Instantiating the derived math service...");

    MyMathService^ mathService = gcnew MyMathService();

            // Call the add method and print the result

            Console::WriteLine("Call the add method from the ASP web service and print the result...");

            result = mathService->Add((float)x, (float)y);

            Console::WriteLine(x + " + " + y + " = " + result);

    return 0;

}

The custom header added in this example can be used to route the request or to handle other HTTP-level processing. Also notice that the override to GetWebRequest happens in a class that derives from the Web service, rather than in the automatically generated client proxy itself. This is because if the client proxy gets regenerated, Microsoft Visual Studio .NET will overwrite the previous proxy file and any overrides will need to be reinserted. By making the changes in a derived class, the overrides will continue to work even after the client proxy is regenerated. Furthermore, the derived class changes can be applied to other Web services that also need this functionality.

 

 

 


< Chap 11 TOC: XML Web Service & Network | Main | ASP .NET, C# Web Service Program Example & IIS >