Skip to content

Open Sesame: Parse .NET SDK

Four weeks ago, we open-sourced our iOS and Android SDKs. Today, we're happy to announce that our .NET SDK is also now completely open-source!

Following the concept from our previous blog post, .NET SDK adopts the pattern of separating a component into State and Controller. Since State is simply a dumb object that stores data, with C# we can construct State directly with Object Initializer.

IObjectState state = new MutableState {
    ObjectId = "lLaKcoLNU",
    ClassName = "Corgi",
    ServerData = new Dictionary<string, object>() {
        { "isCute", true },
        { "muchWow", "yes" }
    }
};

The main challenge of open-sourcing Parse .NET SDK is building for multiple platforms with as much shared code as possible. Each platform has its own networking stack, UI system, file storing system, and push notification handler. We have built the abstraction using a combination of PCL, PlatformHooks, and reflection. For further illustration, let's take a look at how Push works in Parse .NET SDK.

Writing Cross-Platform ParsePush

As of today Parse Push for our .NET SDK works on WinRT, Silverlight, .NET 4.5, Windows Phone, Xamarin iOS and Android, and Unity iOS and Android. As you may have noticed, Push works differently on each platform - even between Windows 8 and Windows Phone 8.

First, registering for push notifications is a different experience for each platform. On Windows and Windows Phone, you have to store the channel URI to listen to the push. With Android, you have to request a GCM registration ID. On iOS, you have to register for remote notification. But everything boils down to one problem: How can you uniquely identify this device so that the Push Server can send a targeted push to this device? In the Parse SDK, we simplify this problem by saving a ParseInstallation object that contains special fields which enable push notifications for that device.

  1. On Windows, the special field is deviceUris. This is auto-populated by ParseInstallation.SaveAsync.
  2. On Android (Unity and Xamarin), the special fields are deviceToken and pushType. This is auto-populated by ParseClient.Initialize.
  3. On iOS (Unity and Xamarin), the special field is deviceToken. This is populated by ParseInstallation.SetDeviceToken.

Second, the Parse server will need to know device-specific information like the device type and timezone to correctly perform a push. Each platform also has a native API for this. Windows can use TimeZoneInfo.Local.StandardName for timezone. Xamarin Android, on the other hand, should call Java.Util.TimeZone.Default.ID, while Xamarin iOS should call Foundation.NSTimeZone.SystemTimeZone.Name. These are abstracted into IPlatformHooks.cs and PlatformHooks.<Platform>.cs. We use reflection to choose the correct PlatformHooks implementation to use for each runtime.

// ParseClient.cs
private static readonly IPlatformHooks platformHooks;
private static readonly string[] assemblyNames = {
  "Parse.Phone", "Parse.WinRT", "Parse.NetFx45", "Parse.iOS", "Parse.Android", "Parse.Unity"
};

static ParseClient() {
  Type platformHookType = GetParseType("PlatformHooks");
  if (platformHookType == null) {
    throw new InvalidOperationException("You must include a reference to a platform-specific Parse library.");
  }
  platformHooks = Activator.CreateInstance(platformHookType) as IPlatformHooks;
}

private static Type GetParseType(string name) {
  foreach (var assembly in assemblyNames) {
    Type type = Type.GetType(string.Format("Parse.{0}, {1}", name, assembly));
    if (type != null) {
      return type;
    }
  }
  return null;
}

Lastly, each platform handles push differently. There are native APIs to be called on each platform. We tackle this problem by letting developers handle the push from ParsePush. We wrote ParePush as a partial class, ParsePush.cs and ParsePush.<Platform>.cs. ParsePush.cs provides all common API for sending and subscribing to push, while ParsePush.<Platform>.cs provides the native API call for handling push.

// ParsePush.cs
public Task SendAsync();
public static Task SendAlertAsync(string alert);
public static Task SubscribeAsync(string channel);
public static Task UnsubscribeAsync(string channel);

// ParsePush.iOS.cs
public static void HandlePush(NSDictionary userInfo)

These are a few approaches that we've taken to write the cross-platform .NET SDK. If you find any issues or areas for possible improvement, send us a pull-request in the now open-source .NET SDK!