-1

I'm new to azure, i've already configured my app to receive raw notification and i'm able to receive them from the debug page of azure website, my question is, how can i send them from my backend? i'm able to send all type of notification but can't figure out how to send that type... A really simple one like the azure one (Windows one not Windows phone one), just one not formatted string

Enrico
  • 21
  • 4

3 Answers3

8

Asuming you are using WNS (and not MPNS), you simply call SendRaw from the hub.wns object. The syntax is:

sendRaw(tags, payload, optionsOrCallbackopt, callback)

See the NodeJS docs for the WNS service in Push Notification hubs at http://dl.windowsazure.com/nodedocs/WnsService.html.

For a .NET backend, you use NotificationHubClient.SendNotificationAsync as documented at https://msdn.microsoft.com/en-us/library/azure/dn369343.aspx. The notification class you feed in will be a WindowsNotification as described at https://msdn.microsoft.com/en-us/library/azure/microsoft.servicebus.notifications.windowsnotification.aspx.

Since you want to send a raw notification, you have to create the payload yourself. The documentation on how to create a raw payload is at https://msdn.microsoft.com/en-us/library/windows/apps/jj676791.aspx, and more specifically:

  • The HTTP Content-Type header must be set to "application/octet-stream".
  • The HTTP X-WNS-Type header must be set to "wns/raw".
  • The notification body can contain any string payload smaller than 5 KB in size.
ActiveNick
  • 551
  • 1
  • 4
  • 12
0

Here is some working code that will perform this task (.Net Standard 2.0 compliant):

  public static async Task SendRawNotification(string notificationString)
  {
    var sasToken = CreateSASToken($"http://{NotificationNamespace}.servicebus.windows.net/{NotificationHub}", "DefaultFullSharedAccessSignature", $"{SharedAccessKey}");

    var description = new NotificationDescription
    {
      NotificationType = type,
      Notification = JsonConvert.SerializeObject(notification)
    };
    var serialized = JsonConvert.SerializeObject(description);
    byte[] contentInBytes = Encoding.UTF8.GetBytes(serialized);

    HttpWebRequest request = WebRequest.Create($"https://{NotificationNamespace}.servicebus.windows.net/{NotificationHub}/messages/?api-version=2015-01") as HttpWebRequest;
    request.Method = "POST";
    request.ContentType = "application/octet-stream";
    request.Headers.Add("Authorization", sasToken);
    request.Headers.Add("X-WNS-Type", "wns/raw");
    request.Headers.Add("ServiceBusNotification-Format", "windows");


    using (Stream requestStream = request.GetRequestStream())
      requestStream.Write(contentInBytes, 0, contentInBytes.Length);

    using (HttpWebResponse webResponse = await request.GetResponseAsync() as HttpWebResponse)
    {
      if (webResponse.StatusCode != HttpStatusCode.Created)
      {
        throw new InvalidOperationException($"Failed to create notification: {serialized}");
      }
    }
  }

private static string CreateSASToken(string resourceUri, string keyName, string key)
{
  TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
  var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 3600); //EXPIRES in 1h 
  string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
  HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));

  var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
  var sasToken = String.Format(CultureInfo.InvariantCulture,
  "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
      HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);

  return sasToken;
}

The previous answers to this question have invalid links and provide no useful information on how to achieve this functionality.

Unfortunately, as of writing this response, the Azure Notification Hub SDK is broken in regards to sending Raw Notifications when using the NuGet Package: Microsoft.Azure.NotificationHubs (2.0.0)

This functionality was available and still works in Microsoft.Azure.NotificationHubs (1.0.9), this, however, is only available in.Net Framework projects targeting 4.6.1.

If you wish to send Raw Notifications in a .Net Core or .Net Standard 2.0 project, then you will receive an exception on the send saying something similar to "You have to set the content type to 'application/octet-stream'". This is because, in the SDK itself, they are constructing the HttpRequest using a StringContent object, which appends "charset-utf8" to the ContentType header.

Until an update to the NuGet package is released (Microsoft is aware of this problem and is currently working on providing an update), then you will have to create the HttpRequest yourself.

Unfortunately, once again, the Microsoft documentation regarding how to achieve this is severely lacking in details.

There are several steps to accomplish this, as follows:

  1. Create your Resource URI String

The Uri for the resource you are trying to use. For the purpose of sending a request to an Azure Notification hub, this should be formatted as follows: https://{NotificationHubNamespace}.servicebus.windows.net/{NotificationHubName}

So if your notification namespace is "notification-ns" and your notification hub is called "notification-hub", then the URI should be: https://notification-ns.servicebus.windows.net/notification-hub

  1. Save your DefaultSharedAccessSignature from Azure Portal

You need to copy down your DefaultFullSharedAccessSignature from the Azure Portal. Your signature should look like the following: Endpoint=sb://xxxx.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=xxxxxxxxx=

Copy / save the part following "SharedAccessKey=", as this is used to generate the access token.

  1. Generate your SharedAccessSignature Token (SAS Key)

Call the CreateSASToken function, set the parameters to the following: resourceUri: "https://{NotificationHubNamespace}.servicebus.windows.net/{NotificationHubName}" keyName: "DefaultFullSharedAccessSignature" key: the saved part following "SharedAccessKey=" in the DefaultFullSharedAccessSignature

This will generate a correctly formatted SharedAccessSignature (SAS Key)

Now, you can use the System.Net.Http library to create the HttpWebRequest to send the Raw Notification.

NIMISHAN
  • 1,265
  • 4
  • 20
  • 29
Ant
  • 1
  • 2
0

A Microsoft Engineer has since provided me with the following example program which is also capable of sending a raw notification, I think it is appropriate to share it here:

using Newtonsoft.Json.Linq;
using System;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace ConsoleApp
{
    class Program
    {
        static string NH_NAMESPACE = "{Please input}";
        static string HUB_NAME = "{Please input}";
        static string KEY_NAME = "DefaultFullSharedAccessSignature";
        static string KEY_VALUE = "{Please input}";

        static void Main(string[] args)
        {
            JObject jobject = new JObject();
            jobject.Add("text1", "my app");
            jobject.Add("text2", "my value");

            SendNotificaitonAsync(jobject.ToString()).Wait();

            Console.ReadLine();
        }

        private static async Task SendNotificaitonAsync(string content)
        {
            string resourceUri = $"https://{NH_NAMESPACE}.servicebus.windows.net/{HUB_NAME}/messages/";
            using (var request = CreateHttpRequest(HttpMethod.Post, resourceUri))
            {
                request.Content = new StringContent(content, Encoding.UTF8, "application/octet-stream");
                request.Content.Headers.ContentType.CharSet = string.Empty;
                var httpClient = new HttpClient();
                var response = await httpClient.SendAsync(request);
                Console.WriteLine(response.StatusCode);
            }
        }

        private static HttpRequestMessage CreateHttpRequest(HttpMethod method, String resourceUri)
        {
            var request = new HttpRequestMessage(method, $"{resourceUri}?api-version=2017-04");
            request.Headers.Add("Authorization", createToken(resourceUri, KEY_NAME, KEY_VALUE));
            request.Headers.Add("X-WNS-Type", "wns/raw");
            request.Headers.Add("ServiceBusNotification-Format", "windows");

            return request;
        }

        private static string createToken(string resourceUri, string keyName, string key)
        {
            TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
            var week = 60 * 60 * 24 * 7;
            var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
            string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
            HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
            var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
            return sasToken;
        }
    }
}
Ant
  • 1
  • 2