Last active
September 11, 2022 08:47
-
-
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]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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