Thursday, September 21, 2006

VB.Net: Creating and Consuming a Basic Web Service

I thought it would be fun to start experimenting with Web services a little more. I have, for a while now, been fascinated with the concept of web services and the possibilities they provide. From a business perspective, I can create a web service that is normally provided by a report, let’s say something along the lines of retrieving a transcript for a particular employees training, or for a group of employees for that matter. But, before I can walk, I need to learn to crawl.

For this example, I used the Microsoft Visual Web developer 2005 Express edition to create both the web services used in this example and the client. The requirements to run are an IIS server running .Net 2.0. The web service itself will provide 4 functions:

HelloWorld
Add
Subtract
Divide

Hello world is self explanatory. The remaining 3 functions provide their Integer math equivalent operations and return the results. The client program will only consume two of these functions, the Add function and the Hello World function. The idea is that the client will have 3 text boxes, two will be parameters and the third textbox will display the results. When the user clicks on the button, an alert box will display the results of the Hello World function.

To create the web service itself, from within VWD (Visual Web Designer), I went to file, New Web Site. In the dialog that popped up, I selected ASP .Net Web Service, chose a location, and kept the language as Visual Basic .Net.

The page that comes up is the skeleton of the web service. Fortunately, the Hello World function is already provided. I added the remaining 3 functions, to have the service.vb file below:

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols

<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class MyService
    Inherits System.Web.Services.WebService

    'The generic Hello World function.
    <WebMethod()> _
    Public Function HelloWorld() As String
        Return "Hello World"
    End Function

    'Add two numbers together
    <WebMethod()> _
    Public Function Add(ByVal Num1 As Integer, ByVal Num2 As Integer) As Integer
        Return Num1 + Num2
    End Function

    'Subtract two numbers
    <WebMethod()> _
    Public Function Substract(ByVal Num1 As Integer, ByVal Num2 As Integer) As Integer
        Return Num1 - Num2
    End Function

    'Divide two numbers
    <WebMethod()> _
    Public Function Divide(ByVal Num1 As Integer, ByVal Num2 As Integer) As Integer
        Return Num1 / Num2
    End Function
End Class

You might notice the WebMethod tags. These indicate that the functions are exposed. The other stuff is all auto-generated, so I couldn’t tell you what it does, all I know is it works. To test this, I posted this to my IIS server using the option under the Website/Copy WebSite menu. In the following dialog box, I selected my local IIS server, chose connect, and clicked the button to create a new Web Application.

Once posted, I connected via IE to test, and saw the exposed web services. Now I want to create the client. Using the same project, I confirmed that I did not need to add a new Web Reference. If this was a new project, I would go up to the WebSite/Add Web Reference menu, and point to <webroot>/<project folder>/Service.asmx. It is possible to use the WSDL file as well; however I did not use this in verification.

Graphically the client is simply 3 text boxes and a button. The code looks like so:

<%@ Page Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        'Instantiate the web service object
        Dim ms As New MyService
        
        'Set the results of textbox 3 to the result of the add method in the web service
        TextBox3.Text = ms.Add(TextBox1.Text, TextBox2.Text)
          
        'Create a temporary string containing the script to use a JavaScript popup box
        'Note: I had to seperate the < /script > tag into 3 tagsdue to some strange error where
        'VWD kept wanting
        'to use the that tag to end the code block inside of the web page. Very strange.
        Dim strScript As String = String.Format("<script language='JavaScript'>alert('{0}');<" & "/" & "script>", ms.HelloWorld)
        
        'Check if the script has been registered with the page.
        If (Not ClientScript.IsStartupScriptRegistered("clientScript")) Then
            'Use the newer .Net 2.0 ClientScript.RegisterStartupScript function to
            'register the script. I am using Button1s type as the type indicator
            'however since only 1 object is doing this, I could have used any and it
            'would not have mattered
            ClientScript.RegisterStartupScript(Button1.GetType, "clientScript", strScript)
        End If
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
            <br />
            <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox><br />
            <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
            <br />
            <br />
            <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox></div>
    </form>
</body>
</html>

Some interesting thing to note in the client. First, I am demonstrating how you can call a JavaScript pop-up/alert function from within ASP .Net. This was difficult to find. In searching for this and implementing it, I came across an error with VWD where the </script> tag in the string caused compilation to fail with the error “Statement cannot appear within a method body. End of method assumed”. I thought this was odd since it is inside of a string literal, however VWD did not agree with me. So the solution was to split up the string using concatenations. I wasn’t too thrilled with this since it makes the code look ugly, but I didn’t really have any choice.

Once posted, the program worked like a baby. I think I will see how difficult it is to do the same things with Java next and compare the difficulty between the two. From there, I think I will try to implement a database driven web service.

No comments: