Most Web service calls today are done using a Simple Object Access Protocol (SOAP) envelope within the body of a Hypertext Transfer Protocol (HTTP) POST request. Clients and proxy servers cannot intelligently interpret SOAP requests , so they will not automatically instate HTTP caching for Web service responses. (They can do so for regular POST responses, unless the origin server explicitly forbids downstream caching.) The good news is that caching is extremely simple to implement in Web services.
The WebService() attribute class provides a property called CacheDuration , which specifies the number of seconds that a response should be cached. The Web service cache automatically varies by request, and it is always stored on the origin server. The CacheDuration property sets an absolute expiration policy on cached responses by adding the specified duration to the timestamp of the initial. As with any kind of caching, the Web service cache is not guaranteed to persist responses indefinitely. However, unlike with page-level caching, you do not need to write special code in the client for handling this outcome. The Web service takes care of interpreting its own cache contents and will service a request using the cache if it can. Otherwise, it will automatically regenerate the response.
The following code illustrates a Web service method that returns the timestamp of the current HTTP request. The GetDateTimeStamp() method accepts a string argument in order to illustrate how the cache stores multiple versions of the response for varying requests. The Web service implements a 60-second cache policy:
<WebMethod(CacheDuration:=60)> Public Function GetDateTimeStamp(_ ByVal strUser As String) As String Return (Me.Context.Timestamp.ToLongTimeString.ToString()) End Function
Web services will not cache responses if they are compiled within a Web application project, so you should compile this Web service as a stand-alone project. This Web service is compiled from the ApressWS1 project, which is included with the sample code for this chapter. The Web service filename is apNorthwind.asmx .
Once you have compiled the Web service, you can then invoke the GetDateTimeStamp() method using a proxy browser interface, as shown in Figure 5-6.
The method returns the following SOAP output:
<?xml version="1.0" encoding=" utf-8" ?> <string xmlns=" http://tempuri.org/">2:47:51 PM</string>
The return timestamp will continue to read 2:47:51 P.M. for 60 seconds following the initial request, as long as the strUser argument value remains the same. If the value changes, then the Web service will return a different cached response with an alternate timestamp. The following are some sample responses:
2:47:51 PM {Invoke button was clicked at 2:47:51 PM; strUser = jeff} 2:47:51 PM {Invoke button was clicked at 2:48:21 PM; strUser = jeff} 2:48:31 PM {Invoke button was clicked at 2:48:31 PM; strUser = ken} 2:47:51 PM {Invoke button was clicked at 2:48:41 PM; strUser = jeff} 2:48:31 PM {Invoke button was clicked at 2:48:51 PM; strUser = ken}
Listing 5-12 illustrates a Web service method that generates a DataSet and implements a 60-second cache policy.
<WebMethod(CacheDuration:=60)> Public Function GenerateDataSet(_ ByVal BeginningDate As Date, ByVal EndingDate As Date) As DataSet Dim sqlDS As DataSet Dim strConn As String Dim arrParams() As String Dim objDB As Apress.Database Try ' Step 1: Retrieve the connection string from Web.config strConn = ConfigurationSettings.AppSettings("ConnectionString") ' Step 2: Instance a new Database object objDB = New Apress.Database(strConn) ' Step 3: Execute [Employee Sales By Country] arrParams = New String() {"@Beginning_Date", BeginningDate, _ "@Ending_Date", EndingDate} sqlDS = objDB.RunQueryReturnDS("[Employee Sales By Country]", _ arrParams) Catch err As Exception ' Implement error-handling code here Finally End Try Return (sqlDS) End Function
This Web service is also compiled in the ApressWS1 project. The Web service manages its own cache and ensures that a response will be delivered to the Web client page, whether or not the response originates from the cache. The client does not need to check for the existence of a response.
The sample project AspNetChap5B contains a Web page, ap_OutputCache3.aspx , that is a client for the ApressWS1 Web service. The client application must first set a dynamic Web reference to the Web service. Follow these steps:
Compile the ApressWS1 project.
Switch over to the AspNetChap5B project. In Solution Explorer, right-click the project file and select Add Web Reference from the pop-up menu.
In the dialog box, type in the Uniform Resource Indicator (URI) for the Web service ”for example: http://localhost/ApressWS1/apNorthwind.asmx .
The contract details will appear in the left pane of the dialog box.
Click the Add Reference button.
In Solution Explorer, open the properties page for the Web reference.
Change the URL behavior from Static to Dynamic. This adds the URI to the Web.config file.
This is the URI that gets added to a new application setting in the Web.config file:
<appSettings> <add key=" AspNetChap5B.localhost.Service1" value=" http://localhost/ApressWS1/apNorthwind.asmx"/> </appSettings>
The Web client calls the GenerateDataSet() Web service method as shown in Listing 5-13.
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim sqlDS As DataSet Dim objWS As localhost.Service1 Try ' Step 1: Generate the DataSet, using a Web Service call objWS = New localhost.Service1() objWS.Url = ConfigurationSettings.AppSettings( _ "AspNetChap5B.localhost.Service1") sqlDS = objWS.GenerateDataSet(Me.ap_txt_beginning_date.Text, _ Me.ap_txt_ending_date.Text) ' Step 2: Bind the DataSet to the DataGrid BindDataGrid(sqlDS) Catch err As Exception Response.Write(err.Message) Finally sqlDS = Nothing End Try End Sub
As with the previous example, the GenerateDataSet() Web service method will cache responses for 60 seconds and will vary the cache based on the request. Users who request the same date range will receive the same cached response.
Note | You should be careful in deciding whether to implement Web service caching simply because you have so little control over the behavior of the cache. You should not implement caching in Web services that handle widely varying requests and that consistently generate large responses. This scenario could result in a cache that is populated with multiple versions of large responses. The cache will optimize its memory usage, but you cannot guarantee that it will do so effectively enough such that the Web service performance level remains consistent. |