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








  • Design Decisions

    Just as there are design decisions to be made when you build a web service, there are design decisions related to how to use a web service. One of the most obvious is handling exceptions.


    SOAP Exceptions


    In an ideal scenario, whenever you call a web service, some type of application logic is executed performing the desired task according to the request. However, code often has bugs. SOAP takes this fact into account and defines the response that a web service should use when an error occurs. This error takes the form of a SOAP message, and it is known as a SOAP Exception.

    Requests to ASP.NET Web services that generate an exception will return a SOAP exception. Within the System.Web.Services.Protocols namespace is a class named SoapException. Clients using .NET can wrap try...catch blocks around calls to web services and catch SOAP Exceptions as instances of a SoapException class. Let's look at an example. The following is a simple web service (written using VB.NET) that can generate a runtime 'divide by zero' error:


    <%@ WebService %>

    Imports System.Web.Services

    Public Class ExceptionExample
    <WebMethod()> Public Function Divide(a As Integer, b As Integer) As Integer
    Return a / b
    End Function
    End Class

    Using Visual Studio .NET or wsdl.exe, you can build a proxy class. Let's name it ExceptionExample, deploy it to a web application's bin directory, and call the ExceptionExample Web service. Using VB.NET, you could write:


    <Script runat="server">
    Public Sub Page_Load(sender As Object, e As EventArgs)
    Dim example As New ExceptionExample()

    lblDiv1.Text = example.Divide(6,2)
    lblDiv2.Text = example.Divide(5,0)
    End Sub
    </Script>
    The result of 6 divided by 2 is: <asp:label id="lblDiv1" runat="server" />
    <br>
    The result of 5 divided by 0 is: <asp:label id="lblDiv2" runat="server" />

    If you execute this code, the statement example.Divide(6,2) is valid, and should execute. However, the statement example.Divide(5,0) results in a divide-by-zero error. Figure 20-8 the result:


    Figure 20-8:

    The code raises an unhandled exception on line 6 in our call to Divide(5,0). The exception that is bubbled up and displayed in the ASP.NET error page is of type SoapException. Let's make a few modifications to the code to handle this exception:


    <%@ Import Namespace="System.Web.Services.Protocols" %>

    <Script runat="server">
    Public Sub Page_Load(sender As Object, e As EventArgs)
    Dim example As New ExceptionExample()

    Try
    lblDiv1.Text = example.Divide(6,2)
    Catch err As SoapException
    lblDiv1.Text = "Unable to compute..."
    End Try

    Try
    lblDiv2.Text = example.Divide(5,0)
    Catch err As SoapException
    lblDiv2.Text = "Unable to compute..."
    End Try

    End Sub
    </Script>
    The result of 6 divided by 2 is: <asp:label id="lblDiv1" runat="server" />
    <br>
    The result of 5 divided by 0 is: <asp:label id="lblDiv2" runat="server" />

    Unlike an ASP/VBScript combination, ASP.NET supports structured error-handling (so no more On Error Resume Next) thanks to the CLR. In our code we've made a few modifications to catch exceptions: we've added a namespace, System.Web.Services.Protocols, which contains the SoapException class and have added try...catch blocks around the code. Now, if an exception of type SoapException occurs, we can catch the exception and display a meaningful result.

    When you run the modified code, you get the following result, as shown in Figure 20-9:


    Figure 20-9:

    Another design decision is whether to use SOAP headers to send additional data with the web service. In the previous chapter, we examined how to support SOAP headers on the server. Now, let's look at how to use SOAP headers with the proxy.


    Using SOAP Headers


    The following is a simple ASP.NET Web service (written in VB.NET) that implements a SOAP header:


    <%@ WebService %>

    Imports System.Web.Services
    Imports System.Web.Services.Protocols

    Public Class MySoapHeader : Inherits SoapHeader
    Public Value As String
    End Class

    Public Class UsingSoapHeaders
    Public sHeader As MySoapHeader
    <WebMethod(), SoapHeader("sHeader")> _
    Public Function GetValueOfSoapHeader() As String
    Return sHeader.Value
    End Function
    End Class

    Here, GetValueOfSoapHeader returns the value of the SOAP header that the caller presents.

    Described in WSDL


    The information for SimpleSoapHeader is described in the WSDL for the service, as the application using the web service will require knowledge of the SoapHeader, in order to call the service:


    <s:element name="MySoapHeader" nillable="true" type="s0:MySoapHeader" />
    <s:complexType name="MySoapHeader">
    <s:sequence>
    <s:element minOccurs="1"
    maxOccurs="1"
    name="Value"
    nillable="true"
    type="s:string" />
    </s:sequence>
    </s:complexType>


    This WSDL uses an XML Schema to define a SOAP header, MySoapHeader. The proxy generator (Visual Studio .NET or wsdl.exe) will then create a class MySoapHeader with a single member variable Value.

    SOAP Header Proxy


    The following is the VB.NET code generated by Visual Studio .NET for the WSDL preceding the web service:

    Namespace Simple
    <WebServiceBindingAttribute(Name:="UsingSoapHeadersSoap")
    [Namespace]:="http://tempuri.org/")>
    Public Class UsingSoapHeaders
    Inherits SoapHttpClientProtocol
    Public MySoapHeaderValue As MySoapHeader
    Public Sub New()
    MyBase.New
    Me.Url = "http://localhost/.../SoapHeaders_vb.asmx"
    End Sub
    <SoapHeaderAttribute("MySoapHeaderValue")> _
    <SoapDocumentMethodAttribute("http://tempuri.org/GetValueOfSoapHeader",
    Use:=SoapBindingUse.Literal,
    ParameterStyle:= SoapParameterStyle.Wrapped)>
    Public Function GetValueOfSoapHeader() As String
    Dim results() As Object = Me.Invoke("GetValueOfSoapHeader", _
    New Object(0) {})
    Return CType(results(0),String)
    End Function
    End Class
    <XmlRootAttribute([Namespace]:="http://tempuri.org/", IsNullable:=true)>
    Public Class MySoapHeader
    Inherits SoapHeader

    Public Value As String
    End Class
    End Namespace

    The proxy class contains a MySoapHeader subclass, which has a member variable, Value. The proxy class also contains a member variable, MySoapHeaderValue, which is used to set the SOAP header.

    Using the SOAP Header


    Let's look at how to use this proxy, along with its SOAP header to send additional data with the web service request. The following is a simple ASP.NET page (written in VB.NET) that uses the proxy:


    <%@ Import Namespace="Simple" %>

    <script runat="server">
    Public Sub Page_Load(sender As Object, e As EventArgs)
    ' Create a new instance of the UsingSoapHeaders
    ' proxy class used to call the remote .asmx file
    Dim soapHeaderExample As New UsingSoapHeaders()

    ' Create a new instance of the mySoapHeader class
    Dim myHeader As New MySoapHeader()

    ' Set the value of myHeader
    myHeader.Value = "Sample Header Text"

    ' Set the MySoapHeader public member of the
    ' UsingSoapHeaders class to myHeader
    soapHeaderExample.MySoapHeaderValue = myHeader

    ' Get the result of the call
    Dim result As String
    result = soapHeaderExample.GetValueOfSoapHeader()
    span1.InnerHtml = result
    End Sub
    </script>
    <font size=6>The value of the SOAP header is: <font color="red">
    <span id="span1" runat="server"/></font></font>

    In the Page_Load event handler, we create a new instance of the web service proxy, soapHeaderExample. We also create an instance of MySoapHeader that represents the SOAP header (myHeader). The Value field of myHeader is set to Sample Header Text.

    Next, we set myHeader to the soapHeaderExample member variable MySoapHeaderValue. Finally, we call the GetValueOfSoapHeader Web service. The MySoapHeader class instance myHeader is serialized as a SOAP header for the message and is sent along with the request. When the call completes, the value that was sent as a SOAP header is displayed.

    Using SOAP headers is easy. The WSDL of the service describes what the SOAP header is, and the proxy generation tool turns the XML description found in the WSDL into a .NET class that you can program with. SOAP headers are very powerful since they allow you to pass out-of-band data (data that is part of the request, but doesn't belong as part of the method marked as a web service). For example, to send a user ID with each request, you obviously wouldn't want to design each of the methods in the web service to accept that user ID as a parameter. It would be much easier to simply make use of a SOAP header.

    This example is relatively simple, but it's enough to allow us to demonstrate how we could build some meaningful applications that use SOAP headers. Later, you'll see a real-world example of how to use SOAP headers. Specifically, you'll see how you can use SOAP headers to send authentication details with each request. Using SOAP headers for authentication is obviously a custom implementation of authentication and authorization, and so you should start by reviewing the security features that are already available.

  • / 243