Professional ASP.NET 1.1 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Professional ASP.NET 1.1 [Electronic resources] - نسخه متنی

Alex Homeret

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






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:


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:


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:


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")]


/ 244