The .asmx file format is very straightforward. You have two options for exposing application logic as an ASP.NET Web service. Both options involve creating a file with a .asmx extension:
Inline :The application logic exists within the .asmx file.
Code-behind :The application logic exists outside the .asmx file.
The first option (and the one used for our examples) is to code the application logic within the .asmx file. This is similar to inline ASP.NET pages “ we take the Fibonacci VB.NET or C# code, and create the corresponding Fibonacci_vb.asmx and Fibonacci_cs.asmx .
We have a code-behind option for ASP.NET Web services just as that for ASP.NET pages. Code-behind is the default behavior for ASP.NET Web services created with Visual Studio.NET. Rather than the application logic existing within the .asmx file, the application logic is stored in an external assembly.
To be able to reference an external assembly, the assembly must reside in the ASP.NET application's bin directory. The bin directory is a special directory used by the ASP.NET application, to which assemblies can be deployed and automatically registered.
To use the code-behind option, simply create a small ASP.NET Web service .asmx file (which we'll call Fibonacci_Codebehind.asmx ) that contains a single line:
<%@ WebService Codebehind="Fibonacci.vb" Class="Fibonacci" %>
You need an implementation of the Fibonacci class in a separate assembly, either compiled and deployed in the ASP.NET application's bin directory, or as part of an assembly named directly in the configuration file. Here's what the source would look like for the VB.NET version of the Fibonacci example ( Fibonacci.vb ):
Imports System Imports System.Web Imports System.Web.Services Public Class Fibonacci <WebMethod()> Public Function GetSeqNumber(fibIndex As Integer) As Integer If (fibIndex < 2) Then Return fibIndex End If Dim FibArray(2) As Integer Dim i As Integer FibArray(0) = 0 FibArray(1) = 1 For i = 2 To fibIndex FibArray(1) = FibArray(1) + FibArray(0) FibArray(0) = FibArray(1) - FibArray(0) Next Return FibArray(1) End Function End Class
You can simply use the following command line to compile the source into a .NET assembly:
vbc /t:library /r:System.Web.dll /r:System.Web.Services.dll Fibonacci.vb
The result of this is a single file, Fibonacci.dll , which you need to place in a bin directory that is located below the root directory of the application. You can easily deploy the assembly ( Fibonacci.dll ) so that both ASP.NET pages and web services may use it “ it's simply a component with a WebMethod attribute.
For example, if you decide that the functionality encapsulated within a class would make a great web service, you can simply make some minor changes to the assembly's application logic and create a one- line ASP.NET Web service .asmx file (as shown), to enable the application logic as a SOAP-based endpoint.
As code-behind is the default behavior, the use of the Codebehind statement in Fibonacci.asmx is optional. Visual Studio .NET will use the Codebehind attribute, but you can just as easily remove it and still achieve the same functionality, so long as the assembly contains the class the ASP.NET Web service references. Also, there is no difference in performance between using inline code or code-behind.
Further discussion of web services will use the inline style, unless otherwise noted. The only tangible benefits of using code-behind over the inline style are:
Code is compiled, and the source cannot be viewed once deployed.
Since the code-behind option is an assembly, the assembly can also be used in ASP.NET pages.
Both the inline and code-behind options share a common set of directives that are used to give ASP.NET special instructions when handling ASP.NET Web service requests .
Like ASP.NET pages, ASP.NET Web services support directives that instruct ASP.NET how to process the request. For example, when the Fibonacci examples were converted to ASP.NET Web services, we first added a directive at the top of the .asmx file.
Using VB.NET, we wrote:
<%@ WebService Class="Fibonacci" %>
And using C#:
<%@ WebService Language="C#" Class="Fibonacci" %>
The WebService directive is a required addition for all ASP.NET Web services. We'll look at the directive syntax, and then at the attributes we'll use most often.
The directive syntax is identical to that of ASP.NET pages. The declaration is contained within <%@ and %> tags, contains a single directive, and may contain multiple attributes that apply to that directive:
<%@ DirectiveName Attribute="Value" %>
Or:
<%@ WebService Attribute="Value" Attribute="Value"%>
An ASP.NET Web service may contain multiple classes. However, only one of the classes can contain methods marked with WebMethod attributes. This relationship is enforced with a WebService directive attribute named Class .
The Class attribute is special, since it is required and forces us to always declare the WebService directive within a .asmx file. Fortunately, it's not complicated. The Class attribute simply names the .NET class, whether inline or code-behind, that contains exposed methods or properties:
<%@ WebService Class="[Namespace.Class Class]" %>
The Fibonacci class must be named in the Class attribute as the class contains the logic to be exposed:
<%@ WebService Class="Fibonacci" %>
If the Fibonacci class existed within a namespace, you'd need to further qualify it:
<%@ WebService Language="C#" Class="MyMath.Fibonacci" %> namespace MyMath{ public class Fibonacci{ // implementation } }
In addition to the class attribute, you need to use the language attribute if you use a language other than the ASP.NET default language, VB.NET. To use C# as the language for the Fibonacci implementation, add a Language directive:
<%@ WebService Language="C#" Class="Fibonacci"%>
That's all you need for coding simple ASP.NET Web services. Next, we'll look at the changes to be made to the application logic.
Whether the application code for an ASP.NET Web service exists inline or in an assembly named through the code-behind support, the requirements for both resources remain the same. You must:
Include a reference to the System.Web.Services namespace
Use attributes found within the System.Web.Services namespace to identify those methods and properties that should be Web-callable
Optionally inherit from the WebService base class
The System.Web.Services namespace contains classes that ASP.NET relies upon to enable ASP.NET Web services. Declare the use of this namespace in your ASP.NET Web service file differently depending upon the language you code the logic with. Using VB.NET, you would write:
Imports System.Web.Services
Using C#, you would write:
using System.Web.Services;
Importing the System.Web.Services namespace is required, as this namespace contains the WebMethod attribute.
The WebMethod attribute is the declarative code used to enable the application logic to be Web-callable. Thus, you'd be able to support serialization and deserialization of XML, mapping of XML values to correct types, and transporting of requests and responses “ the 'infrastructure' that enables web services.
Again, the syntax of the attribute declaration varies from language to language. For VB.NET, declare the attribute inline with the function or property declaration:
<WebMethod> Public Function GetSeqNumber (fibIndex as Integer) as Integer
For C#, declare the attribute on the line preceding the method or property declaration:
[WebMethod] public int GetSeqNumber(int fibIndex)
The following is an example of using WebMethod in VB.NET ( WebMethod1.asmx ) that returns the sum of two integers provided by the user :
<%@ WebService class="WebMethod1" %> Imports System.Web.Services Public Class WebMethod1 <WebMethod> Public Function Add(a As Integer, b As Integer) As Integer Return a + b End Function End Class
Once the WebMethod attribute is added, the Add method is Web-callable, and when the .asmx is requested through a browser, the method is available to select as shown in Figure 19-5:
The last change you might need to make to the application code is to inherit from the WebService base class (also contained in the System.Web.Services namespace). You only need to do this if the web service requires the properties that the base class make available, as discussed next.
An ASP.NET Web service is part of the ASP.NET application it resides in. Just as we have application-specific configuration, session, and data for ASP.NET pages, we have the same capabilities for ASP.NET Web services.
You have a couple of choices for how you gain access to the ASP.NET-intrinsic objects, such as Application or Session . The easiest way to enable access to ASP.NET intrinsic objects within a web service is to inherit from the WebService base class.
In the following VB.NET code, we use the Inherits keyword to inherit from the WebService base class. This base class for example, gives access to an Application property, just as we would expect to find when coding an ASP.NET page:
<%@ Webservice class="WebServiceBaseClass" %> Imports System.Web.Services Public class WebServiceBaseClass Inherits WebService <WebMethod> Public Sub SetApplicationState(state As String) Application("state") = state End Sub <WebMethod> Public Function GetApplicationState() As String Return Application("state").ToString() End Function End Class
This code ( WebServiceBaseClass1.asmx ) exposes two Web-callable methods:
SetApplicationState : Accepts a string value and sets an application key/value pair to the value passed in
GetApplicationState : Simply retrieves the value of the data set in SetApplicationState
It's important to note that an ASP.NET page has access to the same application state memory that ASP.NET Web services do (the same is also true with Cache and Session ). Therefore, items added to application state memory, or to the cache, can be shared between the page and web services. This allows for powerful reuse. For example, an e-commerce site can load the store catalog into Application state memory from the database a single time, and then both the ASP.NET pages and web services can share that data.
The WebService base class adds five public (not Web-callable) properties that you are already familiar with from ASP.NET pages:
Application : Application state memory
Context : Instance class passed throughout the life of the request
Server : Server-intrinsic, provides us with access to methods such as CreateObject
Session : Session state memory
User : Identity of the user making the request (security feature)
Classes do not need to inherit from the WebService base class in order to be a functional web service “ it is only for convenience. In fact, since an ASP.NET Web service is simply another ASP.NET resource, the HttpContext , which contains the raw information for the request and response, is already available by default. So, classes that do not inherit from the WebService base class can still implement similar functionality “ for example, accessing the Application intrinsic object.
Let's take, for example, the same code as before, but without inheriting from WebService :
<%@ Webservice class="WebServiceBaseClass" %> Imports System.Web Imports System.Web.Services Public class WebServiceBaseClass <WebMethod()> Public Sub SetApplicationState(state As String) Dim Application As HttpApplicationState Application = HttpContext.Current.Application Application("state") = state End Sub <WebMethod()> Public Function GetApplicationState() As String Dim Application As HttpApplicationState Application = HttpContext.Current.Application Return Application("state").ToString() End Function End Class
In this example ( WebServiceBaseClass2.asmx ), we're using the web service's instance of the HttpContext to retrieve the intrinsic Application object. This means we have to import the System.Web namespace in the code, since HttpContext is defined in the System.Web namespace.
The HttpContext instance can then be used to access the intrinsic Application object, which is set to a local variable of type HttpApplicationState named Application . The code then uses the intrinsic Application object in an identical manner to the code that inherited from the WebService base class.
Since a class can only inherit from a single base class, the advantage of not using the WebService base class can be seen when inheriting from a different class.
You now have all the basic knowledge necessary for building ASP.NET Web services. You could now skip directly to consuming ASP.NET Web services. However, there are more options available in building ASP.NET Web services. For example, the WebMethod attribute has configurable properties, and it's not the only attribute you can use.
Before looking at these options, we need to talk a little about the protocols and data types supported by web services.