Following the first answer, I need to clarify that the solution I am looking for is when a temporary monitoring is needed, in the way VSCode with IoT Hub extension works, when it can temporarily listen to the event messages from the Event Hub behind the Iot Hub, for the development or debugging purposes. This is not a solution for the actual event listening and the mentioned IoT Hub routing should be used to consume the event.
I am trying to reproduce what IoT Hub plugin for VS Code is doing.
Here is an example of getting the "Event Hub-compatible endpoint" SAS key from IoT Hub that later can be used to listen to the devices events. For this to work one needs the proper RBAC rules to access it, and then:
In my case, getting the SAS key looks like this in C#:
using System;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.IotHub;
using Azure.ResourceManager.IotHub.Models;
using Azure.ResourceManager.Resources;
namespace MyTools.Utilities.IotDevices;
public class IotHubConnectionStringHelper
{
private readonly string _subscriptionId;
private readonly string _resourceGroupName;
private readonly string _iotHubName;
public async Task<string> GetConnectionStringForPolicy(string policyName)
{
Response<IotHubDescriptionResource> iotHub = await GetIotHubAsync().ConfigureAwait(false);
string endpoint = GetIotHubEndpoint(iotHub);
IotHubDescriptionResource iotHubDescription = iotHub.Value;
SharedAccessSignatureAuthorizationRule policy = await GetPolicyAsync(iotHubDescription, policyName);
string result = $"Endpoint={endpoint};SharedAccessKeyName={policy.KeyName};SharedAccessKey={policy.PrimaryKey};EntityPath={_iotHubName}";
return result;
}
private async Task<SharedAccessSignatureAuthorizationRule> GetPolicyAsync(IotHubDescriptionResource iotHub, string policyName)
{
AsyncPageable<SharedAccessSignatureAuthorizationRule>? policiesEnum = iotHub.GetKeysAsync();
await foreach (SharedAccessSignatureAuthorizationRule policy in policiesEnum)
{
if (policy.KeyName == policyName)
{
return policy;
}
}
throw new Exception("Policy not found.");
}
private static string GetIotHubEndpoint(Response<IotHubDescriptionResource> iotHub)
{
string endpoint = string.Empty;
if (iotHub.Value.Data.Properties.EventHubEndpoints.TryGetValue("events", out EventHubCompatibleEndpointProperties? eventHubProps))
{
if (eventHubProps == null || eventHubProps.Endpoint == null)
{
throw new Exception("No event hub endpoint found.");
}
endpoint = eventHubProps.Endpoint;
}
return endpoint;
}
private async Task<Response<IotHubDescriptionResource>> GetIotHubAsync()
{
ArmClient armClient = new ArmClient(new AzureCliCredential());
SubscriptionResource subscription = await armClient.GetSubscriptions().GetAsync(_subscriptionId);
ResourceGroupResource resourceGroup = await subscription.GetResourceGroups().GetAsync(_resourceGroupName);
IotHubDescriptionCollection iotHubCollection = resourceGroup.GetIotHubDescriptions();
Response<IotHubDescriptionResource> iotHub = await iotHubCollection.GetAsync(_iotHubName);
return iotHub;
}
}
And to emphasize it one more time, this is not for the production use, but a method for a temporary listening to the messages when debugging, developing or similar.