UPDATE: This post was written using Xamarin.Android 4.8 and Xamarin.iOS 6.4 business editions in Visual Studio 2012.
Alright everyone, raise your hand if you typically gravitate towards using the latest and greatest tools, libraries, and patterns in the applications you develop. Well, the newest hotness in the world of Xamarin.Android and Xamarin.iOS cross-platform development is the async/await and System.Net.Http.HttpClient support they added in the recent release.
If you’re developing either an Android or iOS application or you’re not using PCLs to share code across platforms then this post probably isn’t for you. If however, you’re like me and targeting multiple platforms (i.e. Windows Phone, Android, iOS) and using a PCL library such as MvvmCross to maximize code reuse, then chances are you’ve spent some hours in NuGet/PCL hell banging your head trying to get async/await working across all platforms.
I’m hoping this post can help others avoid the pain and misery of getting async/await and HttpClient working in their cross-platform application that makes use of PCLs like MvvmCross. This is likely one of many possible configurations that work – it just happened to be the first configuration that worked for me and it wasn’t terribly offensive. Don’t be scared off by the 23 steps listed below – it not really that bad…I’m starting a solution from scratch and being as explicit as possible. So, without further ado, enjoy!
- Create a Portable Class Library project named CrossPlatform.AsyncAwaitHttpClient.Core.Pcl. Target Frameworks: .NET Framework 4.5, Silverlight 4 and higher, Windows Phone 7.5 and higher, .NET for Windows Store Apps, Mono for Android, MonoTouch (if you don’t have Mono for Android and MonoTouch listed as Target Frameworks, read this post: Cross-Platform, WinRT, MonoDroid, MonoTouch, MonoMac, PCLs and VS2012). Delete Class1.cs after the project is created.
- Edit project properties for the CrossPlatform.AsyncAwaitHttpClient.Core.Pcl project you just created and remove “.Pcl” from the Assembly name and Default namespace. Save your changes.
- Install the MvvmCross NuGet package in CrossPlatform.AsyncAwaitHttpClient.Core.Pcl.
- Create a new .NET Framework 4.5 Class Library project named CrossPlatform.AsyncAwaitHttpClient.Core.
- Install the MvvmCross NuGet package in CrossPlatform.AsyncAwaitHttpClient.Core. Delete all files in the project except packages.config.
- Drag the ViewModels folder and App.cs from CrossPlatform.AsyncAwaitHttpClient.Core.Pcl to CrossPlatform.AsyncAwaitHttpClient.Core.
- Add reference to System.Net.Http assembly to CrossPlatform.AsyncAwaitHttpClient.Core.
- Optional: Remove CrossPlatform.AsyncAwaitHttpClient.Core.Pcl project from solution – we just needed it to get App.cs and FirstViewModel.cs files since the MvvmCross NuGet package thinks our plain .NET Framework 4.5 class library is a WPF application.
- If you’re targeting the Windows Phone platform in addition to Android and/or iOS, follow steps 10 – 14 below otherwise skip to 15.
- Create a new Windows Phone Class Library named CrossPlatform.AsyncAwaitHttpClient.Core.Phone.
- Edit project properties for the CrossPlatform.AsyncAwaitHttpClient.Core.Phone project you just created and remove “.Phone” from the Assembly name and Default namespace. Save your changes.
- Install the MvvmCross NuGet package in CrossPlatform.AsyncAwaitHttpClient.Core.Phone. Delete all files added to project except packages.config.
- Install the Microsoft.Bcl.Async and Microsoft.Net.Http NuGet packages in CrossPlatform.AsyncAwaitHttpClient.Core.Phone.
- Create a ViewModels folder in CrossPlatform.AsyncAwaitHttpClient.Core.Phone. Add “Existing Item…” for App.cs and FirstViewModel.cs found in CrossPlatform.AsyncAwaitHttpClient.Core, however, select Add as Link instead of Add.
- Create your client projects for Windows Phone, Android, iOS (i.e. CrossPlatform.AsyncAwaitHttpClient.Phone, CrossPlatform.AsyncAwaitHttpClient.Droid, CrossPlatform.AsyncAwaitHttpClient.Touch).
- Install the MvvmCross NuGet package to each project created in step 14.
- Follow the instructions found in the ToDo-MvvmCross folder of each of your client projects to get them setup with MvvmCross. In the Droid and Touch client projects, add a reference to the CrossPlatform.AsyncAwaitHttpClient.Core project as your MvvmCross Core. Windows Phone projects should add a reference to the CrossPlatform.AsyncAwaitHttpClient.Core.Phone project instead.
- Install the Microsoft.Bcl.Async and Microsoft.Net.Http NuGet packages in your Windows Phone client project.
- Add a reference to the System.Net.Http assembly (C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Net.Http.dll) to your Android client project.
- Add a reference to the System.Net.Http assembly (C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoTouch\v4.0\System.Net.Http.dll) to your iOS client project.
- Update the line in the LinkerPleaseInclude.cs of your iOS project from:
imageView.Image = new UIImage(imageView.Image);
imageView.Image = new UIImage(imageView.Handle);
- Update your FirstViewModel.cs to make a web request using the HttpClient (see example on the Xamarin Developer Center for an example: Async Support Overview).
- Voila! No more head banging.
I hope this walkthrough wasn’t too terrible. I’d be interested in hearing from you if you’ve found a different way of making this all work. What’s interesting is that I first started down this rabbit hole by installing the Microsoft.Bcl.Async and Microsoft.Net.Http NuGet packages across the board – and it worked in Windows Phone and Android but not iOS. Anyway, like I said, let’s compare notes if you have a different approach that works.
You can download the sample solutions here: CrossPlatform.AsyncAwaitHttpClient.zip