I have an IoTHub with a route that points to an EventHub which triggers a Functions.
I'm having problem getting the DeviceId and other IoT Hub properties from the event object without adding those explicitly to the payload.
If I set the input type to a string
(or a custom type):
public static void Run(string iotMessage, TraceWriter log) {
log.Info($"C# Event Hub trigger function processed a message: {iotMessage}");
}
I only get the payload without any other IoT Hub properties like DeviceId, CorrelationId or MessageId.
I tried to set the type to EventData
instead:
public static void Run(EventData iotMessage, TraceWriter log) {
log.Info($"C# Event Hub trigger function processed a message: {JsonConvert.SerializeObject(iotMessage)}");
}
Now I can access the IoT Hub properties via two getters: Properties and SystemProperties. For example I can access DeviceId like this iotMessage.SystemProperties["iothub-connection-device-id"]
. But it does not expose the payload.
So how do I access both IoT Hub properties and the payload?
I missed a thing in the documentation for EventData. It has a method called GetBytes() and returns the body as a byte array. Example of getting both the IoT Hub properties and the body:
public static async void Run(EventData telemetryMessage, TraceWriter log)
{
var deviceId = GetDeviceId(telemetryMessage);
var payload = GetPayload(telemetryMessage.GetBytes());
log.Info($"C# Event Hub trigger function processed a message. deviceId: { deviceId }, payload: { JsonConvert.SerializeObject(payload) }");
}
private static Payload GetPayload(byte[] body)
{
var json = System.Text.Encoding.UTF8.GetString(body);
return JsonConvert.DeserializeObject<Payload>(json);
}
private static string GetDeviceId(EventData message)
{
return message.SystemProperties["iothub-connection-device-id"].ToString();
}
That's the recommended way of doing this, if you need access to detailed event properties in addition to the payload. The simple/default bindings for string
etc. are useful in cases where you don't need to access those event properties. Our runtime calls EventData.GetBytes()
for you behind the scenes and converts the data to the input type you've specified.
I do think we could make improvements to facilitate these scenarios however. I've logged a bug here in our repo to track this.
There are some upcoming updates that will simply this according to this:
Added first class binding data support for many of the important
ServiceBus and EventHub message/event properties. For EventHub:
- PartitionContext
- PartitionKey
- Offset
- SequenceNumber
- EnqueuedTimeUtc
- Properties
- SystemProperties
For ServiceBus:
- DeliveryCount
- DeadLetterSource
- ExpiresAtUtc
- EnqueuedTimeUtc
- MessageId
- ContentType
- ReplyTo
- SequenceNumber
- To
- Label
- CorrelationId
- Properties
So you should be able to bind to these properties as well as the payload.