Using SOAP Headers
Using SOAP Headers
Communicating with an XML Web service method using SOAP follows a standard format. Part of this format is the data that is encoded in an XML document. The XML document consists of a root Envelope tag, which in turn consists of a required Body element and an optional Header element. The Body element comprises the data specific to the message. The optional Header element can contain additional information not directly related to the particular message. Each child element of the Header element is called a SOAP header.
Although the SOAP headers can contain data related to the message, as the SOAP specification doesn’t strictly define the contents of a SOAP header, they typically contain information processed by infrastructure within a Web server. An example of how a SOAP header can be used is to supply routing information for the SOAP message within the SOAP header.
Defining and Processing SOAP Headers
XML Web services created using ASP.NET can define and manipulate SOAP headers. Defining a SOAP header is accomplished by defining a class representing the data in a particular SOAP header and deriving it from the SoapHeader class.
To define a class representing a SOAP header
- Create a class deriving from the SoapHeaderclass with a name matching the root element for the SOAP header.
public class MyHeader : SoapHeader [Visual Basic] Public Class MyHeader : Inherits SoapHeader
- Add public fields or properties, matching the names and their respective data types for each element in the SOAP header.For instance, given the following SOAP header, the class following it defines a class representing the SOAP header.
public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [Visual Basic] Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class
To process SOAP headers within an XML Web service
- Add a public member to the class implementing the XML Web service of the type representing the SOAP header.
[WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader timeStamp; [Visual Basic] <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService ' Add a member variable of the type deriving from SoapHeader. Public TimeStamp As MyHeader
- Apply a SoapHeader attribute to each XML Web service method that intends to process the SOAP header. Set the MemberName property of the SoapHeaderattribute to the name of the member variable created in the first step.
[WebMethod] [SoapHeader("timeStamp")] public void MyWebMethod() [Visual Basic] <WebMethod, SoapHeader("TimeStamp")> _ Public Sub MyWebMethod()
- Within each XML Web service method that the SoapHeaderattribute is applied to, access the member variable created in the first step to process the data sent in the SOAP header.
[WebMethod] [SoapHeader("timeStamp", Direction=SoapHeaderDirection.InOut)] public string MyWebMethod() { // Verify that the client sent the SOAP Header. if (timeStamp == null) { timeStamp = new MyHeader(); } // Set the value of the SoapHeader returned // to the client. timeStamp.Expires = 60000; timeStamp.Created = DateTime.UtcNow; return "Hello World"; } [Visual Basic] <WebMethod,SoapHeader("TimeStamp", _ Direction:=SoapHeaderDirection.InOut)> _ Public Function MyWebMethod() As String ' Verify that the client sent the SOAP Header. If (TimeStamp Is Nothing) Then TimeStamp = New MyHeader End If ' Set the value of the SoapHeader returned ' to the client. TimeStamp.Expires = 60000 TimeStamp.Created = DateTime.UtcNow Return "Hello World" End Function
The following code example demonstrates how to define and process a SOAP header in an XML Web service created using ASP.NET. The MyWebService
XML Web service has a member variable named timeStamp
, which is of a type deriving from SoapHeader (MyHeader
) and set to the MemberName property of the SoapHeader attribute. In addition, a SoapHeader attribute is applied to the MyWebMethod
XML Web service method specifying myHeaderMemberVariable
. Within the MyWebMethod
XML Web service method, myHeaderMemberVariable
is accessed to set the value of the Created
and Expires
XML elements of the SOAP header.
<%@ WebService Language="C#" Class="MyWebService" %> using System; using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService : System.Web.Services.WebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader timeStamp; // Apply a SoapHeader attribute. [WebMethod] [SoapHeader("timeStamp", Direction=SoapHeaderDirection.InOut)] public string HelloWorld() { if (timeStamp == null) timeStamp = new MyHeader(); timeStamp.Expires = 60000; timeStamp.Created = DateTime.UtcNow; return "Hello World"; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits System.Web.Services.WebService ' Add a member variable of the type deriving from SoapHeader. Public timeStamp As MyHeader ' Apply a SoapHeader attribute. <WebMethod(), _ SoapHeader("timeStamp", Direction:=SoapHeaderDirection.InOut)> _ Public Function HelloWorld() As String If (timeStamp Is Nothing) Then timeStamp = New MyHeader End If timeStamp.Expires = 60000 timeStamp.Created = DateTime.UtcNow Return "Hello World" End Function End Class
In the previous example, a SOAP response is returned to the client with the Expires
element set to 60000 (number of milliseconds, so 1 minute) and the Created
element to the current time in coordinated universal time. That is, the following SOAP response is sent to the client.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <MyHeader xmlns="http://www.contoso.com"> <Created>dateTime</Created> <Expires>long</Expires> </MyHeader> </soap:Header> <soap:Body> <MyWebMethod xmlns="http://www.contoso.com" /> </soap:Body> </soap:Envelope>
Building a Client that Processes SOAP Headers
An XML Web services client can send and receive SOAP headers when communicating with an XML Web service. When a proxy class is generated for an XML Web service expecting or returning SOAP headers using the Wsdl.exe utility, the proxy class includes information about the SOAP headers. Specifically, the proxy class has member variables representing the SOAP headers that correlate to those found in the XML Web service. The proxy class also has definitions for the corresponding classes representing the SOAP header. For example, proxy classes generated for the previous XML Web service will have a member variable of type MyHeader
and a definition for the MyHeader
class. For details on creating a proxy class, see Creating an XML Web Service Proxy.
Note: If the XML Web service defines the member variables representing the SOAP headers of type SoapHeader or SoapUnknownHeader instead of a class deriving from SoapHeader, a proxy class will not have any information about that SOAP header.
To process SOAP headers within an XML Web service client
- Create a new instance of the class representing the SOAP header.
Dim mySoapHeader As MyHeader = New MyHeader() [C#] MyHeader mySoapHeader = new MyHeader();
- Populate the values for the SOAP header.
header.Expires = 60000 header.Created = DateTime.UtcNow [C#] header.Expires = 60000; header.Created = DateTime.UtcNow;
- Create a new instance of the proxy class.
Dim proxy As MyWebService = New MyWebService() [C#] MyWebService proxy = new MyWebService();
- Assign the SOAP header object to the member variable of the proxy class representing the SOAP header.
proxy.MyHeaderValue = mySoapHeader [C#] proxy.MyHeaderValue = mySoapHeader
- Call the method on the proxy class that communicates with the XML Web service method.The SOAP header portion of the SOAP request sent to the XML Web service will include the contents of the data stored in the SOAP header object.
Dim results as String = proxy.MyWebMethod() [C#] string results = proxy.MyWebMethod();
The following code example demonstrates how to pass a SOAP header from a client to an XML Web service.
<%@ Page Language="VB" %> <asp:Label id="ReturnValue" runat="server" /> <script runat=server language=VB> Sub Page_Load(o As Object, e As EventArgs) Dim header As MyHeader = New MyHeader() ' Populate the values of the SOAP header. header.Expires = 60000 header.Created = DateTime.UtcNow ' Create a new instance of the proxy class. Dim proxy As MyWebService = New MyWebService() ' Add the MyHeader SOAP header to the SOAP request. proxy.MyHeaderValue = header ' Call the method on the proxy class that communicates ' with your XML Web service method. Dim results as String = proxy.MyWebMethod() ' Display the results of the method in a label. ReturnValue.Text = results End Sub </script> [C#] <%@ Page Language="C#" %> <asp:Label id="ReturnValue" runat="server" /> <script runat=server language=c#> void Page_Load(Object o, EventArgs e) { MyHeader header = new MyHeader(); // Populate the values of the SOAP header. header.Expires = 60000; header.Created = DateTime.UtcNow; // Create a new instance of the proxy class. MyWebService proxy = new MyWebService(); // Add the MyHeader SOAP header to the SOAP request. proxy.MyHeaderValue = header; // Call the method on the proxy class that communicates // with your XML Web service method. string results = proxy.MyWebMethod(); // Display the results of the method in a label. ReturnValue.Text = results; } </script>
Changing the SOAP Headers Recipients
By default, SOAP headers are sent by an XML Web service client to an XML Web service method when a SoapHeader attribute is applied to an XML Web service method. However, a SOAP header can also be sent by the XML Web service method back to the XML Web service client. It can also be sent both ways. Setting the Direction property of a SoapHeader attribute applied to an XML Web service method controls the recipient of the SOAP header. The Direction property is of type SoapHeaderDirection, which has four values: In, Out, InOut, and Fault. These refer to the recipient (whether it is the XML Web service server), to the client, or both the XML Web service server and client, and whether the SOAP header is sent to the client when an exception is thrown by the XML Web service, respectively.
Note: Version 1.0 of the .NET Framework SDK does not support the Fault value.
To change the SOAP header recipient
- Define the SOAP header.
public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [Visual Basic] Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class
- Add a member variable to the class implementing the XML Web service.
[WebService(Namespace="http://www.contoso.com")] public class MyWebService : WebService { public MyHeader myOutHeader; [Visual Basic] <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits WebService Public myOutHeader As MyHeader
- Apply a SoapHeader attribute to each XML Web service method that processes the SOAP header. Set the Direction property to each intended recipient, using the SoapHeaderDirection enumeration. The following example sets the XML Web service client as the recipient by setting Direction to SoapHeaderDirection.Out.
[WebMethod] [SoapHeader("myOutHeader",Direction=SoapHeaderDirection.Out)] [Visual Basic] <WebMethod, _ SoapHeader("myOutHeader",Direction:=SoapHeaderDirection.Out)>
- Process or set the SOAP header, depending on the recipient. The following code example sets the values of the SOAP header, as the recipient is the XML Web service client.
// Set the Time the SOAP message expires. myOutHeader.Expires = 60000; myOutHeader.Created = DateTime.UtcNow; [Visual Basic] ' Set the Time the SOAP message expires. myOutHeader.Expires = 60000 myOutHeader.Created = DateTime.UtcNow
The following code example defines a MyHeader
SOAP header that is sent from the XML Web service method to the client.
<%@ WebService Language="C#" Class="MyWebService" %> using System; using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService : WebService { public MyHeader myOutHeader; [WebMethod] [SoapHeader("myOutHeader",Direction=SoapHeaderDirection.Out)] public void MyOutHeaderMethod() { // Set the time the SOAP message expires. myOutHeader.Expires = 60000; myOutHeader.Created = DateTime.UtcNow; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits WebService Public myOutHeader As MyHeader <WebMethod, _ SoapHeader("myOutHeader",Direction:=SoapHeaderDirection.Out)> _ Public Sub MyOutHeaderMethod() ' Set the time the SOAP message expires. myOutHeader.Expires = 60000 myOutHeader.Created = DateTime.UtcNow End Sub End Class
Handling Unknown SOAP Headers
An XML Web service client can send a SOAP request with a SOAP header to an XML Web service method that the XML Web service might not have explicitly defined that it was expecting. In this case, it is important to determine whether the semantics of the SOAP header are understood and processed, as the SOAP specification states that an exception is thrown when SOAP headers have a mustUnderstand attribute set to true. For details on handling SOAP headers required by a client, see Handling SOAP Headers Required by an XML Web Service Client.
To handle unknown SOAP headers from an XML Web service client
- Add a member variable to the class implementing the XML Web service with a type of SoapUnknownHeader or SoapHeader, or an array of either, to handle multiple unknown SOAP headers.Declaring the type as either an array or a single instance of SoapUnknownHeader has the added benefit that SoapUnknownHeader has an Element property. The Element property is of type XmlElement and represents the XML document for the Header element of the SOAP request or SOAP response. Thus, an XML Web service method can determine the name of the SOAP header, along with the data passed by the SOAP header, by interrogating the Elementproperty.
public class MyWebService { public SoapUnknownHeader[] unknownHeaders; [Visual Basic] Public Class MyWebService Public unknownHeaders() As SoapUnknownHeader
- Apply a SoapHeader attribute to each XML Web service method that intends to process each unknown SOAP header.
[WebMethod] [SoapHeader("unknownHeaders")] public string MyWebMethod() [Visual Basic] <WebMethod, _ SoapHeader("unknownHeaders") > _ Public Function MyWebMethod() As String
- Add code to determine whether you can process any unknown SOAP headers.If the member variable is of type SoapUnknownHeader, an XML Web service method can determine the name of the SOAP header, along with the data passed by the SOAP header, by interrogating the Element property. The Name property of Elementproperty identifies the name of the SOAP header.
foreach (SoapUnknownHeader header in unknownHeaders) { // Check to see if this a known header. if (header.Element.Name == "MyKnownHeader") [Visual Basic] Dim header As SoapUnknownHeader For Each header In unknownHeaders ' Check to see if this is a known header. If (header.Element.Name = "MyKnownHeader") Then
- Set the DidUnderstand property of the member variable representing the unknown SOAP header to trueif it is known how to process a particular SOAP header.If an XML Web service method does process an unknown SOAP header and does not set the DidUnderstand property to true, a SoapHeaderException can be thrown. For more details, see Handling SOAP Headers Required by an XML Web Service Client
// Check to see if this is a known header. if (header.Element.Name == "MyKnownHeader") header.DidUnderstand = true; else // For those headers that cannot be // processed, set DidUnderstand to false. header.DidUnderstand = false; } [Visual Basic] ' Check to see if this a known header. If (header.Element.Name = "MyKnownHeader") Then header.DidUnderstand = True Else ' For those headers that cannot be ' processed, set DidUnderstand to false. header.DidUnderstand = False End If
Note The DidUnderstand property is used by XML Web services created using ASP.NET to communicate with the XML Web service method. It is not part of the SOAP specification. Its value does not appear in any part of the SOAP request or SOAP response.
Note When an XML Web service client builds a proxy class using the Web Services Description Language Tool (Wsdl.exe) and an XML Web service defines the member variable representing a SOAP header using the SoapUnknownHeader type, no reference to that SOAP header is added to the proxy class. If an XML Web service client decides to add that SOAP header to the SOAP request, they must modify the proxy class by adding a member variable and applying a SoapHeader attribute to the method making the call to the pertinent XML Web service method.
Handling SOAP Headers Required by an XML Web Service Client
A client can require an XML Web service method to interpret the semantics of the SOAP header correctly and process it accordingly for the SOAP request to succeed. To do so, clients set the mustUnderstand attribute of the SOAP header to 1. For instance, the following SOAP request requires the SOAP request recipient to process the MyCustomSoapHeader
SOAP header.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" > <soap:Header> <MyCustomSoapHeader soap:mustUnderstand="1" xmlns="http://www.contoso.com"> <custom>Keith</custom> </MyCustomSoapHeader> </soap:Header> <soap:Body> <MyUnknownHeaders xmlns="http://www.contoso.com" /> </soap:Body> </soap:Envelope>
Whether the XML Web service defines the SOAP header or not determines how the XML Web service should handle SOAP headers required by the client. ASP.NET handles a lot of the work in the case where the XML Web service defines the SOAP header. In the procedure that follows, you can learn how to handle the two cases.
To handle SOAP headers not defined by the XML Web service, but required by an XML Web service client
- Follow the steps for handling unknown SOAP headers from an XML Web service client, paying particular attention to the DidUnderstandproperty of the SOAP header.For SOAP headers not defined by the XML Web service, the initial value of DidUnderstand is false. If ASP.NET detects SOAP headers with their DidUnderstand property set to false after the XML Web service method returns, a SoapHeaderException is automatically thrown.
To handle SOAP headers required by an XML Web service client and defined by the XML Web service
- Follow the steps for processing SOAP headers within an XML Web service created using ASP.NET within each XML Web service method.For SOAP headers defined by the XML Web service and processed in the XML Web service method receiving the SOAP header, ASP.NET assumes the XML Web service understands the SOAP header and sets the initial value of DidUnderstand to true.
The following MyWebService
XML Web service defines the MyHeader
SOAP header and requires it to be sent with any calls to the MyWebMethod
XML Web service method. Additionally, the MyWebMethod
processes any unknown SOAP headers. For the SOAP headers MyWebMethod
can process, DidUnderstand is set to true.
<%@ WebService Language="C#" Class="MyWebService" %> using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader base class. public class MyHeader : SoapHeader { public string MyValue; } public class MyWebService { public MyHeader myHeader; // Receive all SOAP headers other than the MyHeader SOAP header. public SoapUnknownHeader[] unknownHeaders; [WebMethod] [SoapHeader("myHeader")] //Receive any SOAP headers other than MyHeader. [SoapHeader("unknownHeaders")] public string MyWebMethod() { foreach (SoapUnknownHeader header in unknownHeaders) { // Perform some processing on the header. if (header.Element.Name == "MyKnownHeader") header.DidUnderstand = true; else // For those headers that cannot be // processed, set DidUnderstand to false. header.DidUnderstand = false; } return "Hello"; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader base class. Public Class MyHeader : Inherits SoapHeader Public MyValue As String End Class Public Class MyWebService Public myHeader As MyHeader ' Receive all SOAP headers other than the MyHeader SOAP header. Public unknownHeaders() As SoapUnknownHeader <WebMethod, _ SoapHeader("myHeader"), _ SoapHeader("unknownHeaders")> _ Public Function MyWebMethod() As String 'Receive any SOAP headers other than MyHeader. Dim header As SoapUnknownHeader For Each header In unknownHeaders ' Perform some processing on the header. If header.Element.Name = "MyKnownHeader" Then header.DidUnderstand = True ' For those headers that cannot be ' processed, set DidUnderstand to false. Else header.DidUnderstand = False End If Next header Return "Hello" End Function End Class
Note The DidUnderstand property is used by ASP.NET to communicate with the XML Web service method. It is not part of the SOAP specification; its value does not appear in any part of the SOAP request or SOAP response.
If an XML Web service forwards a SOAP header, it is very important to follow the rules in the SOAP specification, especially those pertaining to the value of the Actor. For details, see the W3C Web site (http://www.w3.org/TR/SOAP/).
Handling Errors That Occur While Processing a SOAP Header
When an XML Web service detects an error specific to the processing of a header, a SoapHeaderException should be thrown. Using this exception class allows XML Web services to correctly format the response. If the client is created using the .NET Framework, it will receive the SoapHeaderException with its contents, including the InnerException property, placed in the Message property. The InnerException property of the SoapHeaderException caught by the client will be null. This is a programming model supported by the .NET Framework, as the exception is sent over the network in a SOAP <Fault> XML element, as prescribed by the SOAP specification. For more details on exceptions, see Handling and Throwing Exceptions in XML Web Services.
The following code example throws a SoapHeaderException if a client makes a SOAP request to the MyWebMethod
XML Web service method setting the Expires
property to a date and time that occurs in the past by the time the SOAP request reaches the XML Web service.
<%@ WebService Language="C#" Class="MyWebService" %> using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public DateTime Expires; public DateTime Received; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader myHeaderMemberVariable; // Apply a SoapHeader attribute. [WebMethod] [SoapHeader("myHeaderMemberVariable")] public void MyWebMethod() { if (timeStamp == null) timeStamp = new MyHeader(); else { // Check whether the SOAP message is expired. if ((timeStamp.Expires.CompareTo(DateTime.UtcNow)) <= 0) { // The SOAP message is expired, so throw a SOAP header // exception indicating that. SoapHeaderException se = new SoapHeaderException( "SOAP message expired before reaching this node.", SoapException.ClientFaultCode, this.Context.Request.Url.ToString()); throw se; } } } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As DateTime Public Received As DateTime End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService ' Add a member variable of the type deriving from SoapHeader. Public myHeaderMemberVariable As MyHeader ' Apply a SoapHeader attribute. <WebMethod, _ SoapHeader("myHeaderMemberVariable")> _ Public Sub MyWebMethod() If (TimeStamp Is Nothing) Then TimeStamp = New MyHeader Else ' Check whether the SOAP message is expired. If ((TimeStamp.Expires.CompareTo(DateTime.UtcNow)) <= 0) Then ' The SOAP message is expired, so throw a SOAP header ' exception indicating that. Dim se As New SoapHeaderException( _ "SOAP message expired before reaching this node.", _ SoapException.ClientFaultCode, _ Me.Context.Request.Url.ToString()) Throw se End If End If End Sub End Class
Note: The .NET Framework version 1.0 includes the SoapHeaderAttribute.Required property which enables an XML Web service to require that a client send a specific SOAP header when the property is set to true. ASP.NET indicates that the SOAP header is required in a generated WSDL document by setting the wsdl:required attribute to “true” on the soap:header element. .NET Framework clients of the XML Web service built from the WSDL document receive a SoapHeaderException if they do not send the required SOAP header and other clients receive a SOAP Fault. To interoperate with other SOAP implementations this functionality is removed in later versions.
The Required property is obsolete in version 1.1, and the wsdl:required attribute of a soap:header element in a WSDL document is ignored by the Web Services Description Language tool (Wsdl.exe). Because a SOAP header can no longer be required, an XML Web service should verify that the field or property representing the SOAP header is not null before accessing it.
See Also
SoapHeader | SoapHeaderAttribute | SoapHeaderException | SoapUnknownHeader | Building XML Web Services Using ASP.NET | Building XML Web Service Clients