Azure / azure-functions-dotnet-worker

Azure Functions out-of-process .NET language worker
MIT License
431 stars 184 forks source link

[Question] Can you access function parameter attributes from within middleware, and inject values. #1409

Open Jezternz opened 1 year ago

Jezternz commented 1 year ago

Basically I am often found utilizing a watermark pattern to track ingestion progress inside a .net 7 timer trigger function.

I thought it would be nice to utilize middleware to run all the relevant logic. My hope was that I could define my functions something like this:

[Function("IngestionTimerTrigger")]        
public void Run(
    [TimerTrigger("* * * * *")] MyInfo myTimer,
    [WatermarkHandler("Key", "00:15:00")] WatermarkWindow window
)
{     
    ...

So basically I need my middleware to:

I have given it a shot, but have fallen flat pretty fast:

internal sealed class FunctionMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        // I can't find where in context I can in theory retrieve information about the parameter attributes (see if WatermarkHandler attribute exists on a parameter) and their values (retrieve "Key", "00:15:00").
        // I thought maybe:
        // context.FunctionDefinition

        // I figured I may be able to feed in the value for WatermarkWindow window via Items, but not sure about this.
        // context.Items

        await next(context);

Hopefully I have been clear enough. I wondered if I could avoid reflection here, but I suspect not.

Jezternz commented 1 year ago

Digging into this more, I think what I am more specifically looking for is Custom Input Bindings. From reading here (repo), it seems that it is possible in .net 7 isolated, but requires you to setup a package for your binding, then another package to act as bridge to your .net 7 isolated process (totaling 3 separate). I don't suppose it is sitting on the isolated worker roadmap to add better support for custom bindings - unless I have missed something?

fabiocav commented 1 year ago

@Jezternz the pattern described in the post you've found is how input bindings (Azure Functions input bindings) are exposed to the worker.

Currently, we're not actively tracking an enhancement for extensibility that aligns exactly with what you're looking for here, but there are some features that will be landing soon and will give you something close, and hopefully that would be enough to unblock your scenario. This will give you the ability to use a converter mapping attribute and handle the input (parameter binding) from that converter. With the example you have above, you could add any information you need to use in your converter to the function context.

The attribute won't be easily available to you in this initial implementation, but that is something we're tracking as an enhancement.

The feature that will bring the capability is tracked by #164 , so you can follow this (and look at the associated PR when opened) for updates and more context.

sahalsaad commented 6 months ago

I am using the following code to access the attribute.

var entryPoint = context.FunctionDefinition.EntryPoint;
var lastIndex = entryPoint.LastIndexOf('.');
var typeName = entryPoint[..lastIndex];
var methodName = entryPoint[(lastIndex + 1)..];
var requiredScopes = Type.GetType(typeName)?.GetMethod(methodName)?.GetCustomAttribute<MyOwnCustomAttribute>()?.Test;