Series overview
- Handle the incoming notification with an Azure Function (first post)
- Verify the invoice state within the Azure Function, but store the API credentials in the most secure way (second post)
- Send a push notification via Azure Notification Hub to all devices that have linked a merchant’s account to it (this post)
Preparations…
With Azure Notification Hub, we have one of the most powerful tools for sending push notifications out to connected devices. It is designed to handle multiple platforms, so let’s create a new Notification Hub in the Azure Portal. After logging in, select ‘Create a resource‘, followed by ‘Mobile‘ and a final click on ‘Notification Hub‘:

Fill in the details of the new Hub. Remember to select your already existing Resource Group and the same region that is used for your Azure Function:

After about a minute, your newly created Notification Hub is ready to use. Select ‘Go to resource‘ to open it.

Now we are already able to connect to our first platform. For this sample, I will focus on Android. Login to the Firebase console with your Google account. Select ‘Add project‘ and configure your Android app (or add your existing, if you have already one like I do):

After following all (self-explanatory) steps, scroll a bit down in the General tab of your Firebase project. You will find an entry like this:

Download the ‘google-services.json‘-file. We will need it later in our Android app. Now select the ‘Cloud Messaging‘ tab. You will be presented with two keys – copy the upper one:

Go back to the Azure portal and select ‘Google (GCM/FCM)‘ in ‘Settings’ . Paste the earlier copied key and hit the ‘Save‘-Button:

Now we need to authenticate our Azure Function to the Notification Hub. Select ‘Access Policies‘ in the ‘Manage’ section of your Hub and copy the lower ConnectionString with the ‘Listen

Open your Azure Function in a new tab. In the ‘Application settings‘, add a new setting and paste the ConnectionString. Add another one for the NotificationHub’s name:

Go back to the Notification Hub and save the upper ConnectionString locally, as we need that one in our Android application later on
Back to code…
Now that we have prepared the Notification Hub on Azure, let’s write some code that actually sends out our notifications once our Function verified our AtomicPay invoice. In the last post, we already rewrote some of the code in preparation of the final step, our push notifications.
Triggering push notifications
Before we will be able to modify our Function code to actually send the notification, we need to install an additional NuGet package: Microsoft.Azure.
Triggering push notifications can be broken down into these 3 steps:
- create a Hub client from the ConnectionString
- create the content of the notification
- finally send the notification
This translates into this Task inside our InvoiceVerifier
class:
private static async Task TriggerPushNotification(InvoiceInfoDetails invoiceInfoDetails, string accId) { //we need full shared access connection string (server side) var connectionString = ConfigurationManager.AppSettings["NotifHubConnectionString"]; var hubName = ConfigurationManager.AppSettings["NotifHubName"]; var hub = NotificationHubClient.CreateClientFromConnectionString(connectionString, hubName); var templateParams = new Dictionary<string, string>(); templateParams["body"] = $"Received payment for invoice id: {invoiceInfoDetails.InvoiceId} ({invoiceInfoDetails.Status.ToString()})"; var outcome = await hub.SendTemplateNotificationAsync(templateParams, $"accId:{accId}"); _traceWriter.Info($"attempted to inform merchant {accId} of payment via push"); }
We are loading the ConnectionString and the Hub’s name from our Function’s Application settings and create a new client connection using these two safely stored properties. To keep this sample simple, I am using a templated notification that can be used across all supported platforms. The receiver is responsible for the handling of this template (we’ll see how later in this post). Finally, we are sending out the notification to the native platforms, where they will be distributed (in our case, via Firebase Cloud Messaging). By including the accId:{accId}
tag, we are sending the push notification only to the devices that were registered with that specific merchant account.
Of course, this nicely written method does nothing until we actually use it. Let’s update our Run
method. we only need to add one line for our test in the switch that handles the returned invoiceInfoDetails
:
switch (invoiceInfoDetails.Status) { case AtomicPay.Entity.InvoiceStatus.Paid: case AtomicPay.Entity.InvoiceStatus.PaidAfterExpiry: case AtomicPay.Entity.InvoiceStatus.Overpaid: case AtomicPay.Entity.InvoiceStatus.Complete: log.Info($"invoice with id {invoiceInfoDetails.InvoiceId} is paid"); await TriggerPushNotification(invoiceInfoDetails, accId); break; default: log.Info($"invoice with id {invoiceInfoDetails.InvoiceId} is not yet paid"); //todo: this will trigger additional status handling in future break; }
Publish your updated Azure Function. Our Azure Function is now connected to a Notification Hub and is able to send out push notifications. Of course, push notifications ending in Nomandsland are boring. So let’s go ahead.
Receiving the push notifications
Create a new Xamarin.Android app (with XAML or without, your choice). Of course, also here we have some additional setup to perform.
Import google-services.json
Add the google-services.json
we downloaded before from Firebase to your project. Set its Build Action to GoogleServicesJson
in the Properties window. I needed to restart Visual Studio to be able to select this option after adding the file.

Installing NuGet packages
Of course, we also need to install some additional NuGet packages:
The second step involves some changes to the AndroidManifest, giving the Firebase package some permissions and handle its intents in the application
tag:
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" /> <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <category android:name="${applicationId}" /> </intent-filter> </receiver>
Next, we will add a new constants class:
public static class Constants { public const string ListenConnectionString = "<Listen connection string>"; public const string NotificationHubName = "<hub name>"; }
On the client, we are only using the lower permission ConnectionString we copied earlier from the Azure Notification Hub.
Connecting to Firebase
As our Azure Notification Hub sends notifications via Firebase, Google’s native messaging handler, we need a service that connects our app. The service requests a token (the Xamarin library does all that complex stuff for us) that we’ll need to actually register the device for the notifications. Add a new class PlatformFirebaseIidService
Service
attribute. Besides that, we need to register our interest on com.google.firebase.INSTANCE_ID_EVENT
OnTokenRefresh()
[Service] [IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })] public class PlatformFirebaseIidService : FirebaseInstanceIdService { const string TAG = "PlatformFirebaseIidService"; NotificationHub _hub; public override void OnTokenRefresh() { var refreshedToken = FirebaseInstanceId.Instance.Token; Log.Debug(TAG, "FCM token: " + refreshedToken); } }
Now that we hold a fresh Firebase instance token, we can register our app for receiving push notifications. To do this, we’re adding an new method:
void SendRegistrationToServer(string token, List<string> tags = null) { // Register with Notification Hubs _hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString, this); if (tags == null) tags = new List<string>() { }; var templateBody = "{\"data\":{\"message\":\"$(body)\"}}"; //this one registers a template that can be used cross platform //just make sure the template is the same on iOS, Windows, etc. var registerTemplate = _hub.RegisterTemplate(token, "defaultTemplate", templateBody, tags.ToArray()); Log.Debug(TAG, $"Successful registration of Template {registerTemplate.RegistrationId}"); }
Let me break this method down. Of course, we need to connect to our Notification Hub, which is responsible for the decision if our client is a valid receiver or not. If we add tags, they will get send together with the registration. We will add the merchant’s account Id to filter the receiver. As we are sending notifications using a template, we need to register for the template that gets filled by our Azure Function. One thing is left, calling this method after obtaining a token in the OnTokenRefresh
override:
SendRegistrationToServer(refreshedToken, new List<string>() { "accId:<yourAccId>" });
Handling incoming firebase messages
Now that our client is registered with both Firebase and the Azure Notification Hub, of PlatformFirebaseMessagingService
com.google.firebase.MESSAGING_EVENT
[Service] [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] public class PlatformFirebaseMessagingService : FirebaseMessagingService { const string TAG = "PlatformFirebaseMessagingService"; public override void OnMessageReceived(RemoteMessage message) { Log.Debug(TAG, "From: " + message.From); string title = "Azure Test message"; string body = null; if (message.GetNotification() != null) { //These is how most messages will be received body = message.GetNotification().Body; title = message.GetNotification().Title; Log.Debug(TAG, $"Notification Message Body: {body}"); } else { //Only used for debugging payloads sent from the Azure portal body = message.Data.Values.First(); } var notification = NotificationHelper.Instance.GetNotificationBuilder(title, body); NotificationHelper.Instance.Notify(1001, notification); } }
Of course, you are curious about NotificationHelper
NotificationService
public class NotificationHelper : ContextWrapper { private static NotificationHelper _instance; public static NotificationHelper Instance => _instance ?? (_instance = new NotificationHelper(Application.Context)); const string NOTIFICATION_CHANNEL_ID = "default"; const string NOTIFICATION_CHANNEL_NAME = "notif_test_channel"; NotificationManager _manager; NotificationManager Manager => _manager ?? (_manager = (NotificationManager)GetSystemService(NotificationService)); public NotificationHelper(Context context) : base(context) { var channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Default); channel.EnableVibration(true); channel.LockscreenVisibility = NotificationVisibility.Public; this.Manager.CreateNotificationChannel(channel); } }
Creating the Notifications involves the Notificiation.Builder class. We’re simplifying the process for us with this method:
public Notification.Builder GetNotificationBuilder(string title, string body) { var intent = new Intent(this.ApplicationContext, typeof(MainActivity)); intent.AddFlags(ActivityFlags.ClearTop); var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot); return new Notification.Builder(this.ApplicationContext, NOTIFICATION_CHANNEL_ID) .SetContentTitle(title) .SetContentText(body) .SetSmallIcon(Resource.Drawable.ic_launcher) .SetAutoCancel(true) .SetContentIntent(pendingIntent); }
To read more about creation notifications, have a look at the docs for local (= client side) notifications.
Last but not least, we need to inform the system’s notification service to show the notification. The final helper method to this looks like this:
public void Notify(int id, Notification.Builder notificationBuilder) { this.Manager.Notify(id, notificationBuilder.Build()); }
To test the notification, we have two options – one is to send a test notification via the Notification Hub, the other is to use Postman once again to create to trigger our Azure Function. In both cases, your result should be a notification on your device (after you deployed and run the application without the debugger being attached).

Conclusion
In this last post of the series, I showed you all steps that are needed to send out push notifications utilizing an Azure Notification Hub. It takes a bit of setup in the beginning, but the code involved is pretty easy and straight forward.
Now that the series is complete, you can have a look at the source code on Github. You need to add your google-services.json