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.

Wednesday, October 2, 2013

Xamarin Android Activities and Intents

One thing that is really important to understand with Xamarin Android development (or just Android development in general) is how activities work and how to navigate between them.  The Xamarin site talks a little about this but it does not really dig deep into the different options for navigating between activities.  That explanation can be found here:

http://docs.xamarin.com/guides/android/application_fundamentals/activity_lifecycle

The most common way to navigate to a new activity is via the StartActivity command.  By default this will create a new activity on the stack.  The Main Activity in an application may create a Second Activity with the following command:

var secondActivity = new Intent(this, typeof(SecondActivity));
StartActivity(secondActivity);

In this case the activity stack looks like this (please excuse the lack of cool graphics):

Second Activity (current)
Main Activity

If the second activity used the StartActivity command in the same way to try and reopen the Main Activity the call stack will look like this:

Main Activity (current)
Second Activity
Main Activity

It will not re-use the existing Main Activity, but it will create a new instance of the Main Activity.  If you press the back button that will pop the latest Main Activity off the stack and return you to the Second Activity but what if you wanted instead to have brought the original Main Activity back to the fore front without creating a new one?  In that case you could have reordered the activities in the activity stack to bring the Main Activity back to the front with the following command:
var mainIntent = new Intent(this, typeof(MainActivity));
mainIntent.AddFlags(ActivityFlags.ReorderToFront);
StartActivity(mainIntent);

If this were called from the Second Activity instead the activity stack would appear as so:

Main Activity (current)
Second Activity

It did not create a new instance of the Main Activity but the Second Activity didn't go away either.  Pressing the back button will now destroy the Main Activity and return to the Second Activity.

The Second Activity could also have just called Finish() instead.  That would have destroyed the Second Activity and returned to the Main Activity similar to what would have happened if the back button were pressed.

There are other options as well.  What if the Main Activity wanted to create the Second Activity and return some information back to the Main Activity without the Second Activity staying on the activity stack?  For this you can use StartActivityForResult:
var secondActivity = new Intent(this, typeof(SecondActivity));
StartActivityForResult(secondActivity, 1);

The second parameter on the StartActivityForResult is a unique identifier that you can use later to identify which activity it was that is returning to the Main Activity.  As you would expect once the Second Activity is created the activity stack would look like this:

Second Activity (current)
Main Activity

It is important to note that the second activity is not a modal window.  It can in turn just re-create a new instance of the Main Activity or a Third Activity or anything else.  When the Second Activity is done you can send some information back to the Main Activity along with if the Second Activity completed successfully.  To do this you can use code similar to this:
Code:
var myIntent = new Intent(this, typeof(MainActivity));
myIntent.PutExtra("My Key", "The data I want to send back");
this.SetResult(Result.Ok, myIntent);
this.Finish();

This will not create a new instance of the Main Activity but return to the existing one.  The intent allows you to send information back to the Main Activity from the Second Activity.  In this case the PutExtra allows you to add key value pairs of information, strings, integers, binary data, etc.  It also uses the SetResult command to indicate that the activity completed successfully.

The question is, now how does the Main Activity use the information passed back from the Second Activity?  That's what the OnActivityResult event is for.  You can implement this event on the Main Activity and it will fire when the Second Activity is finished.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    var returnString = data.GetStringExtra("My Key");
    var result = resultCode;
}

It is important to note that the OnActivityResult event will fire on the Main Activity before the OnRestart event, followed by the OnStart and OnResume events.

If the intent were not passed along to the SetResult command in the Second Activity, the data parameter would be null.  Since it was, we can use functions such as GetStringExtra to retrieve the data that was set in the Second Activity.  The requestCode should have a value of 1 in this case, the value we set when we created the intent to create the Second Activity. 

The resultCode parameter can also be used to tell if the activity was ended successfully.  If the back button was pressed the value of the resultCode would be Result.Cancelled.  Also once the Finish method is called in the Second Activity it is unloaded and removed from the activity stack as you would expect.

I hope this has helped some of you understand how to navigate between activities in Xamarin Android.