Advanced ASP.NET Web Services


This section will focus on some of the esoteric areas of web services. We'll cover topics such as integrating with Windows DNA, and shaping the SOAP/XML document exposed by our web services.

Controlling and Shaping the XML

ASP.NET provides several additional attributes (not discussed earlier) that allow you to shape the XML generated by the XML serializer used by ASP.NET. There are two separate types of attributes: those that apply to the XML documents generated by the HTTP-GET and HTTP-POST protocols, and those that apply to SOAP. It is not an error to use the attributes together. The following table lists these attributes, along with a brief description of their purpose:

Attribute

Description

XML Documents: XmlAttribute SOAP Documents: SoapAttribute

Allows you to control the XML attribute representation, or convert an XML element into an attribute

XML Documents: XmlElement SOAP Documents: SoapElement

Allows you to control the XML element representation, or convert an XML attribute into an element

XML Documents: XmlArray SOAP Documents: SoapArray

Allows you to treat elements as an XML array

These attributes allow us to have fine granular control over the shape of the XML document used as part of the HTTP-GET, HTTP-POST, or SOAP responses. These attributes are very straightforward, and are most often used when you return an instance of a class. Returning classes have not been discussed yet, so a brief example is necessary. Consider a simple ASP.NET Web service ( Books.asmx ) that returns a Books class:

  <%@ WebService Class="ReturnBooks" %>   Imports System.Web.Services   Public Class ReturnBooks   <WebMethod()> Public Function GetBooks() As Books   Dim b As New Books   b.Title = "Professional ASP.NET"   b.Price = 59.99   b.Description = "This book covers Microsoft's ASP.NET technology " & _   "for building Web Applications"   ReDim b.Authors(5)   b.Authors(0) = "Alex Homer"   b.Authors(1) = "David Sussman"   b.Authors(2) = "Rob Howard"   b.Authors(3) = "Brian Francis"   b.Authors(4) = "Rich Anderson"   b.Authors(5) = "Karli Watson"   Return b   End Function   End Class     Public Class Books   Public Title As String   Public Description As String   Public Price As Double   Public Authors() As String   End Class  

Calls made to the GetBooks WebMethod will return an XML document with a root node of <Book> , and elements within <Book> , such as <Authors> , <Title> , <Price> , and so on, for each of our classes members . Figure 19-17 shows an XML document returned from an HTTP-GET request:

click to expand
Figure 19-17:

To change the shape of the XML document “ say by returning the title as an attribute of Books, and renaming the <Price> element to <DiscountPrice> “ use the XmlAttribute and XmlElement attributes. To influence the SOAP message, you need to add the SOAP equivalent attributes. Two changes have to be made to the Books class. First, add the System.Xml.Serialization namespace, as it contains both the XmlAttribute and XmlElement attributes. Second, add the attributes to the Books class member variables you want them applied to ( Books2.asmx ):

 <%@ WebService Class="ReturnBooks" %> Imports System.Web.Services  Imports System.Xml.Serialization  Public Class ReturnBooks    <WebMethod()> Public Function GetBooks() As Books       Dim b As New Books       b.Title = "Professional ASP.NET"       b.Price = 59.99       b.Description = "This book covers Microsoft's ASP.NET technology " & _                       "for building Web Applications"       ReDim b.Authors(5)       b.Authors(0) = "Alex Homer"       b.Authors(1) = "David Sussman"       b.Authors(2) = "Rob Howard"       b.Authors(3) = "Brian Francis"       b.Authors(4) = "Rich Anderson"       b.Authors(5) = "Karli Watson"       Return b    End Function End Class Public Class Books  <XmlAttribute> Public Title As String  Public Description As String  <XmlElement("DiscountedPrice")> Public Price As Double   <XmlArray("Contributors")> Public Authors() As String  End Class 

All of these attributes allow you to rename either the attribute or the element, as shown in the modification of Price to DiscountedPrice and the renaming of the Authors array from Authors to Contributors . Figure 19-18 shows the new XML document:

click to expand
Figure 19-18:

Modifying the Web Service Help Page

The default web service Help page is the template used for all ASP.NET Web services when a request is made through the browser to a particular web service. Chapter 16 (ASP.NET Configuration) discussed how each application could support its own web service “ it's simply a configuration option to tell the application which ASP.NET page to use. Since the web service Help page is implemented as an ASP.NET page, it can be modified. For example, the page can be customized with graphics specific to the application, or provide additional details about the web services that the server provides.

Remember that any changes to the server's DefaultWsdlHelpGenerator.aspx will apply to all ASP.NET Web services on that server, unless you alter the ASP.NET configuration. However, there are some changes that can be made to this file, which will be useful in debugging the ASP.NET Web service.

HTML Form (Post Support)

If an ASP.NET Web service is capable of supporting the HTTP-POST protocol, and that functionality needs to be tested , DefaultWsdlHelpGenerator.aspx can be opened and modifications be made to the showPost flag:

 // set this to true if you want to see a // POST test form instead of a GET test form bool showPost = false; 

By default, this flag is set to false , but when set to true it will generate another HTML form available on the detail page for a particular WebMethod supporting HTTP-POST.

Protocol Request/Response Sample

When you drill into a particular WebMethod detail page, you are provided with a view of what the protocol request and response messages should look like. Within DefaultWsdlHelpGenerator.aspx , there are three flags that can be altered to change how these protocol messages are displayed:

Flag

Default Value

Description

dontFilterXml

false

By default, the XML shown in protocol messages is not URL-encoded. If the flag is set to true , you can view the URL encoded XML in the message.

maxObjectGraphDepth

4

This setting allows you to control the depth objects to show. This would be applicable for the Books class if it contained a public member Authors that was another class, and Authors contained a public member which was another class, and so on.

maxArraySize

2

This option allows you to control the maximum number of array element examples shown within the protocols. For example, the Books class contained an array of six authors. The array representing these items in the protocol samples would, by default, only show two items.

Next , let's look at one of the features of SOAP headers, which can be used to send out-of- band information.

SOAP Headers

The use of headers is supported only within the SOAP protocol, and not HTTP-GET or HTTP-POST. ASP.NET Web services that are created using SOAP as the default protocol for application-to-application communication. For example, consider the SOAP response to a call to the Fibonacci Web service:

  <?xml version="1.0"?>   <soap:Envelope xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"   xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">   <soap:Body>   <GetSeqNumber xmlns="http://tempuri.org/">   <FibIndex>6</FibIndex>   </GetSeqNumber>   </soap:Body>   </soap:Envelope>  

The HTTP headers have been stripped out, and what remains is the body of an HTTP request containing the SOAP message. The SOAP message contains an envelope ( <soap:Envelope ...> ) that encapsulates a body ( <soap:Body> ) and optional headers ( <soap:Headers> ). To use SOAP headers, you need to specify a SoapHeader attribute on the Web-callable method or property.

The SoapHeader attribute allows you to optionally set a SOAP header, on the consumer or provider of the service. SOAP does not define headers for you: they are simply an extensibility mechanism that can be used in your ASP.NET Web services.

For example, consider the following SOAP message for the Fibonacci example along with a simple header:

 <?xml version="1.0"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"                xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"                xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">  <soap:Header>   <SimpleSoapHeader xmlns="http://tempuri.org/">   <value>string</value>   </SimpleSoapHeader>   </soap:Header>  <soap:Body>       <GetSeqNumber xmlns="http://tempuri.org/">          <FibIndex>int</FibIndex>       </GetSeqNumber>    </soap:Body> </soap:Envelope> 

To use SOAP headers, it is necessary to create a class that inherits from the SoapHeader base class. In the following code, both a SoapHeader attribute and the SoapHeader class will be used. They are two separate classes “ it's just that with attributes it's not necessary to explicitly add Attribute onto the end of the attribute on declaration (as SoapHeaderAttribute ).

The SoapHeader Class

To make use of a SOAP header, you need to create a class that derives from SoapHeader , which can be found in the System.Web.Services.Protocols namespace:

  public abstract class SoapHeader{   public bool MustUnderstand{get; set;}   public string Actor{get; set;}   public bool DidUnderstand{get; set;}   }  

Here's a simple example of a class that inherits from SoapHeader (written in VB.NET):

  Imports System.Web.Services.Protocols     Public Class SimpleSoapHeader   Inherits SoapHeader   Public value As string   End Class  

Within this class is defined a single public member, value . Applications that wish to use this SOAP header can pass data within value .

Let's add this class to the Fibonacci example ( FibonnaciSOAP.asmx ):

 <%@ WebService class="Fibonacci"%>      Imports System.Web.Services  Imports System.Web.Services.Protocols     Public Class SimpleSoapHeader   Inherits SoapHeader     Public value As string   End Class  Public Class Fibonacci  Public simpleHeader As SimpleSoapHeader     <WebMethod, SoapHeader("simpleHeader")> Public Function _   GetSeqNumber (fibIndex as Integer) as Integer  If (fibIndex < 2) Then          Return fibIndex       End If            Dim FibArray(2) As Integer       Dim i As Integer            FibArray(0) = 0       FibArray(1) = 1            For i = 2 To fibIndex          FibArray(1) = FibArray(1) + FibArray(0)          FibArray(0) = FibArray(1) - FibArray(0)       Next            Return FibArray(1)    End Function End Class 

This cannot be tested in the same way as the earlier examples “ you'll see why.later.

In this modified Fibonacci class, we declared a local member variable simpleHeader , of type SimpleSoapHeader :

 Public simpleHeader As SimpleSoapHeader 

This represents an instance of the custom SOAP header that a client will set. Next, we used the SoapHeader attribute, which has been added to GetSeqNumber , and passed in the name of the member variable, simpleHeader :

 <WebMethod, SoapHeader("simpleHeader")> Public Function _                            GetSeqNumber (fibIndex as Integer) as Integer 

Setting the SoapHeader attribute to simpleHeader creates a SOAP header containing a single item (named value ) that you can set, as defined in the SimpleSoapHeader class. When we created the SimpleSoapHeader class, the class inherited from the SoapHeader class. Let's take a look at the inherited properties the class receives.

Properties Inherited from SoapHeader

The SoapHeader class provides three additional properties. We won't discuss them in detail, but you can review the SOAP 1.2 specification (http://www.w3.org/TR/soap12-part1/) to learn more about why they exist. The properties are:

  • Actor : Section 5.2.2 of the SOAP 1.2 specification states that a role header message may be used by a SOAP document to name the intended recipient, as a SOAP message can pass through many applications capable of routing the message. The Actor property allows you to set the URI value “ the endpoint that the SOAP message is ultimately going to be routed to. Alternatively, you can set a special URI “ http://www.w3.org/2003/05/soap-envelope/role/next as defined by the SOAP 1.2 specification “ that indicates that the next recipient of the SOAP message should process the message.

    Note

    Note that the SOAP 1.1 defines the SOAP header attribute as Actor , but this has been renamed to Role . The SoapHeader property will remain as Actor for backward-compatibility.

  • mustUnderstand : Section 5.2.3 of the SOAP 1.2 specification states that a SOAP header can use an attribute, mustUnderstand , to indicate whether it is mandatory or optional for a recipient to process the header entry. This value is set to false by default.

  • DidUnderstand : A Boolean flag that the receiver of the SOAP message may set if the SOAP header was understood .

When we applied the SoapHeader attribute, we set a value that represents a property of a SoapHeader attribute called MemberName . Let's take a look at MemberName and the other properties supported by the SoapHeader attribute.

The SoapHeader Attribute

The SoapHeader attribute is the attribute added to Web-callable methods or properties to instruct those methods and properties to support SOAP headers. You've already seen that to use a SOAP header, you need to create a class that inherits from the SoapHeader base class. After this, you expose a member variable whose type is that of your class (which inherits from SoapHeader ).

Consumers of your web service use the member variable to create an instance of your class and to set values. The SoapHeader attribute is provided with the name of this class “ for example, <SoapHeader("simpleHeader")> “ and is thus able to access the class instance. This constructor sets the MemberName property of the SoapHeader attribute.

The SoapHeader attribute supports three properties:

  • MemberName

  • Direction

  • Required

The MemberName Property

The MemberName property identifies the name of the member (within the class) for which the header is to be created. This is best demonstrated by revisiting the example code:

 public simpleHeader As SimpleSoapHeader      <WebMethod, SoapHeader("simpleHeader")> public Function                            GetSeqNumber (FibIndex as Integer) as Integer 

simpleHeader is a variable of type SimpleSoapHeader (which is the class that inherits from the SoapHeader base class).

Next, you see the SoapHeader attribute and the value passed in its constructor “ the name of the SimpleSoapHeader variable, simpleHeader . simpleHeader is the name of the member that represents the SimpleSoapHeader class. When we discuss consuming web services in the next chapter, you'll see how the consumer can create an instance of SimpleSoapHeader , set its value property, and assign that instance to simpleHeader .

In a nutshell , the MemberName property allows the SoapHeader attribute to name the class variable that it will be a type of.

The Direction Property

SOAP headers are, by default, inbound only; the server servicing SOAP requests expects to receive SOAP headers, but not to set or send SOAP headers. This becomes apparent if you try to test the example (the Fibonacci Web service with a simple SOAP header, shown in Figure 19-19) using the web service's Help page. The HTML form for testing the results is no longer available:

click to expand
Figure 19-19:

The Direction property allows this to be configured. This property uses the SoapHeaderDirection enumeration to determine the direction of the header. Using VB.NET, you could write:

  <SoapHeader("simpleHeader", Direction:=SoapHeaderDirection.InOut)>  

Using C#, you could write:

  [SoapHeader("simpleHeader", Direction=SoapHeaderDirection.InOut)]  

The SoapHeaderDirection enumeration supports three values. Their names describe their use:

  • SoapHeaderDirection.In

  • SoapHeaderDirection.Out

  • SoapHeaderDirection.InOut

The Required Property

Headers defined by a method are required by default, which means that if they are not present in the request, an exception will be generated. Setting the Required property to false allows headers to be optional. Using VB.NET, you would write:

  <SoapHeader("simpleHeader", Required:="false")>  

Using C#, you would write:

  [SoapHeader("simpleHeader", Required="false")]  



Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

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