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 Class="ExceptionExample" %>     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:

click to expand
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:

click to expand
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 Class="UsingSoapHeaders" %>     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.




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