Search code examples
c#azureazure-functions.net-8.0azure-functions-isolated

EventData having serialisation problem after migrating Azure function app from .NET 6 In Process to .NET 8 Isolated


I have migrated an Azure function from .NET 6 in-process to .NET 8 isolated. After the migration, everything works fine except EventData. I have a timer function which sends an array of EventData as output binding to event hub.

This is my code - this is the event hub output binding model:

using System.Diagnostics.CodeAnalysis;
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Functions.Worker;

public class RetryFailedEventHubOutputBindings
{
    public RetryFailedEventHubOutputBindings()
    {
        OutEventHub1 = [];
        OutEventHub2 = [];
    }

    [EventHubOutput("OutEventHub1", Connection = "EventHubConnection")]
    public EventData[] OutEventHub1 { get; set; }

    [EventHubOutput("OutEventHub2", Connection = "EventHubConnection")]
    public EventData[] OutEventHub2 { get; set; }
}

This is my TimeTrigger function (sender):

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Functions.Worker;
using Newtonsoft.Json;

public class RetryFailedFunction
{
    private static readonly SemaphoreSlim Semaphore = new(1, 1);
    private readonly IFailedMessageService _failedMessageService;
    private readonly IAppLogger<RetryFailedPlayerEventFunction> _logger;

    public RetryFailedFunction(IFailedMessageService failedMessageService, IAppLogger<RetryFailedPlayerEventFunction> logger)
    {
        _failedMessageService = failedMessageService;
        _logger = logger;
    }

    [Function(nameof(RetryFailedFunction))]
    public async Task<RetryFailedEventHubOutputBindings> RunAsync([TimerTrigger("%ScheduleTriggerTime%")] TimerInfo myTimer)
    {
        var outputBindings = new RetryFailedEventHubOutputBindings();

        outputBindings.EventHub2.Append(new EventData(Encoding.UTF8.GetBytes("{\"ErrorId\": 10}")));

        return outputBindings;
    }
}

This is the event hub trigger function (receiver):

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
using System.Threading.Tasks;
using Azure.Messaging.EventHubs;
using Microsoft.Azure.Functions.Worker;
using Newtonsoft.Json;

public class ReceiverFunction
{
    private readonly IErrorRepository _errRepo;
    private readonly IRawEventHandler _rawEventHandler;
    private readonly IProductValidationHelper _productValidationHelper;
    private readonly IAppLogger<GenPlayerEventFromDepositsFunction> _logger;
    private readonly IUpdateRetryStatusService _updateRetryStatusService;

    public ReceiverFunction(IErrorRepository errRepo, IUpdateRetryStatusService updateRetryStatusService, IRawEventHandler rawEventHandler, IProductValidationHelper productValidationHelper, IAppLogger<GenPlayerEventFromDepositsFunction> logger)
    {
        _errRepo = errRepo;
        _updateRetryStatusService = updateRetryStatusService;
        _rawEventHandler = rawEventHandler;
        _productValidationHelper = productValidationHelper;
        _logger = logger;
    }

    [Function(nameof(ReceiverFunction))]
    [EventHubOutput("SomeEventHub", Connection = "EventHubConnection_1")]
    public async Task<string[]> RunAsync([EventHubTrigger("EventHub2", Connection = "EventHubConnection", ConsumerGroup = "%EventHubConsumerGroup%")] EventData[] inputEvents)
    {
        var outputEvents = new List<string>();
 
        foreach (var eventData in inputEvents)
        {
            // Event processing logic
        }
    }
}

This is what I see in output, instead of actual data it's showing just datatype in output:

Screenshot

These are changes in my package of function app after migration:

Screenshot

As shown in first image, I'm not receiving expected data in receiver event hub, instead it's just showing data type.

If I change then data type to any other type like string[] or string or any other strongly type, then it's working without any issues, problem is only for EventData, either it's EventData array or just EventData.

And EventData[] was also working in old code, before migration.

Can you please help me with this issue, is there any limitation with .NET 8 isolated Azure function for EventData, or am I doing something wrong here?


Solution

  • Yes, Indeed EventData[] or EventData type is not yet supported in EventHub output binding for isolated worker model.

    You can refer to the isolated output binding usage doc which says while writing a single event, event hub output binding can bind to string, byte[], JSON serializable types in isolated function.

    Whereas for in-process model output binding, it supports Azure.Messaging.EventHubs.EventData, string, byte[], - Plain-old CLR object (POCO) types.

    As you have correctly identified by changing the type to string or any other type apart from EventData, it works in isolated worker model.

    I have the below given code which works for me.

    public class RetryFailedEventHubOutputBindings
    {
        public RetryFailedEventHubOutputBindings()
        {
            OutEventHub1 = [];
            OutEventHub2 = [];
        }
    
        [EventHubOutput("OutEventHub1", Connection = "EventHubConnection")]
        public string[] OutEventHub1 { get; set; }
    
        [EventHubOutput("OutEventHub2", Connection = "EventHubConnection")]
        public string[] OutEventHub2 { get; set; }
    }
    

    Sender function :-

    [Function("RetryFailedFunction")]
    public async Task<RetryFailedEventHubOutputBindings> Run([TimerTrigger("0 */2 * * * *")] TimerInfo myTimer)
    {
        var outputBindings = new RetryFailedEventHubOutputBindings
        {
            OutEventHub2 = new[] { JsonConvert.SerializeObject(new { ErrorId = 10 }) }
        };
    
        return outputBindings;
    }
    

    Receiver function :-

    [Function(nameof(ReceiverFunction))]
    public void Run([EventHubTrigger("OutEventHub2", Connection = "EventHubConnection")] EventData[] events)
    {
        foreach (EventData @event in events)
        {
            _logger.LogInformation("Event Body: {body}", @event.EventBody);
        }
    }
    

    Response :-

    Azure Functions Core Tools
    Core Tools Version:       4.0.6821 Commit hash: N/A +c09a2033faa7ecf51b3773308283af0ca9a99f83 (64-bit)
    Function Runtime Version: 4.1036.1.23224
    
    [2025-01-16T05:41:40.732Z] Found C:\Users\*****\79358853\79358853\79358853.csproj. Using for user secrets file configuration.
    [2025-01-16T05:41:43.559Z] Azure Functions .NET Worker (PID: 15628) initialized in debug mode. Waiting for debugger to attach...
    [2025-01-16T05:41:43.595Z] Worker process started and initialized.
    
    Functions:
    
            ReceiverFunction: eventHubTrigger
    
            RetryFailedFunction: timerTrigger
    
    For detailed output, run func with --verbose flag.
    [2025-01-16T05:41:43.877Z] Executing 'Functions.RetryFailedFunction' (Reason='Timer fired at 2025-01-16T11:11:43.8573126+05:30', Id=e21ae124-c14b-4b04-9296-718971f04fe2)
    [2025-01-16T05:41:43.879Z] Trigger Details: UnscheduledInvocationReason: IsPastDue, OriginalSchedule: 2025-01-16T10:58:00.0000000+05:30
    [2025-01-16T05:41:46.900Z] Executed 'Functions.RetryFailedFunction' (Succeeded, Id=e21ae124-c14b-4b04-9296-718971f04fe2, Duration=3038ms)
    [2025-01-16T05:41:48.456Z] Executing 'Functions.ReceiverFunction' (Reason='(null)', Id=4921187d-8ffe-43e0-a839-b44229ef83fa)
    [2025-01-16T05:41:48.457Z] Trigger Details: PartionId: 0, Offset: 640-640, EnqueueTimeUtc: 2025-01-16T05:41:46.8190000+00:00-2025-01-16T05:41:46.8190000+00:00, SequenceNumber: 8-8, Count: 1
    [2025-01-16T05:41:48.523Z] Event Body: {"ErrorId":10}
    [2025-01-16T05:41:48.524Z] Executed 'Functions.ReceiverFunction' (Succeeded, Id=4921187d-8ffe-43e0-a839-b44229ef83fa, Duration=81ms)