If you build and use the proxy class in Visual Studio .NET, you can see (through statement completion) that the class contains additional methods and properties beyond the methods used in the web service. For example, the
Fibonacci class supported a
GetSeqNumber method. However, if you examine the proxy for
Fibonacci in Visual Studio .NET, you'll see several other methods and properties that
Fibonacci supports. This is because the
Fibonacci proxy class inherits these methods and properties from a base class.
Note |
A proxy inherits from SoapHttpClientProtocol , which inherits from HttpWebClientProtocol , which in turn inherits from WebClientProtocol . |
Let's examine some of the common methods and properties we might use.
We still need to write applications so that they behave correctly when the web service is not performing correctly. For example, the network connection between the provider and the consumer of the service could become saturated so that responses start to take too long. Requests are issued, and the consumer of the service simply waits until the request times out. The default timeout for a request from our proxy is ninety seconds.
The following VB.NET code illustrates a simple
Add Web service that performs slowly due to a call to
Thread.Sleep(20000) that forces the thread to wait 20 seconds before continuing:
<%@ WebService Class="Timeout" %>
Imports System.Threading
Imports System.Web.Services
Public Class Timeout
<WebMethod()> Public Function Add(a As Integer, b As Integer) As Integer
Thread.Sleep(20000)
Return a + b
End Function
End Class
This code introduces false latency into the application. However, if this latency were real, the client using the web service would probably not want to wait 20 seconds for a response.
One of the inherited properties in the proxy class is
Timeout . If you use a proxy named
Timeout for the
Add Web service, you could write the following VB.NET code to time the request out if the web service did not respond within five seconds:
<Script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim example As New Timeout()
example.Timeout = 5000
Try
lblResult.Text = example.Add(4,5)
Catch err As Exception
lblResult.Text = err.Message
End Try
End Sub
</Script>
The result of 4 + 5 is: <asp:label id="lblResult" runat="server" />
This code demonstrates the use of a
Try...Catch block surrounding a web service call. We'll talk more about handling web service exceptions later in the chapter. A timeout is an exception, and if it's not handled, an error will be generated.
Using the
Timeout property of the proxy ensures that the application won't wait for a slow web service. Another inherited property of the proxy,
Url , allows you to set the end-point URL that the proxy sends requests to.
When you build a proxy from a WSDL document generated by ASP.NET, the default end-point of the service is already provided. Here's a snippet of the WSDL for the Fibonacci Web service:
<service name="Fibonacci"> <port name="FibonacciSoap" binding="s0:FibonacciSoap"><soap:address location="http:// ... /Fibonacci_cs.asmx" /> </port> </service>
The
location attribute defined in
<soap:address/> names the end-point to which SOAP calls are sent. The proxy that is generated uses this setting. As an example, consider the constructor of the VB.NET code:
Public Sub New() MyBase.NewMe.Url = "http://localhost/WebServices/Fibonacci_cs.asmx" End Sub
The equivalent C# code:
public Fibonacci() {this.Url = "http://localhost/WebServices/Fibonacci_cs.asmx"; }
Both constructors set the
Url property to the value of
location in the WSDL. Although the value is 'pre-configured' for you in the proxy, you can either remove this setting or reset the value of the property at runtime using the
As you can reset the
Url that the proxy uses, you can dynamically choose the web service you want to use, or use a common proxy for multiple web services. For example, if you built an e-commerce site and wanted to use web services for credit card validation, you could use the
Timeout and the
Url properties together. If a given call to a service timed out (for example, a call to a Credit Card Web service), you could write code that changes the
Url to a web service provided by another vendor and call that backup service. Of course, this assumes that either the proxy supports all these services, or all the services implement a common web service API.
By default the web service proxy will use the settings configured for Internet Explorer to access the Internet. However, you can set your own proxy using the
Proxy property.
To use the
Proxy property, you need to set its value to a class that implements
IWebProxy , such as the
WebProxy class found in the
System.Net namespace. For example, if the local network requires you to use a proxy server named
AcmeCoProxy through port 80, you could write the following VB.NET code:
<%@ Import Namespace="System.Net" %> <Script runat="server"> Private Sub Page_Load(sender As Object, e As EventArgs)
Dim fibonacci As New Fibonacci()
Dim webProxy As New WebProxy("AcmeCoProxy", 80)
Fibonacci.Proxy = webProxy
lblResult.Text = fibonacci.GetSeqNumber(6) End Sub The value of the 6th element in the Fibonacci series is: <asp:label id="lblResult" runat="server"/>
Calls made through the
Fibonacci proxy object are now routed to the
AcmeCoProxy server on port 80. The Web proxy server then issues the request and returns the result to the caller. If the Web proxy server requires credentials, these can be set as part of the
System.Net.WebProxy class.
ASP.NET Web services use HTTP as the transport protocol for messages. Additional transport protocols can be used to route SOAP, including SMTP and UDP, but HTTP will be the most commonly used protocol. Accordingly, the proxy provides with access to common HTTP protocol features, such as cookies.
Just as you would with a browser-based application, you can use HTTP cookies to pass additional data along with SOAP messages. The most common use of cookies in an ASP.NET Web service would be to maintain a
Session on the server that is providing the web service. For example, the following web service (written using VB.NET) uses
Session state to retain values on the server:
<%@ WebService Class="SessionStateExample" %>
Imports System.Web.Services
Public Class SessionStateExample
Inherits WebService
<WebMethod(EnableSession:=true)> _
Public Function SetSession(key As String, item As String)
Session(key) = item
End Function
<WebMethod(EnableSession:=true)> _
Public Function GetSession(key As String) As String
Return Session(key)
End Function
End Class
This ASP.NET Web service has two functions defined as web services:
SetSession : Allows you to pass a key and item (both strings) and uses the key value to create an entry in
Session for the value
GetSession : Allows you to pass the key and retrieve the result of the item stored for that key
The
WebMethod attribute explicitly enables Session (which is not enabled, by default) by setting
EnableSession:="true" for each of the methods. The server will issue a Session cookie to the caller that contains a unique
Session ID. On each subsequent request, the caller (in this case the web service proxy) presents the cookie, and the server is able to load the appropriate
Session data.
There are two caveats for using HTTP cookies with the proxy:
If you create a proxy for a web service, and the web service requires the use of HTTP cookies, you need to explicitly support HTTP cookies within our proxy. This is done by creating an instance of a
CookieContainer class and assigning that instance to the proxy's
CookieContainer property.
If you intend to maintain state through the use of ASP.NET session state within the web service, you need to re-present the HTTP cookie on each subsequent use of the proxy by your application. The
Cookie that the proxy receives is only valid for the life of the proxy. When the proxy instance goes out of scope or is destroyed, the cookie is lost and on subsequent requests you no longer have access to the Session (since you no longer have the Session cookie to send to the server).
The following VB.NET code illustrates both these caveats:
<Script runat="Server"> Public Sub Page_Load(sender As Object, e As EventArgs)Dim sessionExample As New SessionStateExample()
sessionExample.SetSession("name", "rob")
lblSession1.Text = sessionExample.GetSession("name") End Sub </Script> <Font face="arial"> Value: <asp:label id="lblSession1" runat="server"/> </Font>
In the
Page_Load event handler, we create an instance of
SessionStateExample and create a new Session on the web service by calling
SetSession . We then retrieve the value by calling
GetSession("name") . In this case, no value is returned, because the proxy is not using HTTP cookies and so
lblSession1 would not contain a value.
To enable cookie support within the web service proxy, you need to create a
CookieContainer . Here is the fixed VB.NET code:
<%@ Import Namespace="System.Net" %> <Script runat="Server"> Public Sub Page_Load(sender As Object, e As EventArgs) Dim sessionExample As New SessionStateExample()
Dim cookieContainer As New CookieContainer()
sessionExample.CookieContainer = cookieContainer sessionExample.SetSession("name", "rob") lblSession1.Text = sessionExample.GetSession("name") End Sub </Script> <Font face="arial"> Value: <asp:label id="lblSession1" runat="server"/> </Font>
Here, we first import the
System.Net namespace, which contains the necessary
CookieContainer class. Then, within the
Page_Load event handler we add two lines of code to create an instance of the
CookieContainer class and set that instance to the
CookieContainer property of the web service proxy. When this code is executed, we get the desired result. The
GetSession call returns the value set by
SetSession .
Although this is a simple example, it effectively illustrates how to maintain state through the use of an HTTP cookie using a web service proxy. Let's go one step further.
Since the proxy does not persist the Session cookie, to use Session state in your web service across multiple requests, you'd need to do your own cookie persistence. Take the following VB.NET example:
<%@ Import Namespace="System.Net" %> <script runat="server"> Public Sub Page_Load(sender As Object, e As EventArgs) Dim sessionExample As New SessionStateExample() Dim cookieContainer As New CookieContainer()Dim sessionCookie As Cookie
Dim cookieCollection As New CookieCollection() sessionExample.CookieContainer = cookieContainer
sessionCookie = CType(session("sessionCookie"), Cookie)
If (IsNothing(sessionCookie)) Then
sessionExample.SetSession("name", "rob")
cookieCollection = sessionExample.CookieContainer.GetCookies( _
New Uri("http://localhost"))
Session("sessionCookie") = cookieCollection("ASP.NET_SessionId")
Else
sessionExample.CookieContainer.Add(sessionCookie)
End If lblSession1.Text = sessionExample.GetSession("name") End Sub </script> <Font face="arial"> Value: <asp:label id="lblSession1" runat="server"/> </Font>
This is a more advanced example that demonstrates how you can store the web service's Session cookie in Session state with the web application that is using the web service. The code uses two new local variables,
sessionCookie and
cookieCollection , to store the web service's Session cookie.
The code tries to retrieve a value for
sessionCookie by attempting to access a local Session variable. The code then determines if
sessionCookie references an instance of a
Cookie . If it does not, it walks through the procedure of calling the proxy's
SetSession method and then stores the web service's Session cookie. Alternatively, you could simply add the
sessionCookie to the existing proxy's
CookieContainer and call the
GetSession method. We've encapsulated all of this work in one ASP.NET page, but it could just as easily be applied to an entire web application, which would allow us to use ASP.NET Session state for web services across an application.
Let's look at another feature that ASP.NET Web services make easy – converting any web site into a web service.