Skip to content

Instantly share code, notes, and snippets.

@hhyyg
Last active September 11, 2022 08:47
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhyyg/d670cf66235bea3d4ab7aed632acdd4e to your computer and use it in GitHub Desktop.
Save hhyyg/d670cf66235bea3d4ab7aed632acdd4e to your computer and use it in GitHub Desktop.
Azure Notification Hubs REST API in .NET Core [Read/Delete All Registrations of Channel]
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace MyApp
{
/*
* Thanks:
*
* Delete registration in Azure notification hub - Stack Overflow https://stackoverflow.com/questions/31737898/delete-registration-in-azure-notification-hub
* Notification Hub Rest API - The specified resource description is invalid - c# - azure - xmldocument - dotnet-httpclient - azure-notificationhub - TechQA http://techqa.info/programming/question/40139275/Notification-Hub-Rest-API---The-specified-resource-description-is-invalid
* Xml2CSharp.com | Convert your XML Examples into XmlSerializer compatable C# Classes http://xmltocsharp.azurewebsites.net/
*/
class Program
{
const string hubName = "***";
const string apiVersion = "?api-version=2015-01";
const string fullSharedAccessKey = @"Endpoint=sb://***.servicebus.windows.net/;SharedAccessKeyName=***;SharedAccessKey=***";
const string messageChannel = @"/messages";
const string registrationChannel = @"/registrations";
const string installationChannel = @"/installations";
static void Main(string[] args)
{
Core().Wait();
Console.WriteLine("Hello World!");
}
static async Task Core()
{
var feed = await ReadAllRegistrations();
if (feed == null)
return;
Console.WriteLine($"hits count:{feed.Entry.Count}");
foreach (var entry in feed.Entry)
{
var registrationId = entry.Content.AppleRegistrationDescription == null ? entry.Content.GcmRegistrationDescription.RegistrationId
: entry.Content.AppleRegistrationDescription.RegistrationId;
Console.WriteLine($"registrationId:{registrationId}");
//var resultStatusCode = await DeleteRegistration(registrationId);
//Console.WriteLine($"result:{resultStatusCode}");
}
}
public static async Task<Feed> ReadAllRegistrations()
{
var accessKey = ToAccessKey(fullSharedAccessKey);
Uri uri = new Uri($"{accessKey.Endpoint}{hubName}{registrationChannel}/{apiVersion}");
var sasToken = createToken(uri.AbsoluteUri, accessKey.SasKeyName, accessKey.SasKeyValue);
using (var client = new HttpClient())
{
var message = new HttpRequestMessage()
{
RequestUri = uri,
Method = HttpMethod.Get
};
message.Headers.Add("Authorization", sasToken);
message.Headers.Add("If-Match", "*");
var response = await client.SendAsync(message);
if (!response.IsSuccessStatusCode)
{
return null;
}
var reader = XmlReader.Create(await response.Content.ReadAsStreamAsync());
var serializer = new XmlSerializer(typeof(Feed));
var feed = serializer.Deserialize(reader) as Feed;
return feed;
}
}
public static async Task<HttpStatusCode> DeleteRegistration(string registrationId)
{
var accessKey = ToAccessKey(fullSharedAccessKey);
Uri uri = new Uri($"{accessKey.Endpoint}{hubName}{registrationChannel}/{registrationId}/{apiVersion}");
var sasToken = createToken(uri.AbsoluteUri, accessKey.SasKeyName, accessKey.SasKeyValue);
using (var client = new HttpClient())
{
var message = new HttpRequestMessage()
{
RequestUri = uri,
Method = HttpMethod.Delete
};
message.Headers.Add("Authorization", sasToken);
message.Headers.Add("If-Match", "*");
var response = await client.SendAsync(message);
return response.StatusCode;
}
}
private static AzureNotificationsAccessKey ToAccessKey(string connectionString)
{
var key = new AzureNotificationsAccessKey();
// Parse Connection string
char[] separator = { ';' };
string[] parts = connectionString.Split(separator);
for (int i = 0; i < parts.Length; i++)
{
if (parts[i].StartsWith("Endpoint"))
key.Endpoint = "https" + parts[i].Substring(11);
if (parts[i].StartsWith("SharedAccessKeyName"))
key.SasKeyName = parts[i].Substring(20);
if (parts[i].StartsWith("SharedAccessKey"))
key.SasKeyValue = parts[i].Substring(16);
}
return key;
}
/// <summary>
/// Code for generating of SAS token for authorization with Service Bus
///
/// This handy function can be found on this helpful blog post:
/// http://developers.de/blogs/damir_dobric/archive/2013/10/17/how-to-create-shared-access-signature-for-service-bus.aspx
/// </summary>
/// <param name="resourceUri"></param>
/// <param name="keyName"></param>
/// <param name="key"></param>
/// <returns></returns>
private static string createToken(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 = EncodeUrl(resourceUri) + "\n" + expiry;
System.Security.Cryptography.HMACSHA256 hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(System.Globalization.CultureInfo.InvariantCulture,
"SharedAccessSignature sig={1}&se={2}&skn={3}&sr={0}",
EncodeUrl(resourceUri), EncodeUrl(signature), expiry, keyName);
return sasToken;
}
private static string EncodeUrl(string resourceUri)
{
return System.Net.WebUtility.UrlEncode(resourceUri);
}
public class AzureNotificationsAccessKey
{
public string Endpoint { get; set; }
public string SasKeyName { get; set; }
public string SasKeyValue { get; set; }
}
}
[XmlRoot("feed", Namespace = "http://www.w3.org/2005/Atom")]
public class Feed
{
[XmlElement(ElementName = "entry", Namespace = "http://www.w3.org/2005/Atom")]
public List<Entry> Entry { get; set; }
}
[XmlRoot(ElementName = "entry", Namespace = "http://www.w3.org/2005/Atom")]
public class Entry
{
[XmlElement(ElementName = "id", Namespace = "http://www.w3.org/2005/Atom")]
public string Id { get; set; }
[XmlElement(ElementName = "link", Namespace = "http://www.w3.org/2005/Atom")]
public Link Link { get; set; }
[XmlElement(ElementName = "updated", Namespace = "http://www.w3.org/2005/Atom")]
public string Updated { get; set; }
[XmlElement(ElementName = "content", Namespace = "http://www.w3.org/2005/Atom")]
public Content Content { get; set; }
}
[XmlRoot(ElementName = "AppleRegistrationDescription", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public class AppleRegistrationDescription
{
[XmlElement(ElementName = "ETag", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string ETag { get; set; }
[XmlElement(ElementName = "ExpirationTime", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string ExpirationTime { get; set; }
[XmlElement(ElementName = "RegistrationId", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string RegistrationId { get; set; }
[XmlElement(ElementName = "Tags", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string Tags { get; set; }
[XmlElement(ElementName = "DeviceToken", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string DeviceToken { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
[XmlAttribute(AttributeName = "i", Namespace = "http://www.w3.org/2000/xmlns/")]
public string I { get; set; }
}
[XmlRoot(ElementName = "content", Namespace = "http://www.w3.org/2005/Atom")]
public class Content
{
[XmlElement(ElementName = "AppleRegistrationDescription", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public AppleRegistrationDescription AppleRegistrationDescription { get; set; }
[XmlAttribute(AttributeName = "type")]
public string Type { get; set; }
[XmlElement(ElementName = "GcmRegistrationDescription", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public GcmRegistrationDescription GcmRegistrationDescription { get; set; }
}
[XmlRoot(ElementName = "link", Namespace = "http://www.w3.org/2005/Atom")]
public class Link
{
[XmlAttribute(AttributeName = "rel")]
public string Rel { get; set; }
[XmlAttribute(AttributeName = "href")]
public string Href { get; set; }
}
public class GcmRegistrationDescription
{
[XmlElement(ElementName = "ETag", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string ETag { get; set; }
[XmlElement(ElementName = "ExpirationTime", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string ExpirationTime { get; set; }
[XmlElement(ElementName = "RegistrationId", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string RegistrationId { get; set; }
[XmlElement(ElementName = "Tags", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string Tags { get; set; }
[XmlElement(ElementName = "GcmRegistrationId", Namespace = "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect")]
public string GcmRegistrationId { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
[XmlAttribute(AttributeName = "i", Namespace = "http://www.w3.org/2000/xmlns/")]
public string I { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment