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

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

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

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

Alex Homeret

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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


"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">








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

  • / 243