Azure / Azure/azure-functions-dotnet-worker
BindInputAsync caches without regard to type, which leads to invalid cast later
- Dominant language
- C#
- Stars
- 466
- Forks
- 215
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 7
Description
### Description
If I use `BindInputAsync(metadata)` where `T` is a base type of the actual input type, it successfully deserializes, however, the function later fails to invoke, saying it cannot cast from the base class to the actual class. I think this is because `BindInputAsync` caches the binding result regardless of what `T` is.
I want to enforce a common base class for `ActivityTrigger` inputs so that I can have middleware that can read the input for any `ActivityTrigger`.
See below... If you change the below to do `BindInputAsync()` it all works, but now the middleware isn't general enough.
### Steps to reproduce
```C#
using Azure.Messaging;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
await new HostBuilder()
.ConfigureFunctionsWorkerDefaults(x => x.UseMiddleware())
.Build()
.RunAsync();
public class MessageBase
{
public int TenantId { get; set; }
}
public class MessageA : MessageBase
{
public string Name { get; set; }
}
internal class TenantMiddleware : IFunctionsWorkerMiddleware
{
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
{
int tenantId = 0;
if (context.FunctionDefinition.InputBindings.Values.FirstOrDefault(x => x.Type == "activityTrigger") is { } activity)
{
var input = await context.BindInputAsync(activity);
tenantId = input.Value!.TenantId;
}
context.Items.Add("TenantId", tenantId);
await next(context);
}
}
public class CloudEventFunction
{
private readonly ILogger _logger;
public CloudEventFunction(ILogger logger)
{
_logger = logger;
}
[Function("CloudEventFunction")]
public async Task RunCloudEventAsync(
[EventGridTrigger] CloudEvent cloudEvent,
[DurableClient] DurableTaskClient durableTaskClient)
{
await durableTaskClient.ScheduleNewOrchestrationInstanceAsync("OrchestratorFunction");
}
[Function("OrchestratorFunction")]
public async Task RunOrchestratorAsync([OrchestrationTrigger] TaskOrchestrationContext taskOrchestrationContext)
{
var message = new MessageA { TenantId = 42, Name = "Test" };
await taskOrchestrationContext.CallActivityAsync("ActivityFunction", message);
}
[Function("ActivityFunction")]
public Task RunActivityAsync([ActivityTrigger] MessageA message, FunctionContext context)
{
_logger.LogInformation("TenantId: {TenantId}", context.Items["TenantId"]);
return Task.CompletedTask;
}
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.