Azure IoT Hub Framework 3.5 - azure

Are there any good tutorials or guides to using Azure IoT Hub via using the MQTT protocol from devices with framework 3.5? I found the M2MQTT client but it won't work with Azure IoT Hub.

IoT Hub enables devices to communicate with the IoT Hub device endpoints using MQTT v3.1.1 protocol directly. You can take a look at this document. In the document the tutorial is written in python, following code is a full sample for C# using uPLibrary.Networking.M2Mqtt.
C# Example:
private static string hostName = "<iothub-hosename>";
private static int port = 8883;
private static string deviceId = "<deviceid>";
private static string userName = "";
private static string password = "";
private static string certBase64 = "<DigiCert Baltimore Root Certificate>";
static void Main(string[] args)
{
try
{
userName = $"{hostName}/{deviceId}/api-version=2016-11-14";
password = $"SharedAccessSignature sr=<SAS Token>";
byte[] certBytes = Convert.FromBase64String(certBase64);
X509Certificate caCert = new X509Certificate(certBytes);
MqttClient client = new MqttClient(hostName, port, true, caCert, null , MqttSslProtocols.TLSv1_0);
client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
client.MqttMsgPublished += Client_MqttMsgPublished;
client.ConnectionClosed += Client_ConnectionClosed;
client.Connect(deviceId, userName, password);
if(client.IsConnected)
{
//To receive messages from IoT Hub, a device should subscribe using devices/{device_id}/messages/devicebound/# as a Topic Filter.
client.Subscribe(new string[] { $"devices/{deviceId}/messages/devicebound/#" }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE });
//After making a successful connection, a device can send messages to IoT Hub using devices/{device_id}/messages/events/ or devices/{device_id}/messages/events/{property_bag} as a Topic Name.
client.Publish($"devices/{deviceid}/messages/events/", System.Text.Encoding.ASCII.GetBytes("{id=123}"), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, false);
}
}
catch(Exception ex)
{
Console.Write(ex.Message);
}
Console.Read();
}
private static void Client_MqttMsgPublished(object sender, MqttMsgPublishedEventArgs e)
{
Console.WriteLine("Mqtt Published Message-[MsgId:{0}]:{1}", e.MessageId, e.IsPublished ? "Success": "Failure");
}
private static void Client_ConnectionClosed(object sender, EventArgs e)
{
Console.WriteLine("ConnectionClosed");
}
private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
Console.WriteLine(System.Text.Encoding.ASCII.GetString(e.Message));
}
In the code, you may need to copy the DigiCert Baltimore Root Certificate to certBase64 from certs.c as base64 string(remove the lines -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----, and remove \r\n\).
Update:
How to get SAS token?
You can use Device Explorer to generate SAS tokens,please see the device section of Using IoT Hub security tokens.

Are you referring to Azure IoT Hub device SDK for .NET, and it working with .NET Framework 3.5 ? As per the GitHub documentation, it seems IoT Hub SDK for .NET supports only .NET Framework 4.5.1 and above only.
Alternatively, Simply using Azure IoT Hub Rest API - then you can make HTTP requests from your legacy .NET Framework 3.5 code

Related

What is alternate of ServiceBus MessagingFactory in .Net Core?

While converting my project from .Net framework 4.7 to .Net core 2.1, I'm facing issue with Servicebus MessagingFactory. I don't see any MessagingFactory class in new nuget package Microsoft.Azure.ServiceBus for .Net core.
My .Net framework 4.7 Code
private static readonly string messagingConnectionString = Environment.GetEnvironmentVariable("ServiceBusConnection");
private static Lazy<MessagingFactory> lazyMessagingFactory = new Lazy<MessagingFactory>(() =>
{
return MessagingFactory.CreateFromConnectionString(messagingConnectionString);
});
public static MessagingFactory MessagingFactory
{
get
{
return lazyMessagingFactory.Value;
}
}
public static MessagingFactory EventHubMessageFactory
{
get
{
return lazyEventhubMessagingFactory.Value;
}
}
public async Task SendMessageToQueueAsync(string queueName, string message)
{
QueueClient queueClient = MessagingFactory.CreateQueueClient(queueName);
BrokeredMessage brokeredMessage = new BrokeredMessage(new MemoryStream(Encoding.UTF8.GetBytes(message)), true);
await queueClient.SendAsync(brokeredMessage);
}
It was a best practices for high performance application, Also I have many queues under single service bus namespace and I push message based on configuration. I don't want to create QueueClient object in every request and don't want to maintain connection string for every queue.
What is alternate of MessagingFactory in .Net Core?
There are major changes when you are migrating .NetFramework code into .Netcore, you can see Guide for migrating to Azure.Messaging.ServiceBus from Microsoft.Azure.ServiceBus
Example below
static void Main(string[] args)
{
string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
var client = new ServiceBusClient(connectionString);
// create the sender
ServiceBusSender sender = client.CreateSender(queueName);
for (int i = 0; i < 10; i++)
{
// create a message that we can send. UTF-8 encoding is used when providing a string.
ServiceBusMessage message = new ServiceBusMessage($"Hello world {i}!");
// send the message
sender.SendMessageAsync(message).GetAwaiter().GetResult();
}
sender.DisposeAsync().GetAwaiter().GetResult();
client.DisposeAsync().GetAwaiter().GetResult();
}
https://github.com/MicrosoftDocs/azure-docs/issues/46830
https://github.com/Azure/azure-service-bus-dotnet/issues/556
While MessagingFactory is gone, the idea of connection pooling and sharing connections is there. When you create your clients, passing a connection will reuse it. When passing a connection string, will cause clients to establish a new connection.
So you can manually create a ServiceBusConnection or reuse one of an existing client. You can pass the connection object in the constructors of the clients you create. Take care not to close a connection accidentally, e.g. by closing the client that created it.

How to show event message in Azure Service Fabric Explorer

I'm new to Azure Service Fabric. I follow the tutorial to create hello demo service for Stateless.
It's simple service and I can find the Event Message in local VS IDE Diagnostic Events to show the message that I print
ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);
Like below picture:
But I can't see any log for cluster manager explorer.
Is it possible to show the event log in this explorer? How to do it?
There are my demo event source class code;
[NonEvent]
public void Message(string message, params object[] args)
{
if (this.IsEnabled())
{
string finalMessage = string.Format(message, args);
Message(finalMessage);
}
}
private const int MessageEventId = 1;
[Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")]
public void Message(string message)
{
if (this.IsEnabled())
{
WriteEvent(MessageEventId, message);
}
}
Pretty sure that currently the Service Fabric Explorer (SFX) only shows node level events and not application specific events.
According to the resent 7.0 release announcement (https://techcommunity.microsoft.com/t5/Azure-Service-Fabric/Service-Fabric-7-0-Release/ba-p/1015482) work is ongoing to display application specific events in SFX

How to solve Unhandle Exception:System.Net Socket.SocketException in azure iot readmessage device?

Hi i have the following code, that reads the message to the device. I have azure portal running. But i get the following exception when running on a command prompt;
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Azure.EventHubs;
using System.Threading.Tasks;
using System.Threading;
using System.Text;
using System.Collections.Generic;
namespace read_d2c_messages
{
class ReadDeviceToCloudMessages
{
// Event Hub-compatible endpoint
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
private readonly static string s_eventHubsCompatibleEndpoint ="sb://iothub-ns-mydeviceco......";
// Event Hub-compatible name
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
private readonly static string s_eventHubsCompatiblePath = "mydeviceconnection";
// az iot hub policy show --name service --query primaryKey --hub-name {your IoT Hub name}
private readonly static string s_iotHubSasKey = "";
private readonly static string s_iotHubSasKeyName = "service";
private static EventHubClient s_eventHubClient;
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct)
{
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
var eventHubReceiver = s_eventHubClient.CreateReceiver("$Default", partition, EventPosition.FromEnqueuedTime(DateTime.Now));
Console.WriteLine("Create receiver on partition: " + partition);
while (true)
{
if (ct.IsCancellationRequested) break;
Console.WriteLine("Listening for messages on: " + partition);
// Check for EventData - this methods times out if there is nothing to retrieve.
var events = await eventHubReceiver.ReceiveAsync(100);
// If there is data in the batch, process it.
if (events == null) continue;
foreach(EventData eventData in events)
{
string data = Encoding.UTF8.GetString(eventData.Body.Array);
Console.WriteLine("Message received on partition {0}:", partition);
Console.WriteLine(" {0}:", data);
Console.WriteLine("Application properties (set by device):");
foreach (var prop in eventData.Properties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
Console.WriteLine("System properties (set by IoT Hub):");
foreach (var prop in eventData.SystemProperties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
}
}
}
private static async Task Main(string[] args)
{
Console.WriteLine("IoT Hub Quickstarts - Read device to cloud messages. Ctrl-C to exit.\n");
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
var connectionString = new EventHubsConnectionStringBuilder(new Uri(s_eventHubsCompatibleEndpoint), s_eventHubsCompatiblePath, s_iotHubSasKeyName, s_iotHubSasKey);
s_eventHubClient = EventHubClient.CreateFromConnectionString(connectionString.ToString());
// Create a PartitionReciever for each partition on the hub.
var runtimeInfo = await s_eventHubClient.GetRuntimeInformationAsync();
var d2cPartitions = runtimeInfo.PartitionIds;
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
Console.WriteLine("Exiting...");
};
var tasks = new List<Task>();
foreach (string partition in d2cPartitions)
{
tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token));
}
// Wait for all the PartitionReceivers to finsih.
Task.WaitAll(tasks.ToArray());
}
}
}
On my command prompt, the exception is System.Net.Sockets.SocketException:A connection attempt failed because the connected party did not properly respond after a period of time, or established failed because host has failed to respond at Microsoft.Azure.EventHub.Amqp.AmqpHubClient.CreateConnectionAsync(TimeSpan, Timeout); What kind of error is this? Is had to do with firewall connectivity issue on my connection string not to receive message? Or hence i am using Free Trail cant be able to create Service-Bus-Messsage on my EndPoint?
I think the way you construct your connection string is not quite correct. When you copy the connection string from your IoT Hub in the full format, this should already work:
s_eventHubClient = EventHubClient.CreateFromConnectionString("Endpoint=sb://iothub-xxxxxx-1180347-e18a7c8824.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=qya62bOiN0********gIyEQ=;EntityPath=myiothubname");

Subscribe to Azure IoT Hub Device Events

I want to read the "Microsoft.Devices.DeviceConnected" events (https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-event-grid#event-types) from Azure IoT Hub. The only examples I found deals with Azure Event Grid but I'd rather like to use the IoT Hub's internal endpoint (Event Hub). Is this even possible?
When I subscribe to the internal Event Hub using the EventProcessorHost interface all I get are D2C user telemetry messages.
Like #PeterBons said, this feature is not supported by Azure IoT Hub, however can be done outside of the Azure IoT Hub using an Azure Function. The following screen snippet shows this integration where the EventGrid events are pushed to the IoT Hub Stream:
As you can see, the above EventGridTrigger function is an integrator between the Azure Event Grid and Azure IoT Hub. This integrator has a responsibility to consume an event grid events, mapping to the D2C Message and send it to the Azure IoT Hub as a virtual IoT device (backend device) with a Https protocol.
Update:
The following code snippet is an example of the Azure Function - Integrator to the Azure IoT Hub:
#r "Microsoft.Azure.EventGrid"
#r "Newtonsoft.Json"
using System.Configuration;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Web;
using System.Net.Http;
using System.Text;
using System.Globalization;
using Newtonsoft.Json;
using Microsoft.Azure.EventGrid.Models;
// reusable client proxy
static HttpClientHelper iothub = new HttpClientHelper(Environment.GetEnvironmentVariable("AzureIoTHubShariedAccessPolicy"));
public static async Task Run(EventGridEvent eventGridEvent, ILogger log)
{
log.LogInformation(eventGridEvent.Data.ToString());
// my virtual backend iot device
string deviceId = "Device13";
var content = new StringContent(JsonConvert.SerializeObject(eventGridEvent), Encoding.UTF8, "application/json");
await iothub.Client.PostAsync($"/devices/{deviceId}/messages/events?api-version=2018-06-30", content);
}
// helpers
class HttpClientHelper
{
HttpClient client;
DateTime expiringSaS;
(string hostname, string keyname, string key) config;
public HttpClientHelper(string connectionString)
{
config = GetPartsFromConnectionString(connectionString);
client = new HttpClient() { BaseAddress = new Uri($"https://{config.hostname}")};
SetAuthorizationHeader();
}
public HttpClient Client
{
get
{
if (expiringSaS < DateTime.UtcNow.AddMinutes(-1))
{
SetAuthorizationHeader();
}
return client;
}
}
internal void SetAuthorizationHeader()
{
lock (client)
{
if (expiringSaS < DateTime.UtcNow.AddMinutes(-1))
{
string sasToken = GetSASToken(config.hostname, config.key, config.keyname, 1);
if (client.DefaultRequestHeaders.Contains("Authorization"))
client.DefaultRequestHeaders.Remove("Authorization");
client.DefaultRequestHeaders.Add("Authorization", sasToken);
expiringSaS = DateTime.UtcNow.AddHours(1);
}
}
}
internal (string hostname, string keyname, string key) GetPartsFromConnectionString(string connectionString)
{
var parts = connectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim());
return (parts["HostName"] ?? "", parts["SharedAccessKeyName"] ?? "", parts["SharedAccessKey"] ?? "");
}
internal string GetSASToken(string resourceUri, string key, string keyName = null, uint hours = 24)
{
var expiry = GetExpiry(hours);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, $"SharedAccessSignature sr={HttpUtility.UrlEncode(resourceUri)}&sig={HttpUtility.UrlEncode(signature)}&se={expiry}");
if (!string.IsNullOrEmpty(keyName))
sasToken += $"&skn={keyName}";
return sasToken;
}
internal string GetExpiry(uint hours = 24)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
return Convert.ToString((int)sinceEpoch.TotalSeconds + 3600 * hours);
}
}
and function.json:
{
"bindings": [
{
"type": "eventGridTrigger",
"name": "eventGridEvent",
"direction": "in"
}
],
"disabled": false
}
I just wanted to add that you quite easily can create an event subscription (using Event Grid) under Events in the IoT Hub and push Connection events (e.g. Device Connected or Device Disconnected) to an Azure Function, Event Hub or Service Bus etc.
An IoT hub has a default built-in-endpoint (messages/events) that is compatible with Event Hubs. You can create custom endpoints to route messages to by linking other services in your subscription to the IoT Hub.
Here is link to the relevant Azure documentation

How can I set the type of azure service bus to notification hub programmatically

Using methods below, I previously (until last week) could create a service bus with a "mixed" type and then could add a notification hub. However, it suddenly stopped working. It creates a service bus with "Messaging" type and when it tries to create the notification hub, I get the error below:
Enity xxxxxx, create notification hub failed with error forbidden
public ServiceBusNamespaceResponse CreateServiceBus(SubscriptionCloudCredentials credentials, string regoin)
{
var serviceBushubClient = CloudContext.Clients.CreateServiceBusManagementClient(credentials);
var checkserviceBusResponse = serviceBushubClient.Namespaces.CheckAvailability(_deploymentName);
if (checkserviceBusResponse.IsAvailable)
{
try
{
var serviceBusClientResponse = serviceBushubClient.Namespaces.Create(_deploymentName, regoin);
_serviceBusEndpoint = serviceBusClientResponse.Namespace.ServiceBusEndpoint.ToString();
return serviceBusClientResponse;
}
catch (CloudException ex)
{
Console.WriteLine(ex.ErrorMessage);
return null;
}
}
return null;
}
and
public bool CreateNotificationHub(SubscriptionCloudCredentials credentials)
{
SBNotificationHubManager notificationHub;
EntityDescription servesBus = new EntityDescription();
servesBus.Name =_deploymentID;
var des = new MyNotificationHubDescription("push-hub-" + TenantID, servesBus);
notificationHub =
ResourceFactory.Get( _subscriptionID,
new X509Certificate2(Convert.FromBase64String(RowData._base64EncodedCert)),
SBRestResourceType.NHub, des) as SBNotificationHubManager;
if (notificationHub != null)
{
// Console.WriteLine("Created Notification Hub: {0}{1}", Environment.NewLine, notificationHub.LookUp().ToString());
if (notificationHub.Create())
{
Console.WriteLine("Created Notification Hub: {0}{1}", Environment.NewLine, notificationHub.LookUp().ToString());
notificationHub.WaitUntillActive();
return true;
}
}
return false;
}
I was wondering if something recently changed in azure? Can anyone please advise how to define the type of service bus (messaging/notification hub) when creating it in c#. The default with the above method is messaging. I need mixed, but notification hub type also works fine in my case.
Thank you
Now you must explicitly select Messaging (for topics/queues/event hubs) or NotificationHub (for notification hubs). That is idea.
About implementation. Observing source codes I can see overload which accepts ServiceBusNamespaceCreateParameters argument:
Task<ServiceBusNamespaceResponse> CreateNamespaceAsync(string namespaceName, ServiceBusNamespaceCreateParameters namespaceEntity, CancellationToken cancellationToken);
That class has public property of NamespaceType
public NamespaceType NamespaceType{...
So you probably could set it to NamespaceType.NotificationHub and then go ahead to create namespace.

Resources