Tuesday, October 22, 2013

Connecting to Web Services with Xamarin Android in Visual Studio

If you do any type of mobile development you are likely to want to connect to some type of external service somewhere and this is no less true of Xamarin Android.  If you write line of business applications you will almost always need to access a service for data persistence.  For public cloud offerings there is always Microsoft's Azure mobile Services (perhaps more on that in a later post).  But if you want something in a web service you wrote for your own application then you will need to know how to connect to it.

There are three general ways to connect to an external web service in Xamarin Android when using Visual Studio: 
  • Use the built in "Add Web Service" tool
  • Use SlSvcUtil.exe
  • Access directly through code
The first method is the easiest but in some ways the most limiting.  To use it simply right click on the project and select Add Web Reference.  When you do the following screen will appear:


The most common choices here are to either enter in the path to an existing service or to click on Web Services in the solution.  Clicking on the later choice will show any services that may exist in your solution:


If you select a service you can name it and add a reference just like you can with the .Net version of this utility.  However, that's as far as your control goes.  Unlike the .Net version you have no control over what list object types are returned as they are always returned as arrays.  Additionally, with the .Net version if your service returns a serialized object and your client project has a reference to it, then you can generate a client proxy that desterilizes into that type.  That is also not available with the "Add Web Service" tool in the Xamarin Android projects, even if you have a reference to a Xamarin version of the Dll with the exact same types that are returned by the service.

This is important because the types being returned from the service may be more than simple DTOs.  They may be business objects with associated business logic.  For any custom types such as these the "Add Web Service" utility will simply generate dumb stubs with the public properties of the original Types.  You will then have to manually move them in and out of instances of your business objects through code as you fetch and save information from your service.

What if I do have serialized types being returned from my WCF service and I want them to appear as their respective types inside my Xamarin Android client because I want all the business logic and I don't want to engage in a manual mapping process?  What if any time I return more than one instance of that type I want them to be contained in an ObservableCollection instead of a array like I can with the .Net version of the tool?  That's where the SLSvcUtil.exe comes in.  This tool comes with Silverlight and can do much of what the full .Net SvcUtil.exe can.

For a little background you may ask how do we get our types to be both returned from our .Net WCF service and also be recognized in our Xamarin Android project?  One way is to have a .Net version of the DLL and a Xamarin version.  If they both have the same namespace, version and share the same class files then the serialization and deserialization routines won't know the difference.  This is a common trick in .Net cross platform development.  Another option is portable class libraries.  For more on this look at the Xamarin cross platform documentation:


If you have both of those Dlls is that enough?  No, you must create a third; a Silverlight version.  This will also have the same namespace, version and share the same class files.  The reason for this is simple, the SLSvcUtil is a Silverlight utility and expects to reference Silverlight assemblies.

Here is an example of running SLSvcUtil at the command prompt to use types in a specified assembly and specify the return type of multiple objects to be in an ObservableCollection:


 Let's take a look at some of the parameters on that command:

 - The first parameter is the address of service that we are generating a proxy for, in this case http://localhost:63367/GravesiteService.svc.
- The /o: parameter told the command where to write the generated proxy. 
- The /l: parameter specified the language to generate the client proxy for; cs == C#.
- The /n: parameter maps all service namespaces (*) to the namespace to be used for the proxy, SampleAndroidUX.TypedGravesiteService.
- The /r: parameter gives the full reference paths to any Silverlight dlls that you need for your proxy.  In this case we use the parameter twice.  The first time to reference the Silverlight version of the class library containing the returned types from the service.  The second time to reverence the Silverlight version of the System.Windows.dll that contains ObservableCollection.
- The /ct: parameter specifies the collection type to use, in this case ObservableCollection`1.  The `1 at the end tells it to use the proper type for the generic ObservableCollection.

Once I have run this command successfully a new file has been added to the output directory, TypedGravesiteService.cs.  I can now simply add this file to my Xamarin Android project to use it as a generated client proxy.

Using it is similar to using the "Add Web Reference" proxy.  The Silverlight utility would normally expect to load connection information from config files and you will see such a file has been generated in the same directory as you ran SLSvcUtil.exe from.  Alternatively you can also configure and run the client proxy directly.  Consider the following method:

public static GravesiteServiceClient CreateGravesiteService()
{
    return new GravesiteServiceClient(new BasicHttpBinding(), new EndpointAddress("http://addresstomyservice"));
}

The important thing to note here is that we were able to specify some parameters such as where our service resides.  Of course if this were a "real" application we would not hard code our server endpoint URL into the code, but instead get it as a configuration value or from a string resource.

How could we use the newly created proxy?

public Task<ObservableCollection<Town>> GetAllTownsAsync()
{
    var tcs = new TaskCompletionSource<ObservableCollection<ITown>>();
    var service = TypedWCFService.CreateGravesiteService();
    service.GetAllTownsCompleted += (s, e) => tcs.TrySetResult(e.Result);
    service.GetAllTownsAsync();
    return tcs.Task;
}

A few things to note in this sample function.  First we can see that the Silverlight proxies still do not use the new task-based asynchronous pattern (TAP).  We could wrap the client proxy call in a method using the TaskCompletionSource as above to convert to the new TAP asynchronous model.  The second thing you may notice is that the result that we are getting out of e.Result is an ObservableCollection<Town>, exactly the .Net type that is being returned by our .Net WCF service, now in a Xamarin Android version of the class.  Exactly what we wanted to do.

That should get you started on using the first two methods of using web services inside a Xamarin Android project.  I will not cover the third technique here, accessing them through code, as that could easily be another blog post and isn't particularly unique to Xamarin Android development.

I hope this information has helped you consume web services in Xamarin Android.

4 comments:

  1. Hi,

    'm stuck at some point and can't find the way out. Can you provide me with some working demo ?

    ReplyDelete
  2. Hi,
    I would like to ask about xamain PCL project with web service (asmx). I used the proxy class like your example and can connect to my webservice, however, if user switch from mobile network to wifi or wifi to mobile network, my application can't connect to web service again. unless close the app and open again then can connect. Do you know, how do i fix this issue?

    Thanks in advanced.

    ReplyDelete