En un proyecto en el cual estoy participando actualmente se requiere enviar notificaciones push a una aplicación móvil a través de Azure Notification Hub. Como en este proyecto empleamos Dapr me dije... voy a ver si encuentro un componente que esté preparado para la integración. No lo encontré, pero sí te voy a contar cómo logramos conectarnos al Notification Hub y dejar a Dapr ser el encargado de realizar la integración, ¿te interesaría? Sigue leyendo que esto también lo puedes usar en cualquier otro servicio de Azure que disponga de API REST.
¿Qué es Azure Notification Hub?
Azure Notification Hub es un servicio de Azure que proporciona un motor de notificaciones push (de inserción) de escalabilidad horizontal y fácil uso que nos permite enviar notificaciones a cualquier plataforma (iOS, Android, Windows, etc.) desde cualquier backend (en la nube o local).
Es compatible con las siguientes plataformas
APNS (Apple Push Notification Service).
GCM (Google Cloud Messaging).
FCM (Firebase Cloud Messaging).
WNS (Windows Push Notification Service).
MPNS (Microsoft Push Notification Service).
ADM (Amazon Device Messaging).
Baidu (Android China).
¿Qué son las Notificaciones Push?
Creo que a estas alturas casi nadie desconoce qué es una notificación push, pero lo volveremos a recordar. Las notificaciones push son una forma de comunicación de aplicación a usuario que generalmente se muestra en un cuadro de diálogo o una ventana emergente en el dispositivo móvil. Algunas notificaciones son silenciosas, es decir, que se entregan en segundo plano para que la aplicación las procese en segundo plano y decida qué hacer.
Azure Notification Hub dispone de una capacidad de filtrar el envío de notificaciones gracias a la funcionalidad de etiquetado, que permiten segmentar a los usuarios por actividad, interés, geografía, preferencia o cualquier otra etiqueta personalizada. Con esto conseguimos que el contenido se entregue a dispositivos concretos.
Una etiqueta puede tener una cadena de hasta 120 caracteres que incluya caracteres alfanuméricos y no alfanuméricos.
Especificación del binding Dapr HTTP.
Vamos a repasar cómo definiremos el componente de Dapr para binding Http aunque dejo el enlace de la documentación oficial.
En nuestro caso establecemos únicamente el metadato de la URL de nuestro Azure Notification Hub.
1apiVersion: dapr.io/v1alpha12kind: Component3metadata:4 name: http-push-notifications5spec:6 type: bindings.http7 version: v18 metadata:9 - name: url10 value: https://[namespace].servicebus.windows.net/[notificationhubname]11
Cuando realicemos una petición a este componente podremos realizar una de estas operaciones que coinciden con los verbos HTTP que manejamos habitualmente.
Como metadatos a enviar al binding, se establecerán los siguientes:
Vale, ya tenemos listo el binding y cómo usarlo. Ahora repasaremos un poquito el API REST de Azure Notification Hub para enviar una notificación como plantilla.
Especificación API REST Azure Notification Hub
Dejo por aquí el enlace para que puedas consultarlo.
Como vemos, la url para enviar un mensaje a nuestro Notification Hub es la siguiente
1https://[namespace].servicebus.windows.net/[notificationhubname]/messages/?api-version=2015-012
Como definimos en nuestro componente que la url es https://[namespace].servicebus.windows.net/[notificationhubname], necesitamos usar el metadato "path" con el valor "/messages/?api-version=2015-01".
Las siguientes cabeceras son obligatorias:
Authorization: token generado tal y como se especifica en autenticación de firma de acceso compartido con Service Bus. Generaremos el token en tiempo de ejecución con código que se mostrará más adelante.
Content-Type: establecemos con el valor "application/json;charset=utf-8".
ServiceBusNotification-Format: establecemos con el valor "template".
Si queremos enviar una notificación con un tag específico o una expresión de etiquetas, estableceremos la cabecera:
Con todo esto, el cuerpo de la solicitud que se envía a Azure Notificacion Hub sería algo como:
1{2 "operation": "post",3 "metadata": {4 "path": "/messages/?api-version=2015-01",5 "Authorization": "SharedAccessSignature sr=https%3a%2f%2fnamespace.servicebus.windows.net%2fnotificationhubname%2fmessages%2f%3fapi-version%3d2015-01&sig=IhCVcSUDFsgEULcB%2fBrM8hBD44cWyGXZN1Xb3nuzfzQ%3d&se=1684406490&skn=DefaultFullSharedAccessSignature",6 "Content-Type": "application/json;charset=utf-8",7 "ServiceBusNotification-Format": "template",8 "ServiceBusNotification-Tags": "(follows_RedSox || follows_Cardinals) && location_Boston"9 }10}11
Veamos cómo generar el token de autenticación.
Para generar el token de autenticación como requiere el servicio, es necesario pasarle como parámetro la url completa, un tiempo de expiración para el token, el nombre de la clave SAS a usar y la clave propiamente dicha para firmar.
static string GenerateSasTokenForAzureNotificationHub(string uri, int minUntilExpire, string sasKeyName, string sasKeyValue)
1{2 TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);3 var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + minUntilExpire);4 string stringToSign = HttpUtility.UrlEncode(uri) + "n" + expiry;5 HMACSHA256 hmac = new(Encoding.UTF8.GetBytes(sasKeyValue));6 var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));7 var sasToken = string.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",8 HttpUtility.UrlEncode(uri), HttpUtility.UrlEncode(signature), expiry, sasKeyName);910 return sasToken;11}12
Entonces nuestro método para enviar una notificación quedaría:
1async Task SendPushNotificationAsync(string message, IConfiguration configuration)2{3 var outputBindingService = host.Services.GetService<IDaprOutputBindingService>()!;45 var connectionString = IDaprOutputBindingService.ParseConnectionStringForAzureNotificationHub(configuration["NotificationHub:ConnectionString"], configuration["NotificationHub:NotificationHubName"]);67 var metadata = new Dictionary<string, string>()8 {9 { "path", CoreConstants.PUSH_NOTIFICATION_URI_PATH },10 { CoreConstants.CONTENT_TYPE_HEADER_NAME, CoreConstants.JSON_UTF8 },11 { CoreConstants.PUSH_NOTIFICATION_FORMAT_HEADER_NAME, CoreConstants.PUSH_NOTIFICATION_FORMAT_HEADER_VALUE },12 { CoreConstants.PUSH_NOTIFICATION_TAGS_HEADER_NAME, "(follows_RedSox || follows_Cardinals) && location_Boston" },13 { CoreConstants.AUTHORIZATION_HEADER_NAME,14 IDaprOutputBindingService15 .GenerateSasTokenForAzureNotificationHub(connectionString.GetNotificationHubUri(), 5, connectionString.SasKeyName, connectionString.SasKeyValue)}16 };1718 var messageText = new19 {20 message21 };2223 await outputBindingService.TryPublishMessageAsync(messageText, "post", metadata, CoreConstants.BINDING_NAME_HTTP_PUSH_NOTIFICATIONS);24}25
¿Dónde puedo encontrar el código de ejemplo?
No os preocupéis si no lo tenéis claro, lo veréis mejor al descargar el código fuente en https://github.com/sparraguerra/compartimoss/tree/master/DaprAndAzureNotificationHub
Hemos visto lo sencillo que es integrar cualquier sistema externo con Dapr al aprovechar el binding Http, y también nuestro código ya no depende de ningún otro SDK o bibliotecas de terceros.
Happy coding!
Sergio Parra Guerra
Software & Cloud Architect at Encamina
https://twitter.com/sparraguerra