Using a Web Service

From $1
Table of contents

MonoTouch can consume SOAP-based web services in the same way that .NET 1.0 and 2.0 applications did using the System.Web.Services.dll functionality.   This small How-To explains how to get started with web services and how to make your application responsive while consuming SOAP-based web services.

Setup

Step 1: Using the System.Web.Services.dll assembly

To consume web services, you need to add to your project the System.Web.Services.dll assembly.  You need to reference this assembly in your project;   If using MonoDevelop, right-click on "Reference" in your solution and pick "Edit References", then select ".NET Assembly" and pick the System.Web.Services.dll assembly from the /Developer/MonoTouch/usr/lib/mono/2.1 directory and click the add button.

At this point, you will have the assembly that can invoke web services included in your project.   

Step 2: Consuming a Web Service from a WSDL file.

Web Services publish description files in the form of a WSDL document (this is an XML document that describes the callable API).   To consume one of these, right click on your project and select "Add Web Reference".  

The dialog that pops up will allow you to enter the URL to a WSDL description file.   Enter the url here, once the dialog fetches the WSDL it will preview the published API.  It should look like this:

AddWebReference.png

If you are not using MonoDevelop, but instead just want to use the command line tools, you would use the "wsdl" command line tool that is part of Mono, and this will generate the web service file for you.

If you want to learn more about how to consume a WSDL file, read Microsoft's Creating an XML Web Service Proxy document.

Step 3: Invoking the Web Service

At this point, you can just create an instance of the generate class that was generated by MonoDevelop (or the wsdl tool if you used the command line).   Intellisense will be active, so you will be able to invoke methods directly.

Sample

If you want to try a web service yourself, you can do this by creating a sample web service like this, call the file "TestService.asmx":

<%@ WebService Language="c#" Class="WebServiceTests.TestService" %>

using System;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace WebServiceTests
{
	public class TestService : System.Web.Services.WebService
	{
		[WebMethod]
		public string Echo (string a)
		{
			return a;
		}

		[WebMethod]
		public int Add (int a, int b)
		{
			return a + b;
		}
	}
}

Then you can run Mono's ASP.NET web server like this:

$ xsp2
Listening on address: 0.0.0.0
Root directory: /tmp
Listening on port: 8080 (non-secure)
Hit Return to stop the server.

That will launch a web server on your localhost on port 8080, you can browse the web service using Safari by visiting: http://localhost:8080/TestService.asmx

To consume the web service, select "Service Description" and then the link that says "Download", the url will look like this: http://localhost:8080/TestService.asmx?wsdl=0

In MonoDevelop, enter that URL in the "Add Web Reference" option, then on your code, you can type the following:

var service = new TestService ();
var result = service.Add (10, 20);

The above will invoke the remote TestService and return the result. In this case, it will merely add the numbers.

The generated class "TestService" derives from the SoapHttpClientProtocol you can invoke various methods and properties on it to configure it (changing the url, configuring the cookies, the user agent, the proxy to use, client certificates and much more). 

Using Web Services Responsibly

Remember that Web Services might take a long time to respond, or they could fail because the host might be unreachable or because the network connection went down.  

The API shown above "service.Add" was a synchronous invocation.   In general, you do not want to do this in applications that must repond to use input because they might block the user from interacting with your application until the web service either responds, or the call fails.

If you are planning on using the synchronous API, make sure that you do this work from a new thread or using the WebService provided asynchronous APIs.

Using the WebService Async Methods

Mono generates two class of methods in addition to the synchronous method. For example, in addition to Add, the following methods are generated: AddAsync and BeginAdd.

Using the async pattern means that you invoke the BeginFoo method and pass it a callback that will be invoked when the invocation has completed.   Your callback then invokes the "EndFoo" method to fetch the result or any errors.  A full explanation is available on Microsoft's Communicating with Web Services Asynhronously page.   Here is how you would use it:

void Run ()
{
    var t = new TestService ();
		
    // Pass "t" as the state to our callback.
    t.BeginAdd (10, 20, callback, t);
}

void callback (IAsyncResult iar)
{
    TestService ts = (TestService) iar.AsyncState;
    int result = ts.EndAdd (iar);

    // Since we are running on a separate thread, we can not access
    // UIKit objects from here, so we need to invoke those on the
    // main thread:
    InvokeOnMainThread (delegate {
        result.Text = "Result: " + res;
    });
}

The above pattern works great for large methods, but for quick hacks, you can use the C# 3.0 syntax:

void Run ()
void Run ()
{
    var t = new TestService ();
    
    t.BeginAdd (10, 20, delegate (IAsyncResult iar) {
        int result = t.EndAdd (iar);

        InvokeOnMainThread (delegate {
            result.Text = "Result: " + res;
        });        
    }, null);
}

The second asynchronous pattern, uses the FooAsync methods that are generated in the stub. These hide the details about IAsyncResult and casting and instead use strong typed event arguments for the results:

void Run ()
    var t = new TestService ();

    // Connect the event
    t.AddCompleted += AddCompleted;
    // Start the request, will run on a separate thread
    t.AddAsync (10, 20);
}

void AddCompleted (object sender, AddCompletedEventArgs args) 
{
    // The result is in args.Result:

    InvokeOnMainThread (delegate {
        result.Text = "Result: " + args.Result;
    });
}

Using threads.

If you want to manage the threads yourself or perhaps if you want to batch multiple operations in one, you would use something like this:

void Run ()
{
    var t = new Thread (doWork);
    t.Start (54);
}

void DoWork (object arg)
{
    // Get the parameter (54 in this sample)
    int value = (int) arg;

    var res = TestService.Add (value, 10);

    // Since we are running on a separate thread, we can not access
    // UIKit objects from here, so we need to invoke those on the
    // main thread:
    InvokeOnMainThread (delegate {
        result.Text = "Result: " + res;
    });
}

 

 

Tag page

Files (0)

 
Page last modified 05:14, 2 Oct 2009 by Miguel