azure - 如何通过事件中心获取来自 IoT 中心的 Azure 函数应用程序中的事件类型

标签 azure azure-functions azure-iot-hub azure-eventhub

目前我有一个 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.EventDataAzure.Messaging.EventHubs.EventData 这个选项似乎在途中丢失了。

所以我的设置: 作为 IoT 设备,我使用 https://azure-samples.github.io/raspberry-pi-web-simulator/(我确实必须注释掉所有 LEDPin 行)

在我的 IoT 中心中,我添加了以下路由。 IoT hub routes

接下来,我使用以下(默认)代码制作了一个函数应用程序(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/

相关文章:

azure - Azure的 "Service Configuration"存储在哪里?

visual-studio-2010 - Visual Studios 2010 SP1 "Unable to copy file ' ...\.svn\all-wcprops' 访问路径 'bin\\.svn\all-wcprops' 被拒绝”

azure - 仅获取与 Azure CLI 中的特定字符串相似的网卡名称

c# - 为什么Azure Functions不支持System.Text.Json,而每个人在示例中都使用NewtonSoft?

azure - 如何从 Azure 登录到外部程序?

python - Azure IoT 中心设备消息和路由筛选器

asp.net-mvc - 在 MVC 项目中将 Azure 与 Ninject InSessionScope 类结合使用

node.js - Azure Function App 对 Webhook 的初始响应

c# - IoT Edge SendEventBatchAsync

azure - ESP8266 未连接到 Azure Iot Hub,返回状态 -2