How to send data to an Azure event hub in a Windows Store app

I’ve been working on a Windows Store app recently which would generate data and push it to an Azure Event Hub. Unfortunately, the Event Hub API doesn’t work with Store apps as the NuGet package fails to install. This means that I had to fall back to using the REST API (documented here).

The idea here is to send a POST request in the following format:

POST https://{service bus namespace name}.servicebus.windows.net/{event hub name}/publishers/{publisher name}/messages HTTP/1.1
Authorization: {token}
Content-Type: text/plain; charset=utf-8
Host: {service bus namespace name}.servicebus.windows.net
Content-Length: {message length}
Expect: 100-continue

{Message}

Everything in {braces} is stuff that can or will need to be changed to send data to your own event hub. For example, if you leave all the parameters at the top of the code below with their default values, the request that gets sent looks an awful lot like this:

POST https://pwrblogdemo-ns.servicebus.windows.net/pwrblogdemo/publishers/test/messages HTTP/1.1
Authorization: SharedAccessSignature sr=pwrblogdemo-ns.servicebus.windows.net&sig=T2iCRtFA%2BEeDfGMryzNssI3ssa8%2BQ0Q3xO2qPetrsk8%3D&se=1429046553&skn=SendRule
Content-Type: text/plain; charset=utf-8
Host: pwrblogdemo-ns.servicebus.windows.net
Content-Length: 14
Expect: 100-continue

{Message:Test}

For this to work, I’m going to assume you already have an event hub set up. If you don’t, then follow the guide here to get one up and running. You’ll also need a shared access policy with “Send” permissions.

Below, I’ve written out some code you can use to send data to your own event hub. Simply change the parameters at the top to set the endpoint and message.

eventHubName and serviceBusNamespace are pretty self-explanatory, and match {service bus namespace name} and {event hub name} in the example request. ruleName will need to be set to the name of a shared access policy with “Send” permissions, and ruleKey will need to be the primary key of that policy.

{token} is a Shared Access Signature token. I’ll talk more about how this is generated below.

An event hub is designed to receive ‘event data’ from ‘Event Publishers’. The documentation’s (purposefully?) vague on this one, but it looks like ‘Event Publisher’ is just a catch-all term for any device which sends data to an event hub. The only thing we have to worry about is giving it a name and sending that name with every request – that’s what {publisher} is in the request examples above. ‘Event data’ consists of a message body and some metadata. I’m not sure how exactly this is formatted, but the metadata is all placed on it when it reaches the event hub, so all we need to worry about sending is the message body, which is sent as the payload for our request. This can be in any format you want.

publishername and message set the publisher’s name and the message in the code below.

[code language=”csharp”]
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;

class EventHubSender
{
//Parameters:
private static string eventHubName = "pwrblogdemo";
private static string serviceBusNamespace = "pwrblogdemo-ns";
private static string ruleKey = "YJaiGMQAHvNrCajrxl1fsO2Ol4KZwOmokHafo/7Qhhk=";
private static string ruleName = "SendRule";
private static string publisherName = "Test";
private static string message = "{Message:Test}";

public async Task SendToEventHub()
{
string serviceBusUri = string.Format("{0}.servicebus.windows.net", serviceBusNamespace);

string authToken = GenerateAuthToken(serviceBusUri);

HttpClient client = new HttpClient();

client.DefaultRequestHeaders.Clear();

var authHeader = new System.Net.Http.Headers.AuthenticationHeaderValue(
"SharedAccessSignature", authToken);
client.DefaultRequestHeaders.Authorization = authHeader;

string body = message;
var content = new StringContent(body, Encoding.UTF8);
client.BaseAddress = new Uri(string.Format("https://{0}", serviceBusUri));

await client.PostAsync(string.Format("/{0}/publishers/{1}/messages", eventHubName, publisherName), content);

client.Dispose();
}

private static string GenerateAuthToken(string serviceBusUri)
{
int expirySeconds = GetExpirySeconds();
string expiry = expirySeconds.ToString();

string signature = GetSignature(serviceBusUri, expiry);

string authToken = string.Format(
"sr={0}&sig={1}&se={2}&skn={3}",
WebUtility.UrlEncode(serviceBusUri),
WebUtility.UrlEncode(signature),
expiry,
ruleName);
return authToken;
}

private static string GetSignature(string serviceBusUri, string expiry)
{
var hashAlgorithmProvider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
var encoding = BinaryStringEncoding.Utf8;
string stringToSign = string.Format("{0}n{1}", WebUtility.UrlEncode(serviceBusUri), expiry);
var keyBuffer = CryptographicBuffer.ConvertStringToBinary(ruleKey, encoding);
var valBuffer = CryptographicBuffer.ConvertStringToBinary(stringToSign, encoding);
var hash = hashAlgorithmProvider.CreateHash(keyBuffer);
hash.Append(valBuffer);
var hashedDataBuffer = hash.GetValueAndReset();
string signature = CryptographicBuffer.EncodeToBase64String(hashedDataBuffer);
return signature;
}

private static int GetExpirySeconds()
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
DateTime expiryTime = DateTime.Now.AddHours(1);
int expirySeconds = (int)expiryTime.Subtract(epoch).TotalSeconds;
return expirySeconds;
}
}
[/code]

The code is doing two things: generating an SAS token; then it is placing this on an HTTP request along with the publisher name and message and sending it.

The SAS token for sending data to an event hub is in the following format:
sr={Service Bus URI}&sig={Signature}&se={Expiry}&skn={Shared Access Policy Name}

The service bus URI is the URL-encoded URI for the service bus namespace (for example, ‘pwrblogdemo-ns.servicebus.windows.net’). The expiry is expressed as the number of seconds between the desired expiry time and midnight on January 1st, 1970. The shared access policy name is the name of the policy you set up to grant send access to the event hub. The signature is an HMAC-SHA-256 authentication code that is obtained by creating a string consisting of the service bus uri and the expiry, separated by a newline e.g. “pwrblogdemo-ns.service.windows.netn1429046553”, then signing this with a hash created from the shared access policy’s primary key.

Useful links:
Event Hub overview
Azure Event Hub REST API documentation

Leave a Reply

Your email address will not be published. Required fields are marked *