Developing a Web Service


Now to the nitty-gritty of Web services: how do you create one and then get an application to make use of it? What tools do you use?

Truth be told, although we work with trivial code for demo purposes, a basic text editor such as Notepad can do the job. Likewise, you can use any tool you’d usually use for .NET development to work with services—Emacs, Dreamweaver MX, CodeWarrior. However, we’ll use Visual Studio .NET throughout the book for examples of larger projects that favor the creation and consumption of Web services. As you’d expect, Visual Studio .NET helps a great deal in the creation of boilerplate code and easy-to- manage projects, and it provides a lot of help in packaging up code for deployment elsewhere. We’ll look at the Web service–specific features of Visual Studio .NET as we go.

A Simple Example in Notepad

We’ll start with a quick example in Notepad to prove that, as with ASP.NET pages, we don’t have to have a huge IDE to develop a Web service. A quick trawl of the UDDI servers out there reveals well over 200 Web services named Hello World or Test; rather than follow the trend, we’ll build something just as simple but a bit more fun. So fire up Notepad and type the following:

<%@ WebService Language="C#"  %> using System; using System.Web.Services; [WebService(Namespace="HHhttp://www.notashop.com/wscr",             Description="SimpleService1")] public class SimpleServices : System.Web.Services.WebService {     [WebMethod(Description="A first warning")]     public string WakeUp(string yourName)     {         return "Wake up " + yourName + ". The Matrix has you";     } }

Or, in Visual Basic .NET, type this:

<%@ WebService Language="VB"  %> Imports System Imports System.Web.Services <WebService(Namespace:="http://www.notashop.com/wscr", _             Description:="SimpleService1")> _ Public Class SimpleServices      Inherits System.Web.Services.WebService     <WebMethod(Description:="A first warning")> _     Public Function WakeUp(ByVal yourName As String) As String         Return "Wake up " + yourName + ". The Matrix has you"     End Function End Class

Create the directory structure wscr\01 under the root folder of your Web server, and save the code as simple1.asmx in the 01 folder. Now start your browser and navigate to your new file at http://localhost/wscr/01/simple1.asmx. You’ll find that Microsoft Internet Information Services (IIS) has generated a test page for the service, as shown in Figure 1-4.

click to expand
Figure 1-4: The test page for our simple1.asmx service

The test page holds entries for each method the service makes public, so in this case, there’s just a single entry for the WakeUp method we’ve defined. Click it, and you’ll see a form in which you can set the value of the WakeUp method’s yourName parameter and an Invoke button to send your request to the service. The response we receive is in XML, as shown in Figure 1-5.

click to expand
Figure 1-5: Our service returns a response in raw XML.

Congratulations. You’ve just successfully written and tested your first Web service. That wasn’t too hard, was it? Let’s see what went on behind the scenes.

Note

If you’re not using Microsoft Internet Explorer for your browser, the response might differ slightly according to how the browser deals with unformatted XML. It is the same XML, however.

The Life Cycle of a Web Service Request

So exactly how do Web services work? What makes them tick? How do client and server interact when Web services are involved? Perhaps the best way to answer these questions is to look at how a client holds a conversation with a service.

Figure 1-6 shows the interaction between a client and a server as we call the WakeUp method on the service we just created. In this case, it starts when we click Invoke on the test page:

  1. The client (in our previous example, the service’s test page) makes a call to the service. It collects the parameters needed for the call by having you enter their values in a form, and it translates them into the desired format for transmission over the Web in a process known as serialization.

  2. In our simple example, the test page form sends the parameters and the name of the method to the server in the URL. As you’ll see in the rest of the book, calls are more frequently serialized into SOAP request messages stored in the body of the HTTP message. However, the service test page doesn’t cater to this.

  3. The SOAP request message is deserialized (in our case, the URL is followed), and the call is executed on the server. If the conversation is one-way, the cycle ends here. An acknowledgment that the work has been done is returned to the client (and nothing else).

    If the client expects a value or values to be returned, the server serializes the return values and out parameters into a given format and transmits them back. (Note that the response might be an error message if things go wrong.)

    Again, the norm here is for the values to be serialized into a SOAP response message to be sent over HTTP, but the results of our simple example are returned as an HTTP response instead. The WakeUp test page shows the different response messages that it can produce depending on how the method call was originally sent to the server.

  4. The client receives the response from the server and acts accordingly. In our example, the browser had no instructions about what to do with the returned XML, so it just displayed it. The client actually has two options: work with the XML as it was returned or deserialize it into .NET objects and work with them. In .NET, the latter is the default.

    click to expand
    Figure 1-6: The life cycle of a Web service request

Note that like a request for a Web page, our Web service and its test page were accessed via a URL. This use of HTTP as the transport protocol for requests is the most common possibility but not the only one. Web services have been set up and run over Simple Mail Transfer Protocol (SMTP), Microsoft Message Queue (MSMQ), and IBM’s WebSphere MQ, but because the SOAP standard defines a binding only to HTTP, HTTP will continue to be the most popular choice. Of course, you still have to work around its weaknesses. For example, a SOAP request working over HTTP (or HTTPS) doesn’t carry any notion of state from client to server or vice-versa unless it has been programmed to do so. By default, the standard state mechanism over HTTP—cookies—is not supported for Web services.

From a developer’s perspective, Web services are quite straightforward to develop and their clients are simpler still. Web services enforce and enable a high level of abstraction between client and server. When a client is built, it uses the WSDL document that unambiguously describes the service’s interface (or behavior) to generate the proxy class. (See http://localhost/wscr/01/simple1.asmx?wsdl for our example service’s WSDL.) Depending on whether a Web method is one-way or two-way, the WSDL document also defines the format to be expected for the return message. It’s up to the client how it uses the methods presented in that interface and how objects are serialized, how queries are generated, and how responses are interpreted. In this way, the Web service client and provider are freed from needing any knowledge of each other beyond the contract of inputs and outputs laid down by the interface and the location of the Web service provider.

Message Formats

Have another look at the page where you can invoke the WakeUp method on our simple service. If you closed the browser already, you should find it at http://localhost/wscr/01/ simple1.asmx?op=WakeUp. Underneath the form to query the service, you’ll find templates for both request and response messages to and from the service in three formats— HTTP-GET, HTTP-POST, and HTTP-SOAP. As an experienced Web developer, you’ll already be familiar with the first two formats, but what exactly does a SOAP message consist of anyway?

SOAP

The schema for SOAP is actually stricter than XML in an effort to keep things simple. (The S in SOAP does stand for simple, after all.) It prevents the use of DTDs and XML processing instructions in a message, for example. There’s nothing to stop the client or the server from validating the structure of the message against a DTD or a schema, but you can’t include the DTD or the schema in the message for the recipient of the message to use.

The SOAP specification defines a SOAP message as an XML document consisting of up to three main elements.

  • The <Envelope> element is the top-level element of a SOAP message and encompasses the actual contents of the message and any processing information that might need to be followed for its successful delivery.

  • The <Header> element contains the delivery instructions for the message and any other information that isn’t the message itself—for example, any transactional information, cryptography keys, delivery routes, and so on. Adding a SOAP header to your message is optional.

  • The <Body> element contains the actual message from the sender, be it a request, a response, or a SOAP <fault> element containing an error message.

Figure 1-7 illustrates the hierarchy of these elements.


Figure 1-7: A SOAP message has an Envelope that encompasses <Header> and <Body> elements.

For example, if we had sent our simple service a SOAP request, it would have looked like this:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"                 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <WakeUp xmlns="http://www.notashop.com/wscr">       <yourName>Dan</yourName>     </WakeUp>   </soap:Body> </soap:Envelope>

Note that we defined four XML namespaces for our reference in the message:

  • http://schema.xmlsoap.org/soap/envelope is the namespace for SOAP 1.1 elements.

  • http://www.w3.org/2001/XMLSchema and http://www.w3.org/2001/ XMLSchema-instance let us define any custom types and strongly type the variables inside the SOAP envelope. (We don’t actually need these in our simple example, but they’re handy to know.)

  • http://www.notashop.com/wscr is the service’s namespace. We used this to differentiate the message payload from the SOAP protocol elements.

You can also define an optional attribute in the <Envelope> element called encodingStyle that allows you to set the serialization rules used in the SOAP message. The actual custom serialization routines are defined in the code behind the service and its client. The .NET serializers were designed to make this process very simple, and the simple and complex types defined by .NET all correspond to XSD types as defined in XML schemas, making the actual serialization process faster to perform.

A Simple Example in Web Matrix

For those of you who would rather not work with raw text but who don’t want a copy of Visual Studio .NET, the Web Matrix project, available for download at http://www.asp.net, is well worth looking into. A cut-down version of Visual Studio .NET purely for ASP.NET (and therefore Web service) development, Web Matrix crosses the feel and RAD capabilities of a proper IDE with the absolute control of a text editor. Like Visual Studio .NET, it also has its own Web service wizard.

Start Web Matrix, and when you’re asked to create a new file, select XML Web Service from the panel on the right, as shown in Figure 1-8. You’ll be asked to give a location, a filename, a class, and namespace for your code. We’ll call this service simple2.asmx. Enter C:\Inetpub\wwwroot\wscr\01 for the location (adjusting the path according to the location of your IIS wwwroot folder), simple2.asmx for the filename, SimpleServices for the class, and notashop.wscr for the namespace. Also, select C# or Visual Basic .NET from the Language drop-down list.

click to expand
Figure 1-8: Web Matrix has a Web service wizard.

As you’ll see, Web Matrix adds some demonstration code to our file before we get started. In this case, it asks for two numbers and returns their sum. Replace this demo code so simple2.asmx looks like this in Visual C#:

<%@ WebService language="C#"  %> using System; using System.Web.Services; using System.Xml.Serialization; public class SimpleServices {     [WebMethod]     public string BioVolts(int age) {         int volts = age * 240000;              return "You have generated " + volts              + " biovolts in your lifetime.";     } }

Or, in Visual Basic .NET:

<%@ WebService language="VB"  %> Imports System Imports System.Web.Services Imports System.Xml.Serialization Public Class SimpleServices     <WebMethod> Public Function BioVolts(age As Integer) As String         Dim volts As Integer = age * 240000         Return "You have generated " & volts _             & " biovolts in your lifetime."     End Function End Class

The structure of the code surrounding the new method isn’t exactly the same as simple1.asmx, and some of that difference is reflected when we browse to our new service (as shown in Figure 1-9).

click to expand
Figure 1-9: A new service, but this time with a warning

The initial test page at http://localhost/wscr/01/simple2.asmx now warns us to change the Web service’s namespace before we make it public. You’ll see how to do this in our next example, and you’ll see the difference it makes when our Web service class inherits from the .NET service base class, System.Web.Services.WebService, as it did in our first example. For the time being, the service works exactly as we’d expect it to.

A Simple Example in Visual Studio .NET

As you’d expect from Microsoft’s development environment of choice, you get a great deal more assistance with your Web service development in Visual Studio .NET than you do Notepad or Web Matrix. Visual Studio .NET sets up projects, creates files and virtual directories, and makes your Web service publicly available to those who can see it.

To add a new C# Web service project to your current Visual Studio .NET solution, follow these steps:

  1. Choose New Project from the File menu, and in the New Project dialog box, select Visual C# Projects from the left pane and ASP.NET Web Service from the right.

  2. In the Location box, type in the URL through which your Web service will be accessible. The folder name there will also be the name of the project. For example, http://localhost/hello or http://www.notashop.com/wscr/hello in the location box both mean that the project’s name is hello. We’ll put ours at http://localhost/wscr/01/simple3.

    Note that Visual Studio .NET expects the remote location you give for the Web service’s home to be available; if it can’t contact the Web server in question, an error appears reminding you to get it started. The same is true when you need to reopen a Web service project.

  3. Click OK, and Visual Studio .NET generates a new virtual directory for the service and creates several new files, including the .asmx file we’re starting to know.

Project Files

When Visual Studio .NET initially sets up a Web service project, it generates several files, as shown in Figure 1-10. If you don’t see all of them, select the Show All Files option from the set of icons in the Solution Explorer window.


Figure 1-10: Solution Explorer shows the files in our Web service project.

AssemblyInfo.cs, Global.asax, Global.asax.cs, Global.asax.resx, and Web.config work in exactly the same way as for a standard Web Forms project. It’s the .asmx files we need to investigate.

The .asmx file is the focus of your Web services. As you’ve seen, this is the file that contains the Web service and that, together with its associated .asmx.cs or .asmx.vb code- behind file, implements its functionality. By default, Visual Studio .NET opens the .asmx file in design view. As you’ll see in Chapter 7, it is possible to incorporate .NET components into your service by dragging them onto the canvas from the Toolbox window, but for now switch to code view (right-click in the design view and choose View Code) to open a copy of the .asmx.cs code-behind file.

Let’s look at the code generated (minus the comments). We’ll start off with a set of references to pieces of the .NET Framework. Only System.Web.Services and System.ComponentModel are really needed for the code included, so you can remove the others if you want.

using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace Simple3 {

Like any other .NET application, a Web service is written as a class, so it might be instantiated as an object by your application. Although it’s not necessary for services as trivial as the ones demonstrated so far, you can choose to derive your class from System.Web.Services.WebService, the .NET base class for Web services. In doing so, you gain access to the common ASP.NET objects, such as Application, Session, User, and Context, which will come in handy when you need to manage session state and identify your service’s users.

    public class Service1 : System.Web.Services.WebService     {         public Service1()         {             InitializeComponent();         }

The constructor for this class calls only the usual InitializeComponent method that Visual Studio .NET autogenerates to initialize the components that are to be used by the service. This, along with a Dispose method to allow for a clean exit from the service, should be left to the IDE to update as necessary.

        #region Component Designer generated code         private IContainer components = null;                  private void InitializeComponent()         {         }         protected override void Dispose( bool disposing )         {             if(disposing && components != null)             {                 components.Dispose();             }             base.Dispose(disposing);                 }         #endregion

Finally, to demonstrate the basic mechanics of a Web service, Visual Studio .NET also includes a commented out “Hello World” example:

        // WEB SERVICE EXAMPLE         // The HelloWorld() example service returns the string Hello World         // To build, uncomment the following lines then save and build the          // project. To test this web service, press F5 //        [WebMethod] //        public string HelloWorld() //        { //            return "Hello World"; //        }     } }

Like the Web Matrix code, Visual Studio’s dummy code works straight away. All you need to do is uncomment the HelloWorld method or delete it and replace it with the following and then press F5. A test page will appear as normal.

        [WebMethod]         public string TakeAPill(string color)         {             string response;             switch(color)             {                 case "red":                     response = "Welcome to Wonderland Alice";                     break;                 case "blue":                     response = "The Matrix still has you";                     break;                 default:                     response = "Red or blue to leave this crossroads";                     break;             }             return response;         }

How Does It Work?

The code in an .asmx or code-behind file is written in a language supported by .NET and contains the usual class and function definitions, so why do we get a Web service and not an ASP.NET page or something else when we browse to an .asmx file? What transformed the simple function into a public method exposed by a Web service?

Declaring a Web Service

When you create an .asmx file, you first need to declare that it’s a Web service. In our first two examples, we did this manually by adding the @WebService directive at the top of our .asmx file. This tells ASP.NET how the Web service has been implemented.

<%@ WebService language="C#"  %>

The directive has four attributes that allow us to specify the language the code is written in, the class (and assembly) implementing the Web service, the location of the code-behind page, and whether the service should be compiled with debug symbols.

If you’re wondering about the Visual Studio .NET example and why there’s no sign of this directive in the default code, just open the .asmx file in Notepad. Sure enough, you find the following.

<%@ WebService Language="C#" Codebehind="Service1.asmx.cs"       %>

Visual Studio .NET tries to keep you from looking at the actual .asmx page code. Instead, you either work in design view or edit the code-behind file.

The WebService Attribute

You might have noticed in our last two examples that the test pages warned about using the http://tempuri.org/ namespace URI in a live environment. This is the temporary default namespace that any .asmx service uses unless one is explicitly assigned. As the test page notes, you make this assignment with the WebService attribute.

Not to be confused with the class of the same name, the WebService attribute is used just in front of the class declaration for your Web service. In C#, this looks like the following:

[WebService(Namespace="http://www.notashop.com/wscr",             Description="SimpleService1",             Name="Try This Out")] public class SimpleServices : System.Web.Services.WebService {      

Here is the Visual Basic .NET equivalent:

<WebService(Namespace:="http://www.notashop.com/wscr", _             Description:="SimpleService1", _             Name:="Try This Out")> _ Public Class SimpleServices      

The WebService attribute allows you to declare your own namespace for your Web service, its name, and a brief description of what it does. Its use is optional, as are the items you can define, but it’s recommended if you want to distinguish your Web service when you put it live on a production server.

The WebMethod Attribute

Now that our file is recognized as a unique Web service, we’re left to declare which methods in our class will be made public under the service and be included as an operation in the service’s WSDL document. This we do with the WebMethod attribute, in much the same way that we used the WebService attribute, as in the example:

[WebMethod] public string WakeUp(string myName) {     return "Wake up " + myName + ". The Matrix has you"; }

Here’s the Visual Basic .NET version:

<WebMethod()> _ Public Function TakeAPill(ByVal color As String) As String      End Function

The WebMethod attribute also has a collection of qualifiers that you can use to establish how the method works within the context of a Web application. For example, you can set the following:

  • Whether the response from the method is buffered (BufferResponse)

  • Whether the method can handle state information (EnableSession)

  • How long the method’s response is kept in the server’s cache (CacheDuration)

  • Whether the method supports transactions (TransactionOption)

  • An alias for the client to call the method by instead of its actual name (MessageName)

  • A brief description of the method’s use (Description)

We’ll revisit these qualifiers later in the book.

People often make a few erroneous assumptions about using the WebMethod attribute. Let’s look at some examples. MethodOne works exactly as you’d expect:

public class SimpleServices : System.Web.Services.WebService {     [WebMethod(Description="Example method")]     public string MethodOne()     {              }

However, MethodTwo doesn’t. A function must be declared public for the WebMethod attribute to make sense. Private and protected methods will not be made public even if they’re tagged with the attribute.

    [WebMethod]     private string MethodTwo()     {         // Private class methods can't be Web methods     }

A common false assumption is that classes implementing Web services need to declare every method as a WebMethod. This is wrong. MethodThree(), for example, will not be exposed as a Web method but will remain public to other .NET classes as usual:

    public string MethodThree()     {         // Methods can remain private to the class implementation     }

Last but not least, it’s worth reiterating that Web methods do not need to return values. It’s perfectly feasible for Web service communications to be one-way only:

    [WebMethod]     public void MethodFour()     {         // WebMethods don't have to return anything     } }

Code-Behind Files

Our three examples have demonstrated that like any other page or form, the class that gives a Web service its functionality doesn’t have to be stored in the .asmx file itself. You have two other options. You can store it in a code-behind (.asmx.cs or .asmx.vb) file, or you can place it in a precompiled assembly. It’s just a matter of using the @WebService directive to tell the .NET runtime where the code is.

You’ve already seen how to declare the class when it’s located in the .asmx file or its code-behind .asmx.cs or .asmx.vb file:

<%@ WebService Language="C#"  %>

or

<%@ WebService Language="VB"  %>

To point the service at a class inside a precompiled assembly, you give the directive the class’s full name and the name of its assembly, as in this example:

<%@ WebService Language="C#"  %>

and this example:

<%@ WebService Language="VB"  %>

Note that the assembly you nominate in the directive must be located in the bin directory of the Web application hosting the XML Web service. If you don’t give an assembly name, ASP.NET will search through all the assemblies in the bin directory until it finds the correct one or it runs out of assemblies. Needless to say, it’s in your interest to provide it.

At its simplest, producing a Web service is a matter of taking some code you’ve already written, adding the WebMethod attribute to the methods you want to expose, and referencing the code from an .asmx file.




Programming Microsoft. NET XML Web Services
Programming MicrosoftВ® .NET XML Web Services (Pro-Developer)
ISBN: 0735619123
EAN: 2147483647
Year: 2005
Pages: 172

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net