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.

Thursday, September 19, 2013

The other day I spoke a little about some of the features included in Csla.Axml.Android.  Another feature it gives you is an easy way to pass a copy of a CSLA object between activities without doing a lot of work.

As you may know when moving from one activity to another in android you cannot simply pass an object by reference.  To get around this you can store a reference of your object in a static variable but global type variables are generally considered anti-patterns.  A better approach is to serialize the object and receive a copy of it in the target activity.  This can be done a variety of ways such as implementing Java.IO.ISerializable, json serialization, etc.  Doing this can lead to varying levels of work on your part.

To serialize and send a copy on a CSLA object from an Activity that inherits from the Csla ActivityBase, use the SeirializeModelForParameter method:

var projectResourceListActivity = new Intent(this, typeof(ProjectResourceList));
projectResourceListActivity.PutExtra(Constants.EditParameter, this.SerilizeModelForParameter());
StartActivity(projectResourceListActivity);


This method takes whatever is in the current view model's model property and serializes it using the mobile formatter.  If you need to send along a different object you can simply pass a reference to it as a parameter in the SerializeModelForParameter(objectIWantToSerialize) command instead.

To reconstitute the object on the target activity you can use a different method on the activity, DeserializeFromParameter.  A good place to do that might be in the activity's OnCreate event:

Library.ProjectEdit projectEdit;
var serializedProjectEdit = Intent.GetByteArrayExtra(Constants.EditParameter);
if (serializedProjectEdit != null)
{
    projectEdit = (Library.ProjectEdit)this.DeserializeFromParameter(serializedProjectEdit);
}

That's all their is too it!

Monday, September 16, 2013

CSLA Xamarin Android

As some of you may have heard, Rocky Lhotka, creator of the CSLA framework has been beset by some rather serious medical issues.  We've known each other for quite some time and it's really quite disconcerting to see someone who has always had boundless professional energy to be out of action for a while.  I'm sure it's quite a bit more disconcerting to him as he's a person that is used to being constantly active and working.

He was about to release a new version of CSLA that included a working port to Xamarin Android.  I had been working on that on and off for quite some time.  The version that is currently in the CSLA GitHub fork is currently has the core portions working in the master branch.  That can be found here:

Official CSLA Github Fork

The version in my fork has some updated UX helpers to extend the default activity and add a level of data binding.  Currently the data binding is still rudimentary but effective.  This can be found here:

Latest CSLA Xamarin Android Source

The UX helpers can be found in the Csla.Axml dll.  The following are some of the things that can be done with it:

Like other CSLA UX helpers there is a view model base that you can use to reshape your CSLA models in a way that is appropriate for a particular view.  These ViewModels expose out an underlying Model property that refers to a CSLA model and allows you to extend and add references to other models as needed.  The syntax to create such a class is as so:

public class ProjectResourceEdit : Csla.Axml.ViewModel<Library.ProjectResourceEdit>

This will strongly type the Library.ProjectResourceEdit class to the generic parameter of the ViewModel.  As expected any calls to ProjectResourceEdit.Model will be of type Library.ProjectResourceEdit.  A wide range of the capabilities you find with the CSLA ViewModel for other UX technologies will also be available with the CSLA Xamarin Android ViewModel.

Another abstract class you can use from the Csla.Axml dll is the ActionBase.  This will strongly type your action to a CSLA view model you have created as above.  It will also give you limited data binding abilities.  To use the ActivityBase simply inherit from it instead of the standard Activity class.  Additionally, provide type information for the ViewModel and associated Model you would like to use.

public class ProjectResourceEdit : ActivityBase<ViewModels.ProjectResourceEdit, Library.ProjectResourceEdit>

Currently activation of the data binding can be done manually in the model, though I have future plans of allowing it to be set directly in the axml.  To bind up a control simply use the following code:

this.Bindings.Add(Resource.Id.txtResourceAssigned, "Text", this.viewModel.Model, "Assigned");

This code assigns the Text property of the TextView with the id of txtResourceAssigned to the associated model's Assigned property.  This property will be initially displayed in the text view and updated back to the Assigned property when the txtResourceAssigned TextView looses focus. Additionally bindings can be created with references to custom functions that can coerce/convert values back and forth from your model/view model to a control on the axml layout.

When moving from a view to move to another control such as clicking a button the binding is sometimes not updated as the original control still has focus.  This is particularly problematic for save buttons.  To force bindings to be updated use the following method in the click event for your save button:

this.Bindings.UpdateSourceForLastView();

Finally,  when getting back a new reference to your model from the data portal you may need to clear your bindings and update them to point to the new instance of your model object.  The bindings can be cleared simply by making the following call:

this.Bindings.RemoveAll();

That's it for today.  In the next post I will discuss how the UX helpers can assist you in passing your model from one activity to another as you cannot pass models by reference between views.