目前我有一个 IoT 中心,我正在尝试将设备连接事件和生命周期事件从 IoT 中心获取到函数应用。这是使用事件中心而不是事件网格。
这样做的原因是这样更便宜,因为事件网格也有一些成本。如果这是不可能的,我将不得不使用事件中心来处理所有遥测数据,并使用事件网格来处理连接/生命周期事件。
Compare message routing and Event Grid for IoT Hub
这个问题似乎与 Subscribe to Azure IoT Hub Device Events 有关,但这里使用了事件网格。
根据我在互联网上找到的信息,这应该是可能的。 https://sandervandevelde.wordpress.com/2022/01/16/azure-iot-device-lifecycle-events/ 。
但是,我担心从 Microsoft.Azure.EventHubs.EventData
到 Azure.Messaging.EventHubs.EventData
这个选项似乎在途中丢失了。
所以我的设置:
作为 IoT 设备,我使用 https://azure-samples.github.io/raspberry-pi-web-simulator/(我确实必须注释掉所有 LEDPin
行)
接下来,我使用以下(默认)代码制作了一个函数应用程序(C# 6,非隔离,Windows)。
using System;
public static void Run(string myIoTHubMessage, ILogger log)
{
log.LogInformation($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}");
}
尝试此操作时请注意。在“function.json”中将 eventHubName 设置为正确的值。如果您不这样做,该函数将不会喜欢它(运行时崩溃)。
这给出了以下结果。
2023-04-20T14:49:38Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=dfc5bf56-b24d-4007-8ce7-dc53368844a6)
2023-04-20T14:49:38Z [Information] Trigger Details: PartionId: 1, Offset: 60129561056, EnqueueTimeUtc: 2023-04-20T14:49:37.9070000+00:00, SequenceNumber: 3096, Count: 1
2023-04-20T14:49:38Z [Information] C# IoT Hub trigger function processed a message: {"deviceId":"AzureIotSim","etag":"AAAAAAAAAAE=","version":2,"properties":{"desired":{"$metadata":{"$lastUpdated":"2023-04-20T14:49:37.6237465Z"},"$version":1},"reported":{"$metadata":{"$lastUpdated":"2023-04-20T14:49:37.6237465Z"},"$version":1}}}
2023-04-20T14:49:38Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=dfc5bf56-b24d-4007-8ce7-dc53368844a6, Duration=1ms)
2023-04-20T14:51:16Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=1dd9de7f-9782-4431-b2ee-2bce3e238f51)
2023-04-20T14:51:16Z [Information] Trigger Details: PartionId: 1, Offset: 60129561728, EnqueueTimeUtc: 2023-04-20T14:51:15.9050000+00:00, SequenceNumber: 3097, Count: 1
2023-04-20T14:51:16Z [Information] C# IoT Hub trigger function processed a message: {"messageId":1,"deviceId":"Raspberry Pi Web Client","temperature":23.38174622864487,"humidity":64.11401901408449}
2023-04-20T14:51:16Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=1dd9de7f-9782-4431-b2ee-2bce3e238f51, Duration=1ms)
2023-04-20T14:51:18Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=1a82745b-458a-40aa-90d1-5337c80ff0b4)
2023-04-20T14:51:18Z [Information] Trigger Details: PartionId: 1, Offset: 60129562216, EnqueueTimeUtc: 2023-04-20T14:51:17.8280000+00:00, SequenceNumber: 3098, Count: 1
2023-04-20T14:51:18Z [Information] C# IoT Hub trigger function processed a message: {"messageId":2,"deviceId":"Raspberry Pi Web Client","temperature":24.456039635710496,"humidity":60.665519892235665}
2023-04-20T14:51:18Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=1a82745b-458a-40aa-90d1-5337c80ff0b4, Duration=0ms)
2023-04-20T14:51:20Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=f0c8cc5c-bec2-4835-8b86-af017ad68ce6)
2023-04-20T14:51:20Z [Information] Trigger Details: PartionId: 1, Offset: 60129562704, EnqueueTimeUtc: 2023-04-20T14:51:19.8130000+00:00, SequenceNumber: 3099, Count: 1
2023-04-20T14:51:20Z [Information] C# IoT Hub trigger function processed a message: {"messageId":3,"deviceId":"Raspberry Pi Web Client","temperature":23.476940209551135,"humidity":73.32736250962085}
2023-04-20T14:51:20Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=f0c8cc5c-bec2-4835-8b86-af017ad68ce6, Duration=1ms)
2023-04-20T14:51:22Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=99bf995b-9965-4ef8-8f46-5a11df269351)
2023-04-20T14:51:22Z [Information] Trigger Details: PartionId: 1, Offset: 60129563192, EnqueueTimeUtc: 2023-04-20T14:51:21.7990000+00:00, SequenceNumber: 3100, Count: 1
2023-04-20T14:51:22Z [Information] C# IoT Hub trigger function processed a message: {"messageId":4,"deviceId":"Raspberry Pi Web Client","temperature":21.78412119821204,"humidity":76.14936941122197}
2023-04-20T14:51:22Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=99bf995b-9965-4ef8-8f46-5a11df269351, Duration=1ms)
2023-04-20T14:51:24Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=52a4220e-4b44-4723-b4c4-278da9547922)
2023-04-20T14:51:24Z [Information] Trigger Details: PartionId: 1, Offset: 60129563680, EnqueueTimeUtc: 2023-04-20T14:51:23.8930000+00:00, SequenceNumber: 3101, Count: 1
2023-04-20T14:51:24Z [Information] C# IoT Hub trigger function processed a message: {"messageId":5,"deviceId":"Raspberry Pi Web Client","temperature":24.420409860121747,"humidity":74.58519698742455}
2023-04-20T14:51:24Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=52a4220e-4b44-4723-b4c4-278da9547922, Duration=1ms)
2023-04-20T14:51:26Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=56614130-1bd2-428f-b164-7fc9b370f946)
2023-04-20T14:51:26Z [Information] Trigger Details: PartionId: 1, Offset: 60129564168, EnqueueTimeUtc: 2023-04-20T14:51:25.8770000+00:00, SequenceNumber: 3102, Count: 1
2023-04-20T14:51:26Z [Information] C# IoT Hub trigger function processed a message: {"messageId":6,"deviceId":"Raspberry Pi Web Client","temperature":23.216916301025233,"humidity":68.84637049944389}
2023-04-20T14:51:26Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=56614130-1bd2-428f-b164-7fc9b370f946, Duration=0ms)
2023-04-20T14:51:49Z [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='(null)', Id=0bc20f6f-56ce-4144-bf98-75f014497087)
2023-04-20T14:51:49Z [Information] Trigger Details: PartionId: 1, Offset: 60129564656, EnqueueTimeUtc: 2023-04-20T14:51:49.3160000+00:00, SequenceNumber: 3103, Count: 1
2023-04-20T14:51:49Z [Information] C# IoT Hub trigger function processed a message: {"sequenceNumber":"000000000000000001D923FE9CF3452400000014000000000000000000000004"}
2023-04-20T14:51:49Z [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=0bc20f6f-56ce-4144-bf98-75f014497087, Duration=0ms)
我认为最重要的两个部分。
{"deviceId":"AzureIotSim","etag":"AAAAAAAAAAE=","version":2,"properties":{"desired":{"$metadata":{"$lastUpdated":"2023-04-20T14:49:37.6237465Z"},"$version":1},"reported":{"$metadata":{"$lastUpdated":"2023-04-20T14:49:37.6237465Z"},"$version":1}}}
{"sequenceNumber":"000000000000000001D923FE9CF3452400000014000000000000000000000004"}
据我所知,这两个是“已创建”和“已断开连接”消息。
好的,可以了,现在 Azure.Messaging.EventHubs.EventData
是否按预期工作?
因此,我使用以下代码创建了一个 C# 函数应用程序(在 Visual Studio 中)(C# 7,隔离,Windows)。
using System;
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace EventHubsFunctionTest
{
public class ParseHubMessage
{
private readonly ILogger _logger;
public ParseHubMessage(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ParseHubMessage>();
}
[Function("ParseHubMessage")]
public void Run([EventHubTrigger("HUBNAME", Connection = "CONNECTIONNAME", IsBatched = false)] EventData data)
{
_logger.LogInformation("Got ContentType {ContentType}", data.ContentType);
_logger.LogInformation("Got CorrelationId {CorrelationId}", data.CorrelationId);
_logger.LogInformation("Got EnqueuedTime {EnqueuedTime}", data.EnqueuedTime);
_logger.LogInformation("Got EventBody {EventBody}", data.EventBody);
_logger.LogInformation("Got MessageId {MessageId}", data.MessageId);
_logger.LogInformation("Got PartitionKey {PartitionKey}", data.PartitionKey);
_logger.LogInformation("Got SequenceNumber {SequenceNumber}", data.SequenceNumber);
foreach(var property in data.Properties)
{
_logger.LogInformation("Got property {Key} with value {Value}", property.Key, property.Value);
}
foreach (var systemProperty in data.SystemProperties)
{
_logger.LogInformation("Got system property {Key} with value {Value}", systemProperty.Key, systemProperty.Value);
}
}
}
}
如果我现在部署它,Azure 功能将会向我返回错误。 (重复两次)
Exception while executing function: Functions.ParseHubMessage Result: Failure
Exception: Microsoft.Azure.Functions.Worker.FunctionInputConverterException: Error converting 1 input parameters for Function 'ParseHubMessage': Cannot convert input parameter 'data' to type 'Azure.Messaging.EventHubs.EventData' from type 'System.String'. Error:System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.messageId | LineNumber: 0 | BytePositionInLine: 14.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType)
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.StringConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.JsonConverter`1.ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo, ReadStack& state)
at System.Text.Json.JsonSerializer.ContinueDeserialize[TValue](ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.ReadFromStreamAsync[TValue](Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.Azure.Functions.Worker.Converters.JsonPocoConverter.GetConversionResultFromDeserialization(Byte[] bytes, Type type) in D:\a\_work\1\s\src\DotNetWorker.Core\Converters\JsonPocoConverter.cs:line 66
at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 106
at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 42
at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77
at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request, WorkerOptions workerOptions) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 84
Stack: at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 106
at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 42
at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77
at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request, WorkerOptions workerOptions) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 84
Result: Function 'ParseHubMessage', Invocation id '285058fc-38f2-4a8d-ac73-77b1bc863521': An exception was thrown by the invocation.
Exception: Microsoft.Azure.Functions.Worker.FunctionInputConverterException: Error converting 1 input parameters for Function 'ParseHubMessage': Cannot convert input parameter 'data' to type 'Azure.Messaging.EventHubs.EventData' from type 'System.String'. Error:System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.messageId | LineNumber: 0 | BytePositionInLine: 14.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType)
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.StringConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.JsonConverter`1.ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo, ReadStack& state)
at System.Text.Json.JsonSerializer.ContinueDeserialize[TValue](ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.ReadFromStreamAsync[TValue](Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.Azure.Functions.Worker.Converters.JsonPocoConverter.GetConversionResultFromDeserialization(Byte[] bytes, Type type) in D:\a\_work\1\s\src\DotNetWorker.Core\Converters\JsonPocoConverter.cs:line 66
at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 106
at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 42
at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77
Stack: at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 106
at Microsoft.Azure.Functions.Worker.Invocation.DefaultFunctionExecutor.ExecuteAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Invocation\DefaultFunctionExecutor.cs:line 42
at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77
有关如何使其发挥作用的任何建议(通过事件中心,而不是事件网格)。
至于(其他)相关问题。
Azure IoT Hub, EventHub and Functions 给我的问题多于答案。 this github 问题的链接。问题就变成了,我如何绑定(bind)到“重要的 ServiceBus 和 EventHub 消息/事件属性。”
Azure function missing IoT hub trigger messages 有问题,没有答案。
Get device ID and payload in Azure Function trigered from IoT Hub 看起来可以完成这项工作,但是 Microsoft.Azure.ServiceBus 已被弃用。
[编辑]
切换到 .net 6 就成功了。但请记住,如果您不在 Visual Studio 中开始新项目(.NET 6、LTS、非隔离)。否则更新后的项目仍然会产生错误。
最佳答案
目前无法使用 Azure Functions 的隔离模型绑定(bind)到 EventData
。为此,您需要使用进程内模型。示例可参见 here .
隔离模型需要跨进程边界传递数据,这需要主机中额外的基础设施支持。这是一个正在研究的领域,目前对某些触发器有预览级支持 - 但事件中心不在其中。更多详情可查看here .
关于azure - 如何通过事件中心获取来自 IoT 中心的 Azure 函数应用程序中的事件类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76071566/