Fix: Calling WCF Methods with Parameters Synchronously on Windows Phone 7

Fix: Calling WCF Methods with Parameters Synchronously on Windows Phone 7

In my previous post, Tidying up Windows Phone 7 + WCF Synchronous Programming Model I proposed a base class called SyncClientBase which would make it much easier to call WCF services from a background thread in a synchronous fashion. Unfortunately, whilst this works well for methods that don’t take any arguments, it completely fails when trying to call methods which take parameters. The first step in the Invoke method was to pull apart the Expression parameter in order to determine the async method that was to be invoked and the corresponding event that would be raised.  ie:

    public TResult Invoke<TResult>(Expression<Action> asyncMethod) 
                          where TResult : AsyncCompletedEventArgs {
        var memberExpression = asyncMethod.Body as MethodCallExpression;
        var method = memberExpression.Method;
        var eventName = method.Name.Replace("Async","Completed");
        var evt = Proxy.GetType().GetEvent(eventName);

 

This works, however, when it comes to actually invoking the async method I was passing in an empty object array – clearly not correct when the method takes parameters. On the desktop we could pull the Expression apart even more and actually pull out the arguments that were supplied in the expression tree. However, after playing around a bit I couldn’t work out how to do this without the .NET CF raising a FieldAccessException or two.

I decided to rework the Invoke method a little: Instead of accepting an Action Expression, it now takes a Func<Delegate> Expression (ie a function that returns the method we want to invoke). It also accepts an array of objects which will be the parameters to the async method to be invoked. The full Invoke method looks like:

public TResult Invoke<TResult>(Expression<Func<Delegate>> asyncMethod, params object[] args) where TResult : AsyncCompletedEventArgs
{     var body = asyncMethod.Body as UnaryExpression;     var operand = body.Operand as MethodCallExpression;     var arg = operand.Arguments[2] as ConstantExpression;     var method = arg.Value as MethodInfo;     var eventName = method.Name.Replace("Async", "Completed");     var evt = Proxy.GetType().GetEvent(eventName);     lock (downloadLock)     {         TResult data = default(TResult);         EventHandler<TResult> handler = (s, e) =>         {             data = e;             downloadWait.Set();         };         evt.AddEventHandler(Proxy, handler);         method.Invoke(Proxy, args);         downloadWait.WaitOne();         evt.RemoveEventHandler(Proxy, handler);         if (data.Error != null)         {             throw data.Error;         }         return data;     }
}
 

The proxy class structure still looks very similar. The only difference is that instead of a method call eg Proxy.Step1Async() we’re passing a delegate eg (Action)Proxy.Step1Async. For methods that require a parameter (eg Step3) the parameters are passed in as additional parameters to the Invoke method.

public class Service1Proxy : SyncClientBase<Services.Service1Client, ServiceTester.Services.IService1>, DemoService.IService1 {     public int Step1() {
        return base.Invoke<Step1CompletedEventArgs>(() => (Action)Proxy.Step1Async).Result;
    }
 
    public int Step2() {
        return base.Invoke<Step2CompletedEventArgs>(() => (Action)Proxy.Step2Async).Result;
    }
 
    public int Step3(int xyz) {
        return base.Invoke<Step3CompletedEventArgs>(() => (Action<int>)Proxy.Step3Async,xyz).Result;
    }
}
 

The only issue with this structure is that there is not validation that the correct number and type of parameters are passed into the Invoke method. Other than that, it’s still quite an elegant wrapper.

Tidying up Windows Phone 7 + WCF Synchronous Programming Model

Tidying up Windows Phone 7 + WCF Synchronous Programming Model

In my previous post, Windows Phone 7 and WCF Don’t Play Nicely, I talked about how you could overcome some of the shortcomings of working with the generated WCF proxy classes in Windows Phone 7. I wasn’t particularly happy with the workaround I posted so I gave it some more thought and decided to go back a step.

If we look at our WCF service that we’re connecting to it is made up of two parts: the interface definition and then the service implementation. In our case they’re very simple:

[ServiceContract]
public interface IService1 {
    [OperationContract]
    int Step1();
 
    [OperationContract]
    int Step2();
}
 
public class Service1 : IService1{
    public int Step1() {
        return 1;
    }
 
    public int Step2() {
        return 2;
    }
}
 

When we generate the service reference in our Windows Phone 7 application we end up with the following methods and events:

    void Step1Async();
    void Step2Async();
    public event EventHandler<Step1CompletedEventArgs> Step1Completed;
    public event EventHandler<Step2CompletedEventArgs> Step2Completed;
 

And just to remind you, we want to get to code that looks as simple as:

public void RunInBackground(Action callback) {
    var proxy = new Service1Proxy();
    var r1 = proxy.Step1();
    var r2 = proxy.Step2();
}
 

Here’s the trick – we’re going to start with another base class that is going to do the synchronous wrapping of our service method request. Essentially this follows the same pattern as what you would have seen with the ServiceHelper class from my previous post. However, in this case the parameter to the Invoke method is an Expression that references the asynchronous service call (eg “Invoke<Step1CompletedEventArgs>(()=>Proxy.Step1Async())” ) . From this expression we can pull out the name of the method to be invoked (eg “Step1Async”) and use that to determine the name of the corresponding event that will get raised when the service request completes (eg “Step1Completed”). The event name can be used to get a reference to the event itself, which we can then wire an event handler to in the same way that the ServiceHelper worked.

public class SyncClientBase<TClientBase, TServiceInterface> : IDisposable
    where TClientBase : ClientBase<TServiceInterface>, TServiceInterface, new()
    where TServiceInterface : class {
 
    public TClientBase Proxy { get; private set; }
    public SyncClientBase() {
        Proxy = new TClientBase();
    }
 
 
    private static object downloadLock = new object();
    private static AutoResetEvent downloadWait = new AutoResetEvent(false);
 
    public TResult Invoke<TResult>(Expression<Action> asyncMethod) 
                          where TResult : AsyncCompletedEventArgs {
        var memberExpression = asyncMethod.Body as MethodCallExpression;
        var method = memberExpression.Method;
        var eventName = method.Name.Replace("Async","Completed");
        var evt = Proxy.GetType().GetEvent(eventName);
        lock (downloadLock) {
            TResult data = default(TResult);
            EventHandler<TResult> handler = (s, e) => {
                data = e;
                downloadWait.Set();
            };
            evt.AddEventHandler(Proxy,handler);
            method.Invoke(Proxy, new object[] {});
            downloadWait.WaitOne();
            evt.RemoveEventHandler(Proxy, handler);
            if (data.Error != null) {
                throw data.Error;
            }
            return data;
        }
    }
 
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    protected virtual void Dispose(bool disposing){
        if (disposing) {
            if (Proxy != null) {
                downloadWait.Set();
                Proxy = null;
            }  
        }
    }
}
 

But how does this complex bit of code get us any closer to where we want to be. Well firstly this code is boilerplate code which doesn’t need to be modified for each new service reference we add. However, we do need to create another proxy class which inherits from SyncClientBase for each of our service references:

public class Service1Proxy: SyncClientBase<Services.Service1Client, 
                                           ServiceTester.Services.IService1>, 
                            DemoService.IService1 {
    public int Step1() {
        return base.Invoke<Step1CompletedEventArgs>(()=>Proxy.Step1Async()).Result;
    }
 
    public int Step2() {
        return base.Invoke<Step2CompletedEventArgs>(()=>Proxy.Step2Async()).Result;
    }
}
 

There are some points to note about this proxy:

– Service1Proxy inherits from SyncClientBase where the type arguments are Service1Client, which is the proxy that is generated when you do Add Service Reference, and IService1, which is also generated when you add the service reference.

– Service1Proxy implements DemoService.IService1 which is the original service interface definition, not Services.IService1 which is generated when you Add Service Reference. You’ll need to add this file to your Windows Phone 7 application (if you add it as a link then when you change your service definition it will automatically be updated in your Windows Phone 7 project).

– For each method defined in the DemoService.IService1 the implementation follows the same pattern:

public int Step1(){     return base.Invoke<Step1CompletedEventArgs>(()=>Proxy.Step1Async()).Result;
}

>> “Step1CompletedEventArgs” – This is the type parameter for the event that will be raised when the service request completes. In the case of Step1Async the corresponding event is Step1Completed which is of type EventHandler<Step1CompletedEventArgs>
>> “() => Proxy.Step1Async()” – This is an Action delegate that invokes the service request you want to call. In this case the Step1Async method is going to be called.
>> “.Result” – This just extracts the actual result data out of the event args and the type should match the return type of the method. In this case the Step1 method returns an integer so the Result property returns an integer value.

Wrapping this all up we get the following simple code to run on our background thread to invoke a sequence of service requests:

public void RunInBackground(Action callback) {
    using (var proxy = new Service1Proxy()) {
        var r1 = proxy.Step1();
        var r2 = proxy.Step2();
    }
}

All you have to do is make sure the Service1Proxy class stays up to date (ie add/modify/delete appropriate methods to make sure it matches IService1) and you have a nice wrapper for calling your services in a synchronous manner on a background thread without blocking the UI thread at all.

Windows Phone 7 and WCF Don’t Play Nicely

Windows Phone 7 and WCF Don’t Play Nicely

There area a number of ways you can access data from within your Windows Phone 7 application. These include using base level classes such as HttpWebRequest and the WebClient but you can also use WCF from within your application. The advantage of using WCF is of that Visual Studio 2010 can generate the necessary strongly typed proxy classes for you. All you need to do is click “Add Service Reference”, enter the url for the service you want to import and off you go. You can now write code that connects to a WCF service… happy days…. fail

Unfortunately it attempting to make life easier for noobie developers the Silverlight/Windows Phone 7 teams have managed to create a rod for almost any serious developer who wants to work with WCF Services. I’ll cover this in two parts as follows:

Async Methods Suck!

If you’ve worked with Silverlight on the desktop or WP7 then you’ll probably have noticed that nearly all methods that perform a network operation are asynchronous. This is true of the base HttpWebRequest class, the WebClient and WCF proxy classes. Conceptually this is quite a good idea as it forces developers to think asynchronously and write code that doesn’t block the UI thread. This in theory should lead to responsive applications.

What this doesn’t take into consideration is that developers who have done a programming 101 course understand the use of multiple threads. If you spin up another thread to do background tasks such as synchronisation then all of a sudden you’re going to find yourself fighting the async programming model that’s been thrust on you.

What we want to be able to do is something like:

Service1Client client = new Service1Client();
public void RunInBackground(){
    client.Step1();
    client.Step2();
}
 

What we end up with instead is:

Service1Client client = new Service1Client();
public void RunInBackground(Action callback) {     
    client.Step1Completed += client_Step1Completed;     
    client.Step1Async(callback);
}
 
void client_Step1Completed(object sender, Step1CompletedEventArgs e) {     
    client.Step1Completed -= client_Step1Completed;     
    client.Step2Completed += client_Step2Completed;     
    client.Step2Async(e.UserState);
}
 
void client_Step2Completed(object sender, Step2CompletedEventArgs e) {     
    client.Step2Completed -= client_Step2Completed;     
    var callback = e.UserState as Action;     
    callback.Invoke();
}
 

Note that the RunInBackground takes an Action as a callback. This is passed along with the various WCF method calls so that it can be invoked when all of the services have completed. Notice how untidy this code is and just how difficult it is to read and maintain.

There are ways to beat Silverlight into shape to make it easier to do a sequence of service calls on a background thread. For example the following ServiceHelper class means that I can call the sequence of Step1 and Step2 in a synchronous fashion. Note that this is done on a background thread.

void MainPage_Loaded(object sender, RoutedEventArgs e) {         
    ThreadPool.QueueUserWorkItem(async => RunInBackground());
}
 
Service1Client client = new Service1Client();
public void RunInBackground(){
    ((Action)client.Step1Async).ServiceCall<Step1CompletedEventArgs>(             
            handler => client.Step1Completed += handler,             
            handler => client.Step1Completed -= handler);
    ((Action)client.Step2Async).ServiceCall<Step1CompletedEventArgs>( 
            handler => client.Step2Completed += handler, 
            handler => client.Step2Completed -= handler); 
}

 
public static class ServiceHelper {     
    private static object downloadLock = new object();     
    private static AutoResetEvent downloadWait = new AutoResetEvent(false);     
    public static T ServiceCall<T>(this Action serviceCall, 
                                     Action<EventHandler<T>> addHandler, 
                                     Action<EventHandler<T>> removeHandler) where T : AsyncCompletedEventArgs {         
        lock (downloadLock){             
             T data = default(T);             
             EventHandler<T> handler = (s, e) =>
             {
                 data = e;
                 downloadWait.Set();
             };
          addHandler(handler);             
             serviceCall();             
             downloadWait.WaitOne();        
             removeHandler(handler);             
             if (data.Error != null) {                 
                 throw data.Error;             
             }             
             return data;         
        }     
    }
}

 

WCF Implementation Sucks!

A nasty surprise awaits those attempting to use WCF on Windows Phone 7. What it little understood is that the proxy classes that Visual Studio generates (which inherit from ClientBase) has some awful code behind it that will flick execution back onto the Main/UI thread. As you saw previously each WCF service call is made up of an asynchronous method call, with a completed event that is raised when the service call returns. This event is raised on the Main/UI thread. This means that if you’re doing any sort of processing (eg writing the response to disk before displaying it) you will accidentally block the UI thread!!!

I’m sorry to say this is one of the worst architectural decisions I’ve seen in a long time and is a hidden cause for so many applications performing badly. There are a couple of solutions:

1) Use HttpWebRequest and use a REST API on the server

2) Jump off the UI thread in each event handler, do the processing and then jump back to UI thread to update the UI.

3) The ServiceHelper shown earlier automatically passes back off to the background thread.

Windows Phone 7, Android and iOS with Mono VII: Database

Windows Phone 7, Android and iOS with Mono VII: Database

Previous posts in this series:

Mono I: Getting Started
Mono II: Basic Navigation
Mono III: Shared Libraries
Mono IV: Webservices
Mono V: Content and Resource Files
Mono VI: File Access

Not only do you want to be able to write to the file system, for more complex applications you will want to write to a relational database.

Windows Phone 7

There is currently no support for Microsoft’s own lightweight database engine, SQL CE. However, there is a port of Sqlite that will work nicely with Isolated Storage.

– Go to CodePlex and download either the source code or just the assemblies for the Sqlite project (http://wp7sqlite.codeplex.com). If you download the assemblies you just need to add them as a reference to your WP7 application project. I prefer to have the source code handy in case something goes wrong. In this case simply add the two Sqlite projects to your solution and add a reference to both projects to your WP7 application project.

– Once you’ve added the sqlite references, all you need to do is write a bit of code to create the database, tables and insert records. Of course you’ll want to validate that the data exists. The following code was taken, and modifies slightly, from the documentation on Codeplex but illustrates all of these operations.

private void CreateSqlLite(string connectionString)
{
     using (SqliteConnection conn = new SqliteConnection(connectionString)) {
         conn.Open();
         using (SqliteCommand cmd = conn.CreateCommand()) {
             cmd.CommandText = "CREATE TABLE test ( [id] INTEGER PRIMARY KEY, [col] INTEGER UNIQUE, [col2] INTEGER, [col3] REAL, [col4] TEXT, [col5] BLOB)";
             cmd.ExecuteNonQuery();
             cmd.Transaction = conn.BeginTransaction();
             cmd.CommandText = "INSERT INTO test(col, col2, col3, col4, col5) VALUES(@col, @col2, @col3, @col4, @col5);SELECT last_insert_rowid();";
cmd.Parameters.Add("@col", DbType.Int32);
             cmd.Parameters.Add("@col2", DbType.Int32);
             cmd.Parameters.Add("@col3", DbType.Double);
             cmd.Parameters.Add("@col4", DbType.AnsiString);
             cmd.Parameters.Add("@col5", DbType.Object);
             for (int i = 0; i < 100; i++)
             {
                 cmd.Parameters["@col"].Value = i;
                 cmd.Parameters["@col2"].Value = i;
                 cmd.Parameters["@col3"].Value = i * 0.515;
                 cmd.Parameters["@col4"].Value = "สวัสดี な. あ · か · さ · た · な · は · ま · や · ら · わ. 形容詞 hello " + i;
                 cmd.Parameters["@col5"].Value = Encoding.UTF8.GetBytes("สวัสดี");
                 object s = cmd.ExecuteScalar();
             }
             cmd.Transaction.Commit();
             cmd.Transaction = null;
             cmd.CommandText = "SELECT * FROM test";
             using (SqliteDataReader reader = cmd.ExecuteReader())
             {
                 while (reader.Read())
                 {
                     //var bytesValue = (byte[])reader.GetValue(5);
                     //var intValue reader.GetInt32(0);
                     //var doubleValue = reader.GetDouble(3);
                     //var stringValue = reader.GetString(4);
                 }
             }
             conn.Close();
         }
     }
}
 

The only thing left for you is to call this method supplying the connection string to use. For example the following will create a database file called test.db within IsolatedStorage on the device.

CreateSqlLite("Version=3,uri=file:test.db");

 

 

iOS

The MonoTouch sdk includes support for Sqlite so all you need to do is reference Mono.Data.Sqlite (right-click the Android application project and select Add References) and System.Data.

– Now from your code you can pass in the full path (within the Personal special folder) of the database file you want to create and work with.

string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test.db"); 
if (File.Exists(dbPath)) File.Delete(dbPath);
CreateSqlLite("Data Source=" + dbPath);

 

Note I: that this uses exactly the same CreateSqlLite method that the WP7 application uses.

 

Android

The MonoDroid sdk includes support for Sqlite so all you need to do is reference Mono.Data.Sqlite (right-click the Android application project and select Add References) and System.Data.

– Now from your code you can pass in the full path (within the Personal special folder) of the database file you want to create and work with.

string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test.db");  if (File.Exists(dbPath)) File.Delete(dbPath);
CreateSqlLite("Data Source=" + dbPath);
 

Note I: that this uses exactly the same CreateSqlLite method that the WP7 application uses.

Note II: Be careful if you’re using “clever” Visual Studio addins like resharper as they can be overly helpful. When I added a reference to System.Data it decided to add a reference to System.EnterpriseServices which is a .NET 4 library and clearly not designed to work with MonoDroid. This caused me no end of frustration  – I ended up going through all the references in my MonoDroid projects looking for references that were not MonoDroid specific.

Windows Phone 7, Android and iOS with Mono VI: File Access

Windows Phone 7, Android and iOS with Mono VI: File Access

Previous posts in this series:

Mono I: Getting Started
Mono II: Basic Navigation
Mono III: Shared Libraries
Mono IV: Webservices
Mono IV: Content and Resource Files

In the previous post we covered including files in your application that could be accessed at runtime. The flipside of this is being able to write to files, and as you may have expected there are some subtle differences between WP7 and the two Mono platforms.

Windows Phone 7

WP7 applications are limited to writing to files located within Isolated Storage. The following code illustrates creating the User Store and then opening a file.

using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using(var file = store.OpenFile("test.txt", FileMode.Create,FileAccess.Write))
using(var strm = new StreamWriter(file))
{     strm.Write("Contents to write to the test file");
}

 

iOS

– Writing to files via MonoTouch is done via the Personal special folder, as per the following example

string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal); 
string filePath = Path.Combine(path, "test.txt");
using (var file = File.Open(filePath, FileMode.Create, FileAccess.Write))
using (var strm = new StreamWriter(file))
{
strm.Write("Contents to write to the test file");
}

Android

Writing to files on MonoDroid should also be done via the Personal special folder, as per the following example

string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);  string filePath = Path.Combine(path, "test.txt");
using (var file = File.Open(filePath, FileMode.Create, FileAccess.Write))
using (var strm = new StreamWriter(file))
{     strm.Write("Contents to write to the test file");
}

Windows Phone 7, Android and iOS with Mono V: Content and Resource Files

Windows Phone 7, Android and iOS with Mono V: Content and Resource Files

Previous posts in this series:

Mono I: Getting Started
Mono II: Basic Navigation
Mono III: Shared Libraries
Mono IV: Webservices

Quite often you’ll want to include files within your application as resources or assets that can be loaded at runtime. For example images, fonts, strings or text files. In this post we’ll cover some of the ways that you can do this across the three platforms.

Windows Phone 7

There are two main ways to include files with your Windows Phone 7 application, as resources or as content. The primary difference is that files included as resources are compiled into the assembly, where as content files are packaged into the xap and deployed alongside your application on the device. Upshot is that resources load slightly quicker, because they’re already in memory, but that they can adversely affect the load time of your application. General rule of thumb on the .NET Compact Framework (which SL for WP7 sits over) is that the larger the assemblies, the longer it takes for the application to load.

Resource files

– Right-click on the wp7 application project (ie NicksNetTravels) in Solution Explorer. Select Add > Existing Item.

– Locate the file you want to add as a resource (in this case SimpleTextFile.txt located in the root folder of the application) and click Add

– Press F4 or open the Properties window and make sure the Build Action is set to Resource (some files default to Content, whilst others will default to Resource).

– In the MainPage.xaml.cs add the following code to read out the contents of the resource file:

using (var strm = App.GetResourceStream(
   new Uri("/NicksNetTravels;component/simpletextfile.txt",UriKind.RelativeOrAbsolute)).Stream)
using(var reader = new StreamReader(strm)) {
var txt = reader.ReadToEnd();
}
 

Note the format of the Uri: The first bit is the assembly name (ie NicksNetTravels) and then the second bit, after component,  is the path to the resource file (ie /simpletextfile.txt”). If you can’t work out the path to the resource I’d suggest using Reflector to open the application assembly and check to make sure your resource is there.

image

Open the .g.resources node and view the resources. Double-click to open them in notepad and view their contents.

image

Content files

– Right-click on the wp7 application project in Solution Explorer. Select Add > Existing item.

– Locate the file you want to add as content (in this case SecondTextFile.txt again located in the root folder of the application) and click Add

– This time make sure the Build Action is set to Content.

In a lot of cases you can reference content files directly by name (for example you can set the Source property of an Image control to “new Uri(“SecondTextFile.txt”, UriKind.Relative)” and it will be able to locate the file. However, if you want to read directly from the file you’ll need to reference the Microsoft.Xna.Framework assembly so that you can make use of the TitleContainer class.

– Right-Click on the WP7 application project, select Add Reference. Find and select Microsoft.Xna.Framework and click Add.

– In the MainPage.xaml.cs add the following code to read out the contents of the file:

using(var strm = TitleContainer.OpenStream("SecondTextFile.txt"))
using (var reader = new StreamReader(strm)) {
    var txt = reader.ReadToEnd();
}
 

You will probably need to add “using Microsoft.Xna.Framework;” to the top of this file too in order to get it to compile.

 

iOS

I’m sure there are probably other alternative ways to package files with your iOS application but this is the way that I’ve found/used so far (please add a comment if you know of another way):

– Right-click the iOS application project in the Solution window of MonoDevelop. Select Add > Add Files. Locate and select the file you want to include and click Open (SimpleTextFile.txt).

– Right-click the newly added file and make sure the Build Action is set to content.

Screen shot 2011-04-09 at 10.03.26 AM

Now, in your code you can access this file as follows:

var name = Environment.CurrentDirectory + “/SimpleTextFile.txt”;
using(var file = System.IO.File.Open(name,System.IO.FileMode.Open,System.IO.FileAccess.Read))
using(var reader = new System.IO.StreamReader(file)) {
    var txt = reader.ReadToEnd();
}

Note that we’re just opening a file using standard file IO commands. The file we added as content gets placed into the CurrentDirectory of the application.

 

Android

In your Android application there is quite a nice model for accessing resources. By default when you create a new project with MonoDroid you will see a Resources folder with a number of sub-folders. Each of these sub folders represents a different type of resource. For example the Drawable folder is used for images – when you access them you will use a Drawable object so that the image can be rendered to the screen. Similarly the Layout folder is used to store your Views for your application. One sub-folder that appears to be missing from the default project structure was the Raw folder. This is particularly useful as it is used for any files that you want to be able to access as a raw stream.

image

– If the Raw sub-folder does exist under the Resources node, right-click the Resources node and select Add > New Folder and call it Raw.

– Right-click the Raw sub-folder and select Add > Existing Item. Find and select the file you wish to add and click the Add button.

If you look at the Properties window for the newly added item you should see that the Build Action is set to AndroidResource. Build your solution – this is required to generate the designer wrapper for accessing the resource from code.

– Add the following code to your application to read the contents of this file

using (var strm= Resources.OpenRawResource(Resource.Raw.SimpleTextFile))
using (var reader = new StreamReader(strm)) {
    var content = reader.ReadToEnd();
}
 

Note that the reference to Resource.Raw.SimpleTextFile is checked at compile time to ensure the resource exists (rather than having to specify a string literal and hope you’ve got the name right).

And there you have it, content/resource file access across the three platforms.

MonoDroid v1 and MonoTouch v4 Released

MonoDroid v1 and MonoTouch v4 Released

Miguel has posted a great summary of the newly released versions of MonoTouch and MonoDroid (officially release for production now!). This is a major step forward in being able to target multiple platform with roughly the same code base. I’ve done a couple of posts covering the basics of getting started across three mobile platforms, wp7, Android and iOS. Check them out:

Mono I- Getting Started
Mono II- Basic Navigation
Mono III: Shared Libraries
Mono IV: Webservices

Feedback always appreciated

Windows Phone 7 Template for Social Reading Applications

Windows Phone 7 Template for Social Reading Applications

Over the past couple of weeks I’ve been working with Dave Gloveron a Visual Studio template that you can use to create simple reader style applications. You can combine RSS/Atom, Facebook Pages and Twitter feeds into a single application. Mix and match how you want the data to be combined, and customise the UI to your hearts content.

Anyhow, the full details have been posted on Dave’s post Windows Phone 7 Social Viewer Application Template Released

Windows Phone 7, Android and iOS with Mono IV: Webservices

Windows Phone 7, Android and iOS with Mono IV: Webservices

In this series so far:
Mono I- Getting Started
Mono II- Basic Navigation
Mono III: Shared Libraries

Now that you’ve got a simple application up and running it’s time to think about accessing data. We’re going to jump in the deep end and look at how to consume a web service. In this case I’ve created a vanilla WCF service with the following definition (just using the WCF Service Application template in Visual Studio):

[ServiceContract]
public interface IService1 {    
    [OperationContract]
    string GetData(int value);
}
 

Note I: I’ve created this service in a new solution in an instance of Visual Studio 2010 running as administrator. I did this because I wanted to run the service in IIS so that it can be accessed from multiple computers (so that the iphone/simulator on my Mac can access it). See the following image to configure the service to run on IIS.

image

Note II: Because I’m running this service in IIS 7 with .NET 4 there is almost no configuration for this service in the web.config file. What this does mean is that because I’m publishing this service over HTTP the default binding is the basicHttpBinding. As with Silverlight and the .NET Compact Framework, there is only support for basicHttpBinding (or the webHttpBinding if you want to roll your own web requests).

 

Windows Phone 7

Adding this service to your Windows Phone 7 application is unbelievably simple. However, to make it slightly more complex we’re going to add the service into our shared library. This way we can have our service logic in a common place across all three platforms.

– Right-click the shared library (BuiltToRoam.General) and select Add Service Reference

– Enter the address of the wcf service (eg http://localhost/SimpleService/Service1.svc” and hit Go. This should return the service information. Give it a namespace (eg Services) and click OK.

image

This will generate a folder called Service References, a number of files that contain the proxy classes for the referenced service and a ServiceReferences.ClientConfig file, which includes endpoint configuration information about the service.

– Add the following code to the MainPage.xaml.cs code behind file.

Service1Client client=new Service1Client(); 
public MainPage() {
     InitializeComponent();
     client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(client_GetDataCompleted);
     client.GetDataAsync(5);
}

void client_GetDataCompleted(object sender, GetDataCompletedEventArgs e) {
     var result = e.Result;
}

Put a breakpoint on the last line of the above code and run the application. What you should notice is that the application will fail throwing an exception. This is because we haven’t told the application the endpoint or binding to use for the service request. Normally this would be specified in the ServiceReferences.ClientConfig file which would be automatically added to the application when adding the service reference. However in this case because we added the service reference to a class library we need to make sure we include the ClientConfig file in the application.

– Right-Click the WP7 application project node (ie BuiltToRoam) and select Add >Existing Item. Navigate to the shared library (ie BuiltToRoam.General) and select the ServiceReferences.ClientConfig file. Do NOT click the centre of the Add button. Instead click the down arrow on the right side of the Add button. Then select Add as Link.

image

Note: This is important because if we update the service reference in the future we don’t want to have to remember to update additional copies of this file.

– F5 to build and run – this should run smoothly (if not, make sure IIS and the service application are running smoothly).

 

iOS

From the iOS application to call our wcf service we can reuse the proxy classes that we just generated.

– Right-click on the shared library (BuiltToRoam.General.iOS) and select Add > Add Files. Select all the files in the Service ReferencesServices folder and click Open. This will add the proxy files to the project with the appropriate build actions.

– Check that the shared library builds – I had to add a reference to the System.ServiceModel assembly at this point (right-click References and select Edit References; from the Packages tab select System.ServiceModel and click OK). You will probably want to add this assembly and System.Xml.Linq to the References for the iOS Application project too.

– Right-click the iOS application project and select Add > Add Files. Locate the ServiceReferences.ClientConfig file that is situated in the shared library project folder. Click Open to add this file – this will display a dialog prompting you to add as a Link or Copy the file. You want to ensure we only have a single copy of this file, so select the Link option

– You need to set the Build Action of the ServiceReferences file you’ve just linked to Content. Do this by right-clicking the file and setting the Build Action directly in the context menu.

 

Screen shot 2011-04-08 at 12.01.01 PM

– Now, all you need to do is write some code to read the configuration file, setup the proxy client and call the service.

Service1Client client;
public MainPageController (IntPtr p) : base (p) {
    EndpointAddress endpoint;
    var name = Environment.CurrentDirectory + “/ServiceReferences.ClientConfig”;
    using(var file = System.IO.File.Open(name,System.IO.FileMode.Open,System.IO.FileAccess.Read))
    using(var reader = new System.IO.StreamReader(file)) {
        var xml =XElement.Load(reader);
        endpoint = (from ep in xml.Descendants(“endpoint”)
                             select new EndpointAddress(ep.Attribute(“address”).Value)).FirstOrDefault();
    }
    client = new Service1Client(new BasicHttpBinding(),endpoint);
    client.GetDataCompleted+=new EventHandler<GetDataCompletedEventArgs>(client_GetDataCompleted);
    client.GetDataAsync(5);  
}

private void client_GetDataCompleted(object sender, GetDataCompletedEventArgs e) {
    var result = e.Result;
}

Note: The Environment.CurrentDirectory is a reference to the location on disk where Content files get copied to when the application gets installed on the device. From there you can open it and use a bit of Xml parsing to read out the endpoint configuration value

Set a break point in the client_GetDataCompleted method to confirm the service call works

 

Android

To make use of the same wcf proxy classes we generated earlier we need to a) add the appropriate files to the shared library and b) add the service configuration to the Android application project.

– The first step is relatively straight forward: In Solution Explorer select the shared project (BuiltToRoam.General.Android) and toggle the Show All Files button in the toolbar of the Solution Explorer window, so that files that aren’t currently part of the project are shown.

– Right-click on the Service References folder and select Include in Project. You can now toggle Show All Files to hide the excluded files again. You should end up with a structure in the shared library similar to the following.

image

The Android application project should already have a reference to the shared library from what we did in the previous posts. However, it’s missing the wcf service configuration file, ServiceReferences.ClientConfig. Unfortunately you can’t just add this to the project and expect it to work, which is what we did in the wp7 case. It’s a little more involved…

– Right-click the shared library project and select Properties. Go to the Build Events tab and add the following Post-Build event:

xcopy “$(ProjectDir)ServiceReferences.ClientConfig” “$(ProjectDir)….NicksNetTravelsAndroidNicksNetTravelsAndroidResourcesRaw” /y

To break this down the Post-Build event commands will get run after this project has been built. In this case we’re copying the ServiceReferences file from the shared library project directory to the ResourcesRaw sub-folder of the Android application project directory.

– Build the solution, and then toggle the Show All Files option for the Android application project. This should reveal the ServiceReferences.ClientConfig file within the Raw directory. If an error is thrown during the build to do with the xcopy command, you may have either got the path wrong (source or destination), or the Raw folder may not exist, in which case you need to create it.

– Right-click the ServiceReferences.ClientConfig file and select Include In Project. Make sure that the Build Action (in the Properties window) is set to AndroidResource

This has included this file as a raw resource that can be accessed from within the Android application. Now in the body of Activity1 we’ll need to open this resource, read out the wcf service configuration which we can use when creating the instance of the proxy.

Service1Client client;
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);

EndpointAddress endpoint;
using (var inputStream = Resources.OpenRawResource(Resource.Raw.ServiceReferences))
using(var reader = new StreamReader(inputStream))
{
var xml = XElement.Load( inputStream));

endpoint = (from ep in xml.Descendants("endpoint")
select new EndpointAddress(ep.Attribute("address").Value)).FirstOrDefault();
}
client = new Service1Client(new BasicHttpBinding(), endpoint);
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(client_GetDataCompleted);
client.GetDataAsync(5);
}


void client_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
var result = e.Result;
}
 

We could have just created the EndpointAddress in code but that would mean that we’ve got it hard coded within the application. By reading the contents of the ServiceReferences file we’re at least keeping the wcf service configuration information in a single file for all three platforms.

– Set a breakpoint in the client_GetDataCompleted method to see the result returned from the service.

Android Frustrations

Android Frustrations

This evening I spent a number of hours chasing my tail.  All I wanted to do was to debug the very simple Android application. I figured all I would have to do is go ahead and purchase MonoDroid (you can only debug using the emulator with the evaluation license, which is painfully slow and periodically breaks). Unfortunately this was not the case.

It turns out that my Samsung Galaxy S which is less than a year old is running Android v2.1 which is too old for the MonoDroid toolkit. I then spent the next hour fighting Samsungs poor excuse for a desktop application, Kies. It doesn’t help that the new version (v2) isn’t compatible with their less than a year old devices. I then managed to locate an older version (v1.5) which was compatible but for the life of me I couldn’t get my device to connect to the software. Finally after tweaking all sorts of things I got it to connect only to discover that the software didn’t have an update for my Galaxy S. ARGH.

Ok, back to basics – lets just get a cooked ROM and apply that. Sure enough I found instructions on how to a) root my Galaxy S and then to b) install Android 2.3.3:

How to Root Samsung Galaxy S

http://www.pathikshah.com/blog/root-samsung-galaxy-s/

Install Android 2.3.3 Gingerbread on Samsung Galaxy S

http://www.pathikshah.com/blog/install-android-2-3-3-gingerbread-on-samsung-galaxy-s/

After doing all that I now have a device I can debug to from Visual Studio 2010 using MonoDroid. This is way way way too painful, but to be expected from Google and Android.

Windows Phone 7, Android and iOS with Mono III: Shared Libraries

Windows Phone 7, Android and iOS with Mono III: Shared Libraries

We’ve got the basics functioning across all three platforms but at the moment we’ve written all our code within the confines of three different projects with no code shared between them. Of course, one of the reasons for using MonoTouch/MonoDroid is to try to reuse and share as much code as possible between the platforms. That and hopefully we don’t need to spend too much time writing obnoxious Java or Objective-C code.

Now we could simply share files between the three projects, after it’s just .NET code but I want to be a little more adventurous. I’m going to create a class library that each of my three platform projects can access. Now I’m actually going to have platform specific class library project files, but the rest of the files contained within the project will be common across all projects.

Unfortunately I don’t know of an easy way to do this, so I’ll show you the long way – if someone does know an easier way to do this, please let me know because this way is painful.

Windows Phone 7

– Add a new project to your Windows Phone 7 application based on the Windows Phone Class Library template. In my case my shared library is going to be called BuiltToRoam.General but rather than leave it in the solution folder, I’m going to go up a level, create a folder called Shared and create the project in there. This will give me a folder structure as follows:

CrossPlatform
    Shared
        BuiltToRoam.General
    NicksNetTravels
    NicksNetTravelsAndroid
    NicksNetTravelsiOS

– In the new project rename Class1.cs to Utility.cs and add the following simple extension method:

namespace BuiltToRoam.General {     
  public static class Utility {         
    public static T EnumParse<T>(this string enumValue, bool ignoreCase = true) where T : struct {
             try {
                 if (string.IsNullOrEmpty(enumValue)) return default(T);
                 return (T)Enum.Parse(typeof(T), enumValue, ignoreCase);
             }
             catch {
                 return default(T);
             }
         }
     }
}

As you can probably work out all this method does is parse a string and return the appropriate enumeration value (strongly typed of course!).

– Right-click your Windows Phone 7 application project in the Solution Explorer window and select Add Reference; Select the BuiltToRoam.General project and add it as a reference.

– Now, just to test that this works, modify the MainPage constructor (in MainPage.xaml.cs) as follows:

public enum Wp7EnumTest {
First,
Second
}
 
public MainPage() {
InitializeComponent();

var test = ("First").EnumParse<Wp7EnumTest>();
}
 

– Build and run. Set a breakpoint after the EnumParse line to check that this works.

 

iOS

This is where it starts to get messy. Essentially you want to create an empty project stub for both iOS and Android. You can’t call them the same as the WP7 project because then you’ll end up with a file conflict; yet if you give them a different name they’ll create a new project folder which won’t contain the same files. There are actually two options here: Option 1 is that you just live with the fact that you’ll have multiple project folders – Visual Studio allows you to add files as links which means that you can have the files in one project (eg the Windows Phone 7 project you just created) and then as links in the iOS and Android projects. Option 2, which I prefer, is to create the project stubs with a slightly different name, and then move them into the same directory as the Windows Phone 7 project file. Then you can add literally the same files as the projects will be in the same folder. Here I’m going to go with Option 2, so if it didn’t make sense when I described it, then hopefully it will by the end of this.

– In MonoDevelop, right-click the Solution node in the Solution window and select Add > Add New Project. Select the MonoTouch Library Project from under the C# > iPhone and iPad node. Give you project a name, in this case BuiltToRoam.General.iOS, and click Forward to create the new project.

– Right-click the newly created project and select Delete (this might seem odd since what we actually want to do is to remove it from the solution, rather than deleting the project). When prompted, select “Remove” from the dialog (if you select “Delete from Disk” it will do just that, which is not what we want).

– In Finder, locate the newly created project file (in this case BuiltToRoam.Genera.iOS.csproj) and move it from where it was created into the shared project folder (in this case SharedBuiltToRoam.General).

– Back in MonoDevelop, right-click the Solution node. This time select Add > Add Existing Project and navigate to the shared project folder and select the project you just moved.

– Right-click the References folder of your iOS application project (ie NicksNetTravelsiOS) and select Edit References. Select the Projects tab and check the box alongside the shared project you just added (ie BuiltToRoam.General.iOS).

– Right-click the shared project and select Add > Add Files. Select Utilities.cs and click Open to add the file to your project

– Modify the code in Main.cs to include the following code to test the code in the referenced assembly works.

public enum iOSEnumTest{
    First,
    Second
}
 
public class Application  {
  static void Main (string[] args) {
   var test = (“First”).EnumParse<iOSEnumTest>();

   UIApplication.Main (args);           
  }
}

– Again, set a breakpoint after the EnumParse line to validate that this code works.

Note: You may find that your breakpoints aren’t hit for some reason. This may be because you’re running without attaching the debugger. To run with the debugger select Run > Run With > Mono Soft Debugger for iPhone

 

Android

Ok, last one. We’re going to follow basically the same process over again. Perhaps I should make a project template for this….. volunteers?

– File > Add > New Project. Select the Mono for Android Class Library from the Mono for Android node. Give your project a name, in this case BuiltToRoam.General.Android, and click OK to create the class library.

– Like we did in the iOS case: Right-click on the newly created project and click Remove. Find the project file (ie BuiltToRoam.General.Android.csproj) in Windows Explorer and move it into the shared project folder.

– Right-click the solution node in Solution Explorer and select Add > Existing Project. Locate the shared project file and click Open to add it to the solution.

– Right-click the Android application project and select Add Reference. Select the Projects tab, select the BuiltToRoam.General.Android project and add it as a reference.

– Right-click the shared project file and select Add > Existing Item. Find Utilities.cs and click Add.

– To verify that this works, add the following code to Activity1.cs

public enum AndroidEnumTest {
    First,
    Second
}

protected override void OnCreate(Bundle bundle) {
    var test = (“First”).EnumParse<AndroidEnumTest>();
    …
}

– Set a break point after the EnumParse line to verify this works.

So there you have it, the ability to share whole projects between WP7, Android and iOS. It wasn’t that hard after all.

Windows Phone 7, Android and iOS with Mono II: Basic Navigation

Windows Phone 7, Android and iOS with Mono II: Basic Navigation

When I’m building a mobile application one of the first things I want to get right is the flow of navigation. My demo cross platform application is no different. So the first thing to do is to work out how each of the navigation systems work, how to control it from C# code and of course wire up a simple navigation.

Windows Phone 7

Yeh, so this one should be easy since I’m so familiar with it. Essentially the navigation model is that an application is made up of a series of pages. To proceed within the application you make a call to Navigate and supply the relative Uri of the page that you want to navigate to. When the user presses the Back button the default behaviour is for the application to return to the previous page. If they press the Back button on the first page of the application, the application will be terminated.

– Add a new page to the application (Right-click the project in Solution Explorer > Add > New Item)

image

– Select the Windows Phone Portrait Page, give it a name, SecondPage.xaml, and click OK

– Add a button to the first page of the application (ie to MainPage.xaml)
  > Double-click MainPage.xaml in solution explorer to open it
  > Find “<Grid x_Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″></Grid>” and replace with

<StackPanel x_Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
    <Button Content=”Go To Second Page”
            Click=”SecondPageClick” />
</StackPanel>

– Right-click anywhere in the MainPage.xaml code/design window and select View Code

– Add the following code into the MainPage class. This is the event handler for the button you just added and causes the application to navigate to the second page.

private void SecondPageClick(object sender, RoutedEventArgs e) {
    this.NavigationService.Navigate(new Uri(“/SecondPage.xaml”, UriKind.Relative));
}

– F5 to run the application. Click the “Go To Second Page” button an note that a new page is displayed. Click the Back Button (bottom left of emulator) to return to the main page. Click Back again to exit the application.

image image

 

 

iOS

– Double-click MainWindow.xib to open it in Interface Builder

– From the Library window (Tools > Library if not already visible) drag a Navigation Controller element onto the MainWindow.xib

image

In order to reference this Navigation Controller from within your code you’re going to need to create an Outlet. You can think of this as a backing variable (although not strictly the same) to allow you to reference this element from code.

– In the Library window, select the Classes tab; Select AppDelegate from the list; Select Outlets from the AppDelegate sub-window.

– Click the + button, and give the new outlet a name, rootNavigation

Screen shot 2011-04-05 at 4.21.26 PM

– Lastly you need to wire the Navigation Controller to the outlet you just created. Select the App Delegate node in the MainWindow.xib window – the Inspector window (Tools > Inspector if not already visible) will update to display information about the App Delegate. Select the App Delegate Connections tab (second one from left) to display the list of outlets available and then drag the empty ring from alongside rootNavigation across onto the Navigation Controller node in MainWindow.xib.

image

We’ve wired up the navigation controller, the last thing to do in order to get the application to display something when we run it (if you recall from when we initially created this application there was nothing displayed on screen when we ran it) is to add the Navigation Controller as a sub-view of the main application window.

– Save changes in Interface Builder and return to MonoDevelop

– Open Main.cs and uncomment and update the line that starts // window.AddSubView (~line 25) to the following:

window.AddSubview(rootNavigation.View);

If you run at this point you will now see a heading of Root View Controller at the top of your application. We now need to add a button which will invoke the navigation to a new view.

– Go back to Interface Builder and find the Navigation Controller window. From the Objects tab of the Library window, drag a View object into the main area of the Navigation Controller window. The newly created View should take up the majority of the window, displacing the “View” placeholder.

– Again from the Library window, drag on a Round Rect Button. Resize the button across the top of the view area, and in the Inspector window change the Title property to read “Go To Second View”

We’ve created both the initial view and a button within the view. Now we need to be able to reference the button from code so that we can wire up an event handler to when the user taps the button. To do this we extend the view controller (if you look in the MainWindow.xib you will see that nested under the Navigation Controller node is a View Controller node) so that when an instance is created, we can wire up an event handler for the button click.

– In the MainWindow.xib window. Select the View Controlller (Root View Controller) node and then switch to the Identity tab of the Inspector window.

– Set the Class value to be MainPageController (we need to give the controller a name here so that we can write code in a code-behind file for a partial class with the same name).

– In the Library window, select the MainPageController on the Classes tab. Then select Actions from the MainPageController dropdown.

– Click the + button to create a new Action (think of actions as event handlers) and call it navigationButtonClick

Screen shot 2011-04-05 at 5.30.35 PM

– Switch over to the MainWindow.xib window; Select the Rounded Rect Button and find the Touch Down connector on the Connections tab of the Inspector window.

– Drag the circle alongside the Touch Down connector across onto the Main Page Controller node of the MainWindow.xib window. When prompted click on the navigationButtonClick action to complete the wiring up process. This has wired up the Touch Down event on the button to the navigationButtonClick action.

image

So now all we need is some code to be invoked when that action occurs. This is where Mono comes in – it’s already created a stub for us. All we need to do is to fill in the code.

– Switch back to MonoDevelop and create a new class file, MainPageController.cs, based on the Empty Class file template. Replace the contents of the file with the following.

using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace NicksNetTravelsiOS {
  public partial class MainPageController: UIViewController {
    public MainPageController (IntPtr p) : base (p) { }
 
    partial void navigationButtonClick (UIButton sender) {
    }
  }
}

Note that the MainPageController is a partial class, and the navigationButtonClick method is a partial method. The class and method definitions are in the MainWindow.xib.designer.cs file and are automatically generated by MonoDevelop (don’t hack around in the designer generated files!!!)

Ok, to round out this we’re going to need another view to switch in when the button is clicked

– In MonoDevelop select File > New > File; Select the iPhone View with Controller template; give it a name, SecondPageController and click New.

– Open the MainPageController.cs file and modify the navigationButtonClick event handler you created earlier.

private SecondPageController secondPage;
partial void navigationButtonClick (UIButton sender) {
  if(secondPage==null){
    this.secondPage = new SecondPageController();
  }

this.NavigationController.PushViewController(secondPage,true);
}

– Build and run this and when you click on the button, the second view will animate in.

Screen shot 2011-04-05 at 5.50.06 PM Screen shot 2011-04-05 at 5.50.15 PM

 

 

Android

The initial application that we created already comes with a button on the first view in the application. All we need to do is add a second view and navigate to it. Ok, just to be clear on the terminology here: In an Android application there are views and activities – and you should think of them in the context that an activity manages the current view and that you can either transition views within the current activity, or you can transition between activities. In this case we’re actually going to do the latter which will involve creating both an additional activity and a corresponding additional view.

– In the Solution Explorer window, right click on the Layout node; Select Add > New Item; Select the View template and give it a name, SecondPage; Click Add

– Next we need to add an additional activity, so right-click the project node and select Add > New Item; Select the Activity template and give it a name, Activity2

– Update the Activity2 class in Activity2.cs as follows. This sets the SecondPage view as the current view for Activity2

[Activity(Label = "My Activity")]
public class Activity2 : Activity
{
protected override void OnCreate(Bundle bundle){
base.OnCreate(bundle);     SetContentView(Resource.Layout.SecondPage);   }
}
 

– The last thing to do is to add the navigation from Activity1 to Activity2, which is in Activity1.cs. Change the delegate for the Click event to the following:

button.Click += delegate { StartActivity(typeof(Activity2)); };
 

– Press F5 to build and run

image image

 

And there you have it – basic navigation across all three platforms. Not that they all use slightly different conventions but all support some level of “back” operation. On Windows Phone 7 it’s a dedicated hardware back button, Android has a back button in the on screen menu area (or I believe it can be a hardware button) and iOS has it as part of the navigation controller on screen infrastructure.

Windows Phone 7, Android and iOS with Mono I: Getting Started

Windows Phone 7, Android and iOS with Mono I: Getting Started

Over the past couple of months I’ve been thinking more about how to share resources between applications written for WP7, Android and iOS. Increasingly companies that I consult with are asking how they can build an application once and have it run across multiple platforms. My belief is that this isn’t easily achievable and even if it is would lead to a poor user experience on one or  more platforms.

The reality is that whilst functionality the platforms all offer similar capabilities and services, they don’t all share the same user experience. This means that we’d want to be able to customise how our applications look and behave on the different platforms. Enter the world of Mono.

MonoTouch and MonoDroid not only allow you to write c# code to address iOS and Android respectively, they also provide wrappers for a large proportion of the core apis and controls. Essentially this means that I could write my business logic once in C# and then have the UI component done in a way that is native to the platform I’m targeting. With iOS this would be via Interface Builder, WP7 using Blend and then for Android my understanding is that I’m left writing UI markup in XML (how surprising….).

In this series I’m going to try to share some of the pain/success/difficulties I experience in building the same application across three platforms.

Let’s get started, so what do we need:

Development and Design Tools

Windows Phone 7

– Development tools (Free): Visual Studio 2010 + Expression Blend (http://create.msdn.com)
– Register for developer program/marketplace ($100AUD): Register

iOS

Note: Make sure you following the instructions on the MonoTouch website re installation
Development tools (Free): XCode + Interface Builder (http://developer.apple.com/devcenter/ios)
– MonoTouch ($399USD):  http://monotouch.net/
– Register for developer program/app store ($99USD): Register

Android

Note: Make sure you following the instructions on the MonoDroid website re installation
– Development tools (Free): Java JDK, Android SDK
– MonoDroid (public beta): monodroid-download
– Register for developer program/market ($25USD): Register

Don’t forget for the iOS component you’re going to need to go buy a Mac to use.

First Applications

 

Windows Phone 7

Launch Visual Studio 2010

– File > New > Project
  > Select Windows Phone Application template under Silverlight for Windows Phone node
  > Enter name of project: NicksNetTravels
  > Click Ok

image

– Make sure Windows Phone Emulator is selected as deployment device (in Standard toolbar)

– F5 to build and run. This will launch the Windows Phone 7 Emulator, deploy the app to it and run it.

image

 

iOS

– Launch MonoDevelop

– File > New > Solution
  > Select  iPhone Window-Based Project under the iPhone and iPad node
  > Enter name of solution: NicksNetTravelsiOS (my applications are going to reside in the same folder, so it’s important that they are named slightly differently).

Screen shot 2011-04-05 at 3.16.50 PM

– (Apple key, or Windows key if using an MS keyboard) + Alt + Enter – build and run application. This will launch the simulator, deploy and run the application

Screen shot 2011-04-05 at 3.23.06 PM

Android

Launch Visual Studio 2010

– File > New > Project
> Select Mono for Android Application template under Mono for Android node
> Enter name of project: NicksNetTravelsAndroid
> Click Ok

image

– F5 to build and run. This will launch the “Select Device” window.

image

– Click “Start emulator image”

image

– Click OK to launch the MonoDroid emulator (this should have been created during installation – see MonoDroid installation instructions. If not, you’ll just need to follow those instructions now by clicking the Create new emulator image link).

Note: The first time I did this the process failed with some cryptic error. I pressed F5 again, selected the existing emulator instance and it seemed to work fine.

image