XML Web Services

XML Web Services

The Internet is quickly evolving from the Web sites of today that deliver only pages to Web browsers to the next generation of programmable Web-based technologies that directly link organizations, applications, services, and devices with one another. These programmable Web sites are not passive they are reusable, intelligent Web services. The common language runtime provides built-in support for creating and exposing XML Web services, using a programming abstraction that is consistent and familiar to both ASP.NET Web Forms developers and existing Visual Basic users. The resulting model is both scalable and extensible and embraces open Internet standards HTTP, XML, SOAP, and Web Services Description Language (WSDL) so that it can be accessed and consumed from any client or Internet-enabled device.

Support for XML Web services is provided by ASP.NET, using the .asmx file extension. An .asmx file contains code similar to an .aspx file. In fact, much of the ASP.NET programming model is available to XML Web service developers, with the exception of the user interface classes. For a Web service, the user interface has no real meaning. It is, after all, a middle-tier technology. There is a caveat, however. ASP.NET projects and ASP.NET Web service projects are not fundamentally different, and there is no required separation. You can add an XML Web service file to a Web project, and you can also add a Web form to an XML Web service project. These files are then URI addressable, in the same way that .aspx files are. Also like .aspx files, .asmx files are compiled automatically by the ASP.NET runtime when a request to the service is made. (Subsequent requests are serviced by a cached precompiled object.)

On a more fundamental level, XML Web services enable the exchange of data and the remote invocation of application logic using XML messaging to move data through firewalls and between heterogeneous systems. Although remote access of data and application logic is not a new concept, XML Web services enable it to take place in a loosely coupled fashion. The only assumption between the XML Web service client and the XML Web service is that recipients will understand the messages they receive. As a result, programs written in any language, using any component model, and running on any operating system can access XML Web services.

When you create and/or use an XML Web service, you are taking advantage of SOAP. You may be aware of the SOAP Toolkit that was published for Visual Basic developers. While you can think of XML Web services as an alternative to the SOAP Toolkit, they are far more powerful, thanks to the .NET Framework. The SOAP Toolkit required a lot of work on the part of the developer, and Visual Basic imposed limitations related to serialization of objects. Visual Basic .NET removes these limitations and provides a far more powerful framework for developing SOAP applications by eliminating the need to implement features such as serialization and proxy generation. These features are already implemented in Visual Basic .NET and can be leveraged without any additional effort. It is possible, of course, to implement serialization yourself to provide any custom features that your application requires. For the vast majority of applications, however, the built-in serialization capabilities of the .NET Framework are more than sufficient.

Creating a Simple XML Web Service

Implementing a basic XML Web service in any application is a straightforward process. The XML Web Service project type (selected in the New Project dialog box) contains all the necessary elements for implementing an XML Web service. If you are running Visual Basic .NET on a machine with Internet Information Services (IIS) installed, it is a trivial task to create a new project and implement an XML Web service. The companion CD contains a sample called Simple Web Service, as well as a setup document that discusses the steps necessary to get the example up and running.

The basic steps for creating an XML Web service are as follows:

  1. Create a new ASP.NET Web service project.

  2. Add a new XML Web service file to the project.

  3. Add a method to the XML Web service class, and mark the method with the WebMethod attribute.

The most important part here is the use of the WebMethod attribute. This attribute tells the compiler to generate the XML contract for the Web service, register it for discovery, and produce the implementation code necessary for marshaling parameters and return objects. It also enables you to filter the methods of your XML Web service class and publish only the methods you want to make publicly available over the Internet. Think of this filtering as taking access protection a step further. You re already familiar with creating public, private, and friend methods. But there will probably be situations in which your application architecture requires a public method on your XML Web service class that you do not want to make available through the XML Web service itself. In such cases, the power of the WebMethod attribute really shines. It gives you absolute control over what you publish over the Internet without requiring you to sacrifice good component design in your XML Web service classes. The following excerpt from the SimpleService.asmx.vb file (part of the SimpleWebService sample project) demonstrates the WebMethod attribute in action:

<WebMethod()> Public Function HelloWorld() As String    HelloWorld = "Hello World. The current time is " & Now() End Function

You can do much more with the WebMethod attribute, such as manipulate additional settings, but we will use it in its simplest, most basic form, as demonstrated here. The MSDN documentation gives a more thorough treatment of the use of this attribute, above and beyond its default behavior.

Now is a good time to talk about restrictions on parameters and return values for XML Web services. An XML Web service is not a bidirectional object. This means that you cannot pass objects by reference; they must always be passed by value. In other words, your parameters and return values must be serializable. Most, if not all, of the intrinsic data types in Visual Basic .NET and the .NET Framework support serialization as long as the objects themselves are self-contained that is, as long as they don t represent or contain any physical system resources, such as database connections or file handles. For your custom classes you have two options. You can implement the ISerializable interface for your class, but this is the more manual process. Alternatively, you can use the Serialize class attribute. This option enables your class to serialize itself. No work is necessary on your part unless one or more of the types contained in your class do not support serialization. In such cases, you have the choice of adding the Serializable attribute to those classes (if they are under your control) or implementing the serialization yourself with the ISerializable interface.

The Simple Web Service example demonstrates the basic elements of an XML Web service. Figure 21-4 illustrates what the compiled service looks like in a Web browser. You can see all the methods exposed by the service and view the complete XML service description. We will leave the latter for you to pursue if you re interested. It is really used only by the Web reference mechanism in Visual Basic .NET, and you don t need to be familiar with the contents of the service description to make use of an XML Web service.

Figure 21-4

The SimpleService.asmx XML Web service as it appears in a Web browser.

Testing Your XML Web Service

As you have already seen, when you build an XML Web service, the Visual Basic IDE creates a test page for that service. This page allows you to inspect all the methods that are exposed, and it also gives you the ability to invoke the methods manually. This should be your first step in testing the service, to ensure that it is doing what you expect. In our sample service, you can click the HelloWorld method in the service description page to get more information about it. Figure 21-5 shows what this method looks like.

Figure 21-5

The SimpleWebService s HelloWorld method.

As you can see, a great deal of information is available through this page. You can also invoke the method (using the Invoke button) and view the SOAP result message. Additionally, if the service accepts parameters, this page will have input boxes for each of the parameters. There are some limitations to this, however. If your methods require parameters in a binary format (a Byte array, for example), you will need to invoke the method programmatically.

The result of invoking the HelloWorld method is displayed in a separate window and looks like this:

<?xml version="1.0" encoding="utf-8" ?>  <string xmlns="http://tempuri.org/"> Hello World. The current time is 10/13/2001 11:13:21 AM</string> 

Pretty neat, huh? Now we need to look at how you can use this method in an application.

Consuming a Simple Web Service

Now that an XML Web service exists on the target machine, it is possible to add a Web reference to a client project. An XML Web service client can be any kind of project, from a command-line or form-based application to a full-blown Web site or COM+ component. In this case, we have gone with a simple form-based application, but feel free to experiment by adding Web references to other kinds of projects.

Recall our discussion of different types of references in Chapter 6. A Web reference is simply a process by which the Visual Basic IDE goes out to the specified XML Web service, gets the XML contract for the service, and builds a proxy class that implements the contract. This process occurs transparently, and it is flexible enough that references can be refreshed in the IDE. In other words, it is possible to have the IDE regenerate the proxy class (which is usually desirable if there are new features that you want to take advantage of or if there have been interface implementation changes).

This proxy is not tightly coupled to the complete interface of an XML Web service. It will use methods and properties according to how they were defined the last time the proxy was generated. If the specified methods have not changed their signature that is, the parameter types, parameter count, or return type your application will not break, regardless of any other changes that might have been made to the XML Web service itself.

Creating this proxy is simple, as we have already mentioned. You create a simple Windows Forms project and add a Web reference by right-clicking the References collection in the Solution Explorer, specifying the path to the XML Web service that you have already created, and clicking OK. After a short delay, a new XML Web service proxy class should be added to your application. Now all that is necessary is to use it. Our sample solution has a Web Service Tester project that implements this sample XML Web service. This is a one-button application that does the following two things in response to a button click:

  1. Create the XML Web service proxy object.

  2. Call the HelloWorld method, and display a message box with the result.

The code itself is simple:

Private Sub CallButton_Click(ByVal sender As System.Object, _    ByVal e As System.EventArgs) Handles CallButton.Click    Dim ws As New localhost.SimpleService()    MsgBox(ws.HelloWorld()) End Sub

You can see the results in Figure 21-6. This sample project helps demonstrate how XML Web services simplify the development of distributed applications. XML Web Services are a powerful tool that enable the development of fundamentally different kinds of applications, due to its platform- and language-independent nature.

Figure 21-6

Web Service Tester application in action.

Moving On

This is all well and good, you may be thinking, but what about my existing applications? How should I implement XML Web services in an existing COM or managed application? Does it require redesign, or are there alternatives? Read on .

Supporting Web Services in Your Existing Applications

If you have an existing application for which you want to implement XML Web services without a major rewrite, you can take the approach of implementing the service as a wrapper around your existing code. Doing so allows you to handle the necessary serialization work in the service without having to modify the original application s code. This can be an effective way to add support for XML Web services to existing COM applications without making any radical changes. It also gives the developer the opportunity to rethink the application s interface to the outside by hiding methods or doing additional work that was not previously done on the server side.

This approach does raise some questions. If you are wrapping existing COM applications, you need to be aware of return types and whether you will need to implement serialization for them. This concern arises as a potential problem only when you need to pass variables that are specific COM types. Intrinsic data types will have no problems; it gets tricky only when you have complex custom data types, such as COM objects. What it ultimately boils down to is that you cannot use a COM component as either a Web service parameter or a return type. You must first serialize a COM component to an intrinsic data type (an XML string or a Byte array). Of the commonly used Microsoft COM objects, only ADO supports serialization to and from XML, and it is a manual process there is no such thing as implicit serialization for COM objects. If you create your own COM components, you may wish to add support for XML serialization. Including support is essential if you want to support passing such a component to and from an XML Web service.

There is also the possibility that you cannot modify the original COM object to add serialization capabilities. In this instance, you would be required to create code to perform the necessary serialization work in Visual Basic .NET, using it on both the server and client tiers. However, it may not be possible to work around some issues and you may be required to make some modifications to your original application. From a middle-tier standpoint, one of the most common objects passed around, and thus a likely candidate for inclusion in an XML Web service, is the ADO Recordset object, which is the subject of the next section.

Using Recordset with XML Web Services

As we mentioned earlier, it is possible to wrap an XML Web service around an existing COM object. If you are passing only the intrinsic types (such as strings, integers, and arrays of variables), you simply need to call the methods directly. The .NET Framework already knows how to serialize these types of variables. If you need to pass ADO Recordsets back and forth, however, you have some work to do.

In ADO 2.1, Microsoft added XML support to the ADO Recordset object. This object provides support for serialization to and from XML. The only caveat is that the support for serialization is not implicit. In other words, the Recordset does not support automatic or implicit serialization, but you can do the work explicitly. The key here is the Save method on the Recordset object and the use of the ADODB Stream object. Figure 21-7 illustrates the process of wrapping a COM object with an XML Web service, where the result is an ADO Recordset, and shows how the Recordset is marshaled from server to client.

Essentially, the figure depicts the process by which the Recordset is persisted to XML on the server and is returned to the client. The client then reconstructs the original Recordset. Notice that the reconstructed Recordset is not exactly the same as the original. The new Recordset does not contain any connections to a database, nor does it understand where it came from. For this reason, we say that this Recordset isdisconnected.

Figure 21-7

Passing a Recordset in an XML Web service.

To give you a better feel for how this process works, we ve provided a sample on the companion CD called Web Services and ADODB. The sample consists of two projects: an XML Web service (NorthwindDatabase) and a Windows Forms client application (Northwind Viewer). The design of the sample is simple. One method is available through the XML Web service that allows the client to specify a SQL query string and returns the result as an XML representation of the resulting Recordset.

The following is the implementation code for the XML Web service. The Query method does all the work. You can see that this method takes a query string as a parameter and returns a string. As we have discussed previously, this return string contains the XML representation of the Recordset returned by the specified query. This project references ADODB and uses the ADO Connection object directly to execute the query. It would also work just fine with a regular COM object that returns a Recordset; we are just trying to make the sample as clear and concise as possible.

Imports ADODB Imports System.Web.Services <WebService(Namespace:="http://tempuri.org/")> _ Public Class NorthwindDatabase    Inherits System.Web.Services.WebService #Region " Web Services Designer Generated Code "    <WebMethod()> Public Function Query(ByVal queryString As String) _       As String       Dim conn As New Connection()       Try          ' You will need to specify the local path to your copy          ' of the Northwind.mdb file. This is just an example.          conn.Open( "Provider=Microsoft.Jet.OLEDB.4.0;" & _             "Data Source=c:\Northwind.mdb")       Catch e As Exception          Return Nothing       End Try       Dim rs As Recordset       Try          rs = conn.Execute(queryString)       Catch e As Exception          conn.Close()          Return Nothing       End Try       Dim str As New StreamClass()       rs.Save(str, PersistFormatEnum.adPersistXML)       Query = str.ReadText()       str.Close()       rs.Close()       conn.Close()    End Function End Class

After the query has been executed, we use the ADODB Stream class to serialize the contents of the Recordset. (In Chapter 20, we touched on XML serialization for Recordsets and introduced the concept with the RsToString and StringToRS methods.) Notice that there are no particular requirements as to the type of Recordset used. This example uses a forward-only Recordset (which is more than sufficient), but it would work equally well with any kind of client or server-side cursor. Also notice that we close out all the ADO classes (Stream, Recordset, and Connection). Chapter 10 discusses why this step is crucial.

Now that we have the XML Web service, we need something to test it. The test sample, Northwind Viewer, has a couple of interesting features. Not only does it deserialize a Recordset from XML, but it also uses the OleDbDataAdapter to convert the Recordset to an ADO.NET DataTable. It then sets the DataSource property of the QueryDataGrid using the newly created table. That s it, aside from additional initialization code in the form s Load event. We should point out one thing here. We instantiate the XML Web service proxy only once in the Load event, rather than on every button click. This practice is perfectly acceptable because the proxy class does not represent an active network connection. Connections are made only when a method on the class is invoked, so we don t bother creating the same proxy over and over. Creating it once is sufficient. Again, notice that we clean up the ADO objects by calling Close. Always play nice with your COM objects and clean up afterward.

Imports ADODB Imports System.Data Imports System.Data.OleDb Public Class Form1    Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "    Dim nwdb As localhost.NorthwindDatabase    Private Sub Form1_Load(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles MyBase.Load       nwdb = New localhost.NorthwindDatabase()       ' Add the query strings for the database       QueryComboBox.Items.Add("Select * From Categories")       QueryComboBox.Items.Add("Select * From Customers")       QueryComboBox.Items.Add("Select * From Employees")       QueryComboBox.Items.Add("Select * From [Order Details]")       QueryComboBox.Items.Add("Select * From Orders")       QueryComboBox.Items.Add("Select * From Products")       QueryComboBox.Items.Add("Select * From Shippers")       QueryComboBox.Items.Add("Select * From Suppliers")    End Sub    Private Sub ExecuteButton_Click(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles ExecuteButton.Click       Dim xml As String       xml = nwdb.Query(QueryComboBox.Text)       If xml Is Nothing Then          QueryDataGrid.DataSource = Nothing          MsgBox("The query failed!")          Exit Sub       End If       Dim str As New Stream()       str.Open()       str.WriteText(xml)       str.Position = 0       Dim rs As New Recordset()       rs.Open(str)       Dim da As New OleDbDataAdapter()       Dim table As New DataTable()       da.Fill(table, rs)       QueryDataGrid.DataSource = table       rs.Close()       str.Close()    End Sub End Class

Figure 21-8 demonstrates the test application in action. You can see that the user selects a query from the ComboBox and then clicks the Execute button. Another neat feature of this application is that the ComboBox is editable at run time, so you can further customize the query.

Figure 21-8

Northwind Database Viewer application in action.

You should now be able to see how you might get started wrapping your application with XML Web services. Depending on how your application is implemented, it is quite possible to handle the serialization issues without a great deal of disruption. An advantage is that it is extremely easy to create a test XML Web service to discover how your application will behave and what is feasible.



Upgrading Microsoft Visual Basic 6.0to Microsoft Visual Basic  .NET
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET w/accompanying CD-ROM
ISBN: 073561587X
EAN: 2147483647
Year: 2001
Pages: 179

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