Wrox Home  
Search
Professional ASP.NET 2.0 XML
by Thiru Thangarathinam
January 2006, Paperback


Processing the SOAP Header from a Web Service

The SoapHeader attribute is used to associate a SOAP header with a Web method. A public member variable is added to the WebService class to hold an instance of the class derived from the SoapHeader class. The name of the member variable is then communicated to the ASP.NET runtime via the SoapHeader attribute. Listing 2 shows the modified QuotesService class definition that is now capable of processing the SoapPaymentHeader.

Listing 2: Web Service Method That Processes the SOAP Header
using System;
using System.Xml;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class QuotesService : System.Web.Services.WebService
{
  public SoapPaymentHeader paymentHeader;
  [WebMethod(Description = 
  	"Returns real time quote for a given stock ticker")]
  [SoapHeader("paymentHeader", Direction = SoapHeaderDirection.In)]
  public double GetStockPriceWithPayment(string symbol)
  {
    //Process the SOAP header
    if (paymentHeader != null)
    {
      string nameOnCard = paymentHeader.NameOnCard;
      string creditCardNumber = paymentHeader.CreditCardNumber;
      CardType type = paymentHeader.CreditCardType;
      DateTime ExpirationDate = paymentHeader.ExpirationDate;
      //Process the payment details
      //.........
      ///End Processing
    }
    else 
      throw new SoapHeaderException("Invalid information in SOAP Header", 
        SoapException.ClientFaultCode);
    double price;
    switch (symbol.ToUpper())
    {
      case "INTC":
        price = 70.75;
        break;
      case "MSFT":
        price = 50;
        break;
      case "DELL":
        price = 42.25;
        break;
      default:
        throw new SoapException("Invalid Symbol", 
			SoapException.ClientFaultCode,
          "http://wrox.com/quotes/GetStockPriceWithPayment");
    }
    return price;
  }
}

Listing 2 declares a member variable named paymentHeader to hold the data contained in the payment SOAP header.

public SoapPaymentHeader paymentHeader;

Note that you do not create an instance of the SoapPaymentHeader class because the ASP.NET runtime is responsible for creating this object and populating its properties with the data contained within the payment header received from the client.

Next you add two SoapHeader attributes to declare that the headers should formally be described as part of the Web method. The constructor of the SoapHeader attribute takes a string that contains the name of the public member variable that should be associated with the SOAP header.

[SoapHeader("paymentHeader", Direction = SoapHeaderDirection.In)]

You set the Direction property to SoapHeaderDirection.In. The Direction property indicates whether the client or the server is supposed to send the header. In this case, because the payment header is received from the client, you set the Direction property to SoapHeaderDirection.In. If a SOAP header is received from the client and then also sent back to the client, the value of the Direction property should be set to SoapHeaderDirection.InOut.

Next the code processes the contents of the SOAP payment header. If the payment header information is not passed in, you throw a SoapHeaderException back to the callers.

throw new SoapHeaderException("Invalid information in SOAP Header", 
  SoapException.ClientFaultCode);

The rest of the implementation is similar to the previous example.

Now that you have associated the payment header with the Web method, the next task is to send the payment SOAP header from the client. Listing 3 shows the ASP.NET pages that creates an instance of the SOAP payment header and sends that as part of the SOAP request that is sent to the server.

Listing 3: Passing SOAP Header Information to a Web Service Method
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Services.Protocols" %>
<script runat="server">
  void btnGetQuote_Click(object sender, EventArgs e)
  {
    try
    {
      QuotesProxy.SoapPaymentHeader header = new 
        QuotesProxy.SoapPaymentHeader();
      header.CreditCardNumber = "xxxxxxxxxxxxxxxx";
      header.CreditCardType = QuotesProxy.CardType.VISA;
      header.NameOnCard = "XXXXXX";
      header.ExpirationDate = DateTime.Today.AddDays(365);
      QuotesProxy.QuotesService obj = new QuotesProxy.QuotesService();
      obj.SoapPaymentHeaderValue = header;
      output.Text = 
	  	obj.GetStockPriceWithPayment(txtSymbol.Text).ToString();
    }
    catch (SoapHeaderException soapEx)
    {            
      output.Text = "Actor : " + soapEx.Actor + "<br><br>";
      output.Text += "Code  : " + soapEx.Code + "<br><br>";
      output.Text += "Message: " + soapEx.Message + "<br><br>";
      output.Text += "Detail: 
	  	" + Server.HtmlEncode(soapEx.Detail.OuterXml);
    }
    catch (Exception ex)
    {
      output.Text = "Exception is : " + ex.Message;
    }
  }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
  <title>Passing SOAP Headers to a Web Service Method</title>
</head>
<body>
  <form id="form1" runat="server">
    <div>
      Enter Stock Symbol: <asp:TextBox runat="server" ID="txtSymbol" />
      <asp:Button Text="Get Quote" runat="server" ID="btnGetQuote" 
        OnClick="btnGetQuote_Click" />
      <br /><br /><br />
      <asp:Label Font-Bold=true runat="server" ID="output" />
    </div>
  </form>
</body>
</html>

To start with, Listing 3 creates an instance of the SoapPaymentHeader object and sets its properties to appropriate values. It then sets the SoapPaymentHeaderValue property of the proxy object to the SoapHeader object.

obj.SoapPaymentHeaderValue = header;

After you set the SoapPaymentHeaderValue property, the contents of the SOAP header will be automatically transferred as part of the SOAP message. Next you also handle any errors thrown by the Web service using two catch blocks: SoapHeaderException block and a generic Exception block.

Conclusion

As you have seen from this article, the optional SOAP Header element can contain additional information not directly related to the particular message. In addition to the optional data related to the message, the SOAP header can also contain information processed by infrastructure within a Web server.

This article is adapted from Professional ASP.NET 2.0 XML by Thiru Thangarathinam (Wrox, 2006, ISBN: 0-7645-9677-2), from Chapter 13 "XML Web Services." Thiru works for Intel Corporation where he focuses on enterprise applications and service oriented architecture. He is a Microsoft Certified Application Developer (MCAD) specializing in architecting and building distributed n-tier applications using ASP.NET, C#, VB, ADO.NET, and SQL Server.Thiru's other recent article on Wrox.com is "Atlas Foundations: ASP.NET 2.0 Callback" excerpted from chapter 9 "XML Data Display" in Professional ASP.NET 2.0 XML.