TLDR: I did a session on x-plat apps focusing on using Xamarin and Azure Mobile Services. I had some demo issues (some my fault some not). This post explains everything and links to the code.
This year at Build, I did a session on Building Cross-Platform and Line of Business Apps with Azure Mobile Services. Joining me for the session was Donna Malayeri who is a Program Manager on Mobile Services. The goals for the session were two: show off the new offline capabilities in the .NET SDK for Mobile Services and demonstrate how developers can use Xamarin to build cross-plat apps that take advantage of Line of Business or enterprise capabilities. Donna focused primarily on the offline area of the session and did a great job of demonstrating the differences between the normal data access in the SDK and the offline access, how and when you should use offline, and how to handle conflicts. My demos on the other hand had a few issues. My hope is to walk through how to reproduce what I was demoing as well as to point out the issues I ran into and how to overcome them.
Xamarin’s iOS Build Host
One of the biggest pain points in demoing Windows Store and iOS apps at the same time is actually deploying to either an iOS device or simulator. Let me step back and explain in more detail. If you’re building a solution with a Windows Store, Windows Phone, Android, and iOS project in them (i.e. a really cross-platform app) then you (currently) HAVE to build from Visual Studio. With Xamarin installed, you can build a Windows Store / Windows Phone / Android project with no issues. However, in order to build the iOS app, you have to pair your Windows machine with an OS X computer running the Xamarain.iOS Build Host. The Build host allows you to send instructions from Visual Studio to build an app or deploy to a simulator or device. Unfortunately, as of today, this system is not without it’s quirks. You have to be running the same version of Xamarin.iOS on both computers, you can’t pair with more than one open instance of Visual Studio, the connection can get screwed up, etc. It’s a big flakey. Even now I’m suffering from an issue where I can deploy to the iOS Simualtor but not a connected device (still no idea why). This was one of the issues I ran into and unfortunately, I still don’t have a solid fix for it. The best alternative I’ve found is to put my code into Git after changing it on the Windows machine, then pull it down on the OS X machine, and then open the solution in Xamarin Studio on iOS. Xamarin Studio won’t be able to load the Windows Store or Windows Phone projects, but you can build and run the iOS project without issues. Hopefully Xamarin will continue to make the Build Host better and this problem will disappear.
Making a Mobile Services PCL
The first thing I demoed was taking a Windows Store project and an iOS project and creating a new Portable Class Library that contains the Mobile Services code. The take away from this is that you can truly share your code (or at least most of it) across your different client platforms. The Mobile Services team has made a lot of strides toward making this step really simple. Unfortunately, there is a small issue affect the BCL libraries that makes a small modification necessary. Thankfully it’s quite easy to fix things. First, from Visual Studio you should have your solution with the different client projects present. Note that if you decide to start off with the WinStore and Xamarin.iOS quickstart projects from the Mobile Services page, you’ll want to remove the nuget for Mobile Services from the WinStore project and the Mobile Services component from the Xamarin.iOS Project.
Next, add a new project to your solution and choose Portable Class Library. You’ll next be asked to select what platforms you want your PCL to support:
Select whichever platforms you want to support here. One thing you’ll notice is that once you select either Xamarin.Android or Xamarin.iOS, you’ll get a warning that says they are both going to be selected because you don’t need anything additional to support both versus just one. Once you’ve added the project, you can then add a reference to the PCL from your client projects (right click on Project and choose Add, Reference).
The next step is to drop in Mobile Services. For this, right click on your Solution and go to Manage NuGet Packages for Solution. Search for Azure Mobile and choose to install the Mobile Services package:
Next, you’ll be asked which projects you want to install to. Make sure you select your PCL and your client projects. You’ll then get a license acceptance window. Finally, the package and it’s dependencies will be installed. If you build right now you’ll see a few errors for An assembly with the same identity has already been imported. This occurs for System.IO, System.Runtime, and System.Threading.Tasks but only for the iOS and Android projects. Go ahead and remove the references to those libraries from your iOS and Android project and you should be able to compile. We still need to make two changes for our application to work though. The first change requires replacing the contents of the app.config that is generated for the iOS and Android project. The contents of those files should look like this:
Now that that’s done, we can make the last change. In your iOS project’s AppDelegate class, put CurrentPlatform.Init() at the bottom of the FinishedLaunching method. For your Android project, place the same code somewhere in your main Activity. Now you should be able to compile and run your app on all of the platforms and then proceed to start making use of Mobile Services from the PCL.
Adding Azure Active Directory Auth and handling project specific code
One of the interesting things about using PCLs and Xamarin is that even though we can put a LOT of our code into the PCL so it’s shared, we still can’t put everything. One clear example of that is the UI and code that is called directly by the UI (i.e. event handlers). Using Mobile Services built in authentication is another example. To understand why, it’s helpful to step back and understand how that auth works.
Mobile Services allows you to do two forms of authentication: client side and server side. On the client side, you use a SDK provided by the auth provider (i.e. Facebook, Google, Microsoft, Twitter) to allow the user to login. Your app then gets whatever key and secret is returned by the provider. You can then pass this information to your Mobile Service and the service will give you back a user ID and auth token you can use to make secure calls to your service. The server flow presents a web view to the user which loads a URL on your Mobile Service which in turn redirects the user to a login page on the provider’s site. This flow uses something called OAUTH. No matter which one you choose, you’re left NEEDING to do client specific code. In the server flow, each platform has a specific way of presenting the web view and each Mobile Services client library has a method specifically for that platform. For Windows Store and Windows Phone apps, you don’t need to pass any context to the UI when you authenticate (the Mobile Services Client knows what it needs to). However, for iOS you have to pass over the currently displayed UIViewController. For Android, you have to pass over the current Activity (context). For this reason, to authenticate we need to have some client specific code.
So the question becomes, how do we do this in a way that makes sense and is extensible. What I like to do is add an abstract class to my PCL named PlatformSpecific:
There are a few methods here to handle logging information (logging is another platform specific implementation) but the important method is the Authenticate method. This method returns a MobileServiceUser (i.e. our authenticated user) and takes in two objects. We take in two generic objects because we are going to pass in objects from our platform specific projects which the other projects don’t know about. For example, from iOS we’ll pass in a UIViewController for the uiObject, but the WinStore, Android, and WinPhone projects wouldn’t know what that is. Once you’ve done that then you can add a class to each of your client projects that has the code for that specific platform. Here’s the iOS code:
Note that we’re casting the uiObject to a UIViewController and passing it in to the LoginAsync method that is defined in the iOS Ext library for Mobile Services (automatically added when we added the NuGet). The Android, Windows Store, and Windows Phone versions will look similar but appropriate for their platforms.
What’s great about doing this in our platform specific classes is now we can still trigger the authentication from our shared PCL code. Our PCL has a reference to a PlatformSpecific object which is set by each of our client projects. So in our PCL, we can use this code:
First we check to make sure the CurrentUser isn’t already set (i.e. they aren’t already logged in) and then we call the platform specific implementation of Authenticate which in turn calls back to our client project!
Handling Push Notifications with Notification Hubs
Push notifications are an interesting area of any client app development. From the client side, it varies from super easy to mildly complicated. The server side is absolutely terrible if you have to develop it all yourself. Thankfully, Azure Notification Hubs makes the server side (and some oft he client side) super easy. There isn’t a library we can use (that I know of) that prevents us from having to do some more client side code. In this case it makes sense because push is a very platform specific thing. For Windows Store and Windows Phone, we just have to register for a Channel URI from the app’s onLaunched method. For iOS, we have to register in the AppDelegate and then we get our token in the RegisteredForRemoteNotifications method. In both of these cases once we get a channel URI or push token, we can send them into our PCL code. Android is a bit more complicated but the concepts end up being the same. Rather than explain in more detail and show lots of code in an already long article, I’ll point you at these resources for Xamarin push for iOS and Android and these for Windows Store and Windows Phone.
Now once you have your channel URI / token / registration ID, you’re ready to register with Notification Hubs. Notification Hubs itself doesn’t currently have a PCL based library for handling registration. This ends up being ok because in this situation, it’s better for us to send our Push Identifier up to our Mobile Service and have it register with Notification Hubs on behalf of the device. I’ll get into this in a minute when I explain the tags. In the PCL, we’ll add this code which we can call from any project (or from earlier after we’ve authenticated):
Notice that we’re sending up the device’s platform, the user’s name, as well as the Push Identifier (again this is the Channel URI, token, or Registration ID). Now on the Mobile Service side, we add a custom API named RegisterForPush and set it to do the following:
First we pull out all the parameters sent up. We also pull out the Installation ID. This is a randomly generated string that is created at first run through for any application using the Mobile Services SDK. We then get a reference to the azure module (this gives us access to talk to Notification Hubs). We then create a reference to our Hub using the hub name and full access signature (which I’ve set as App Settings on the Configure tab of my Mobile Service). Next we have methods to handle registrationComplete and logErrors. We then call listRegistrationsByTag and pass in the installation ID. This returns to us a list of any registrations that are currently tied to our installation ID. So if a device has registered before, we’ll get that registration. We then loop through the registrations and delete them. This effectively means that we’ll make sure all existing registrations are gone before we then proceed to register.
To register we check the platform. Each platform expects to get it’s payload in a specific format. So inside the check for each platform, we fill a template object with the format. We can then use either the gcm, apns, mpns, or wns methods to register with our hub. To the registration methods, we pass the push identifier, a list of tags, the template, and the registration complete method. Tags are an interesting and awesome thing. They allow us to tie a registration to different strings (in this case the username, the platform, “AllUsers”, and the installation ID). Registering with the username allows us to push a message to all of the devices belonging to a specific user (i.e. send this push to all of Chris’ devices). The platform means we can send a push to all users on a platform (i.e. push to everyone on Windows). “AllUsers” means we can send a push that EVERYONE will get. Lastly, the installation ID is a useful way for us to make sure each device only has one registration (which we used before to delete any existing ones).
Now that we’re handling registering, we can take a look at actually delivering a push notification. Notification Hubs has several ways we can talk to it including: a REST API, a .NET NuGet Package, an unofficial Java library, and lastly, a Node.JS package. This Node package is what we used previously from Mobile Services to register with Notification Hubs. Now we’ll use the same thing to trigger our push:
In this example (and from the Build session) the users were sending a message and were able to specify a recipient. Prior to implementing push, this Message insert script would just save the data. Now we save the data and then do a push. We get access to our hub using the azure module again. We then create a payload (this payload variable matches up with what we used in our template earlier). We check to make sure a recipient was specified and if not we use “AllUsers” and we then use the hubs send method to deliver the message. That’s all we have to do, Notification Hubs will take care of the rest!
If you were present at my session, you’ll probably remember this not working very well (push notifications weren’t being delivered). The reason in this case was human error. I missed copying the script to actually DO the push notification when a message was saved. Simple enough to fix though and everything does work just fine.
Connecting back to on-premise
The last piece of my Build demo involved connecting back to an on-premise service. On this topic, I would first point people at Paolo Salvatori’s great walkthrough on integrating a Mobile Service with a REST Service Bus Relay Service. That walkthrough is great though it uses WCF which was a bit more than I wanted to showcase in the short time I had available during this session. I find WebAPI is a good deal simpler to digest if you don’t have as much time. Unfortunately, it isn’t QUITE as easy to connect Web API to Service Bus Relay. Thankfully, Pedro Felix does a great job of explaining how you do it here (and includes all the code in a GitHub repo).
Now Service Bus Relay is a really awesome service. What it allows you to do is connect one service to it (say something running in my data center (which doesn’t require firewall changes!)). Once connected, if you communicate with the Service Bus Relay URL, it will pass that through to your service running on your data center without you worrying about the underlying architecture. In this sample, I actually had my client applications talk to a custom API in my Mobile Service which THEN spoke with the Service Bus Relay which took it back to the Web API running locally on my laptop. If I wanted to, I could lock my Web API down to ensure it was only accessible from Azure IPs as well. Let’s take a look at the script our Mobile Service uses for this:
Here we use the request module to perform our HTTP request and then return the contents we get from Service Bus Relay back to the calling application.
This demo also ran into a few issues. I believe it just had to do with the network connectivity changing but am not certain. I tested it right after the session and later on an airplane and had no issues (including any with latency).
All of the code for this demo is available for you to grab on GitHub. There is a little bit of setup you’ll be required in order to run things but it’s all documented in the readme file. Hopefully this post and the repo provides enough information to duplicate the different system interactions and see how everything works. As always, reach out to me with questions.