Using VB.NET we would write: The WebService Attribute The WebService attribute is used to configure properties for the class - rather than the method or property - named in the WebServi
Trang 1If (Application("ProductData" + City) Is Nothing) Then
Application("ProductData" + City) = LoadDataSet(City)
sql = "SELECT * FROM Authors WHERE City = '" + City + "'"
Dim myConnection As New SqlConnection(dsn)
Dim myCommand As New SqlDataAdapter(sql, myConnection)
Dim products As New DataSet
myCommand.Fill(products, "products")
Return products
End Function
End Class
Trang 2You might have to alter the server name in the code above to reflect your own database
Here, a WebMethod named GetDataSet accepts a single parameter: City The result from the request will be output cached The ASP.NET Web Service is executed once and served statically on subsequent requests for 30 seconds and the cache will vary based on the different value for City If we have a request where the value of City is Dallas, the Web Service will execute once and the result will be cached If there is another request for Dallas within the allotted time period of 30 seconds, it will be served from the cache - the ASP.NET Web Service does not need to execute and query the database
This can be a serious performance enhancement, but should be used wisely - only items that vary by a few parameters are good candidates for Web Services output caching
Buffering the Server Response
Buffering allows the server to buffer the output from the response, and transmit it only once the response is completely buffered For long running methods this might not be optimal - we'd probably want to send the response as we receive it rather than waiting for the complete response
By default, ASP.NET Web Services buffer the response before sending it, as this is usually most optimal for the server However, the BufferResponse property allows us to configure ASP.NET Web Services to not buffer the response By default this property is set to true Using VB.NET we would write:
The WebService Attribute
The WebService attribute is used to configure properties for the class - rather than the method or property - named in the WebService directive These properties apply both to the Web Service Help page, as well as the WSDL It does not, however, mark the methods within the class as web callable
There are three properties of the WebService attribute that we can manipulate:
Description
Trang 3 Namespace
Name
Commenting the Web Service
The Description property is used to provide a brief description of the functionality of the class that contains
web-callable methods and properties It's similar to the Description property of the WebMethod attribute, but it's a description for the entire class, not individual methods and properties Using VB NET we would write:
<WebService (Description:="[string]")> Public Class [Class Name]
Using C# we would write:
[WebService(Description="[string]")]
public class [Class Name]
Using the Description Property
The value from the Description property is added to the WSDL, and is also added to the output generated when the ASP.NET Web Service is requested by the browser For example, we can add a Description property to our Fibonacci example (WebServiceDescription_cs.asmx):
<%@ WebService Language="C#" class="Fibonacci" %>
using System.Web.Services;
[WebService(Description=
"This class contains methods for working with Fib series")]
public class Fibonacci : WebService{
[WebMethod]
Trang 4public int GetSeqNumber(int fibIndex){
if (fibIndex < 2)
return fibIndex;
int[] FibArray = {0,1};
for (int i = 1; i< fibIndex; i++){
FibArray[1] = FibArray[0] + FibArray[1];
FibArray[0] = FibArray[1] - FibArray[0];
Trang 5Controlling the Namespace
XML uses namespaces to uniquely identify sections of an XML document Multiple documents can share markup vocabularies to describe particular regions of information For example, if we have two XML documents that both contain
an <Add> element, how can software differentiate between the two elements in the composite document?
Organizations may qualify their markup vocabulary with a universal name that is unique to their markup vocabulary through the use of XML namespaces
The default namespace that ASP.NET assigns to ASP.NET Web Services is http://tempuri.org We'll talk more about
tempuri.org in the WSDL section in the next chapter For now, all we need to know is that we can use the Namespace property of the WebService attribute to change the namespace value to a value of our choosing Using VB NET we would write:
<WebService(Namespace:="[string]")> Public Class [Class Name]
Using C# we would write:
[WebServiceNamespace="[string]")]
public class [Class Name]
Using the Namespace Property
If we viewed the WSDL from either our VB or C# Fibonacci Web Service, we would see http://tempuri.org/ used for the value of the namespace:
Trang 6If we wanted to change the namespace to http://rhoward/Fibonacci/, we would make the following change to our code (WebServiceNamespace_cs.asmx):
<%@ WebService Language="C#" class="Fibonacci" %>
for (int i = 1; i< fibIndex; i++){
FibArray[1] = FibArray[0] + FibArray[1];
Trang 7FibArray[0] = FibArray[1] - FibArray[0];
}
return FibArray[1];
}
}
Now our WSDL appears as follows:
This affects what our SOAP message looks like:
Trang 8Changing the Name of the Web Service
When the WSDL is generated for an ASP.NET Web Service, the name of the class is used for the service name value within the WSDL When a proxy uses the WSDL and builds a proxy class, the name of the class generated corresponds to the name value of service The Name property of the WebService attribute allows us to override the default value Using VB NET we would write:
<WebService(Name:="[string]")> Public Class [Class Name]
Using C# we would write:
[WebService(Name="[string]")]
Using the Name Property
For example, if we viewed the WSDL of our Fibonacci class we would see the following:
Trang 9If we were to set the Name value to WebServiceExample in the WebService attribute (as in WebServiceName.asmx):
[WebService(Name="WebServiceExample")]
we would see the following change in our WSDL:
All instances of Fibonacci in the WSDL have been replaced with WebServiceExample
This property is useful if we want to control the name of the class that proxies generate, as tools that consume the WSDL
to build the proxy will now build a WebServiceExample class as the proxy instead of building a class with the name Fibonacci
Now that we've looked at the two attributes we will use most often to build ASP.NET Web Services, we're ready to discuss how we should go about designing Web Services, and look at some more advanced issues involved
Designing ASP.NET Web Services
Web Services provide access to application logic, and application logic can take many forms- from stored procedures to components Although ASP.NET Web Services take the form of classes with implementations, this should not imply that normalized object-oriented design principles must be adhered to We shouldn't ever consider a Web Service to be a class,
Trang 10method, or property Rather a Web Service is an endpoint that we send data to and receive data from
Let's start the discussion of building ASP.NET Web Services by discussing API design, namely "chunky versus chatty" patterns
Chunky Versus Chatty
Web Services rely on XML and HTTP to encode and transmit serialized application data The combination of these two technologies provides a powerful means to create cross-platform distributed applications, as well as the ability to push application requests through proxies However, there are some downsides to this technology as well It's an extremely verbose way of describing what should be a simple exchange of data between two applications, and it's stateless Thus, the design recommendation is that we should try to reduce the number of network calls to the Web Service wherever possible
Stateless Versus Stateful
HTTP is a stateless protocol, and this doesn't change for ASP.NET Web Services that use HTTP to transport SOAP messages ASP.NET provides workarounds for this stateless barrier, but the workarounds rely on the use of a session token which can either be stored in an HTTP cookie, or embedded within the URL
We should definitely take the stateless nature of HTTP into account when building web applications If we need to solve that stateless problem with a solution such as Session state, it's worth considering the implications to the Web Service
- using HTTP cookies builds reliance on the protocol rather than the SOAP message
The discussion of stateless versus stateful applies most to discussions of design - how will we expose our application logic and how end-users interact with that logic? For example, will we use the methods or properties in our classes?
Methods or Properties
ASP.NET Web Services use a class with methods marked with the WebMethod attribute to enable us to send and receive SOAP messages Although we've shown how to use the WebMethod attribute applied to methods within the class, this attribute can also be applied to properties:
<%@ WebService Class="MethodsAndProperties" %>
Imports System.Web.Services
Public Class MethodsAndProperties
Trang 11Private Dim _name As String
Public Property YourName() As String
It's best not to mark properties with the WebMethod attribute Although functionally the behavior can be made to work,
it requires that the class instance holds state For example, running the code example above (using our handy Web Service Description Help page) we can call set_YourName and pass it Rob If we then call get_YourName we get no result Since ASP.NET Web Services are stateless, the instance of our MethodsAndProperties class is created and destroyed for each request
We can fix this by enabling session state (StatefulMethodsAndProperties_vb.asmx):
<%@ WebService Class="MethodsAndProperties" %>
Imports System.Web.Services
Public Class MethodsAndProperties
Trang 12Private Dim _name As String
Public Property YourName() As String
Caching Versus Static
Caching is another feature that can really help us build great ASP.NET Web Services It's ideal for data that is requested often and doesn't change frequently As we've already seen, we can control caching using the CacheDuration property
of the WebMethod attribute
Response Caching
The CacheDuration property allows us to specify a time duration within which the response to the request should be served from the ASP.NET cache Serving requests from the cache can dramatically improve the performance of our application, since we no longer need to execute code on each request
Trang 13Requests to a web-callable method using the CacheDuration property will vary the entries for the response in the cache based upon the request So, for a SOAP request, the contents of the cache will depend on the POST data
Public Class DataCachingExample
<WebMethod()> Public Function GetDataSet(column As String) As DataSet
Dim AppCache As Cache
Trang 14End Function
Private Function LoadDataSet(column As String) As DataSet
Dim myConnection As SqlConnection
Dim myCommand As SqlDataAdapter
Dim products As DataSet
myConnection = _
New SqlConnection("server=localhost;uid=sa;pwd=;database=pubs")
myCommand = _
New SqlDataAdapter("select " + column + " from Authors", myConnection)
products = New DataSet()
Although caching is recommended when (and where) possible for performance enhancements, we need to understand how the resources within the Web Service are being cached For example, in the previous database example we had a
Trang 15fairly simple matrix of items to be served from the cache (limited by the number of columns in a particular database table) However, caching is useless for application logic that might have an unlimited amount of variations- for example, Add(aAsInteger,bAsInteger)
Asynchronous Versus Synchronous
Web Services can be designed to be synchronous or asynchronous:
A synchronous design allows the ASP.NET thread of execution to run until it's complete If an action within the code has the potential to block, such as network I/O or an extensive database lookup, this can stall the ASP.NET worker thread Since a thread is a resource, and there are only a limited number of resources available on the system, this can force other requests to be queued This all translates to an impact on the performance and scalability of the system
An asynchronous design, on the other hand, allows the ASP.NET thread of execution to start up another thread, which can call back onto an ASP.NET thread when the work is complete That way, the ASP.NET application is not stalled because of resource constraints on available threads
Advanced ASP.NET Web Services
In this section we're going to 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 us with several additional attributes (which we didn't discuss earlier) that allow us 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:
XML Documents: XmlArraySOAP Documents:
SoapArray Allows us to treat elements as an XML array
Trang 16These 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 we return an instance of a class We haven't discussed returning classes yet, so a brief example is necessary A simple ASP.NET Web Service (Books_vb.asmx) that returns a Books class follows:
<%@ WebService Class="ReturnBooks" %>
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"
Trang 17b.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 Here's the XML document returned from an HTTP-GET request:
Trang 18If we wanted 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> - we would use the XmlAttribute and XmlElement attributes
To effect the SOAP message we would also need to add the SOAP equivalent attributes
We need to make two changes to our Books class First, we need to add the System.Xml.Serialization namespace,
as both the XmlAttribute and XmlElement attributes are found within this namespace Secondly, we need to add the attributes to the book class member variables we want them applied to (Books2_vb.asmx):
<%@ WebService Class="ReturnBooks" %>
Imports System.Web.Services
Imports System.Xml.Serialization
Public Class ReturnBooks
<WebMethod()> Public Function GetBooks() As Books
Dim b As New Books
Trang 19b.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
Trang 20<XmlArray("Contributors")> Public Authors() As String
End Class
All of these attributes allow us 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
Here's our new XML document:
Next, we'll look at the Web Service Help page, which is what we use when we view our Web Service using a browser
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 In Chapter 16, when we discussed ASP.NET configuration, we covered how each application can support its own Web Service Help page- 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, we can make modifications
to it For example, we can customize this page with graphics that are specific to our application, or provide additional details about the Web Services that our server provides
Keep in mind that any modification 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 modifications that we can make to this file which will be useful in debugging our ASP.NET Web Service