hhyyg
7/6/2017 - 9:21 AM

Azure Notification Hubs REST API in .NET Core [Read/Delete All Registrations of Channel]

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; }
	}
}