question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Error creating an IFunctionProvider with a non-static trigger

See original GitHub issue

I have an IFunctionProvider implementation for an Azure Function that creates a route for /healthcheck. The entrypoint for my function metadata is a method called Somenamespace.TestTrigger.RenderHealthCheck. My code looks like this:

    public class TestTrigger
    {
        public static async Task<IActionResult> RenderHealthCheck(HttpRequest req)
        {
            return new OkObjectResult("OK");
        }        
    }
    
    public class HealthCheckTrigger : IFunctionProvider
    {
        public ImmutableDictionary<string, ImmutableArray<string>> FunctionErrors { get; }
        
        public async Task<ImmutableArray<FunctionMetadata>> GetFunctionMetadataAsync()
        {
            var assembly = Assembly.GetExecutingAssembly();
            
            var functionMetadata = new FunctionMetadata()
            {
                Name = nameof(TestTrigger.RenderHealthCheck),
                FunctionDirectory = null,
                ScriptFile = $"assembly:{assembly.FullName}",
                EntryPoint = $"{typeof(TestTrigger).FullName}.{nameof(TestTrigger.RenderHealthCheck)}",
                Language = "DotNetAssembly"
            };

            var jo = JObject.FromObject(new HttpBindingMetadata()
            {
                Methods = new List<string> { HttpMethods.Get },
                Route = "HealthCheck",
                AuthLevel = AuthorizationLevel.Anonymous,
            });
            
            var binding = BindingMetadata.Create(jo);
            functionMetadata.Bindings.Add(binding);            
            
            var functionMetadataList = new List<FunctionMetadata>
            {
                functionMetadata
            };

            return await Task.FromResult(functionMetadataList.ToImmutableArray()).ConfigureAwait(false);
        }
    }

This works fine, and when I run the function and hit the /HealthCheck endpoint I get my OK message. However, I’d like to make the RenderHealthCheck method non-static, so I can use dependency injection in the constructor and access various services in my application. I changed my code to:

public class TestTrigger
{
    private readonly HealthCheckService healthCheckService;
    
    public TestTrigger(HealthCheckService healthCheckService)
    {
        this.healthCheckService = healthCheckService;
    }

    public async Task<IActionResult> RenderHealthCheck(HttpRequest req)
    {
        return new OkObjectResult("OK");
    }        
}

Now, when I hit the endpoint, I get the following exception:

Executed 'Functions.RenderHealthCheck' (Failed, Id=c02a9ba6-1ed3-4c07-8b38-214d345b6ff1, Duration=488ms)
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.RenderHealthCheck
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at lambda_method(Closure , TestTrigger , Object[] )
   at Microsoft.Azure.WebJobs.Host.Executors.TaskMethodInvoker`2.InvokeAsync(TReflected instance, Object[] arguments) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\TaskMethodInvoker.cs:line 21
   at Microsoft.Azure.WebJobs.Script.Description.DotNetFunctionInvoker.MethodInvoker`2.InvokeAsync(Object target, Object[] parameters) in D:\a\1\s\src\WebJobs.Script\Description\DotNet\DotNetFunctionInvoker.cs:line 533
   at Microsoft.Azure.WebJobs.Script.Description.DotNetFunctionInvoker.InvokeCore(Object[] parameters, FunctionInvocationContext context) in D:\a\1\s\src\WebJobs.Script\Description\DotNet\DotNetFunctionInvoker.cs:line 272
   at Microsoft.Azure.WebJobs.Script.Description.FunctionInvokerBase.Invoke(Object[] parameters) in D:\a\1\s\src\WebJobs.Script\Description\FunctionInvokerBase.cs:line 82
   at Microsoft.Azure.WebJobs.Script.Description.FunctionGenerator.Coerce[T](Task`1 src) in D:\a\1\s\src\WebJobs.Script\Description\FunctionGenerator.cs:line 225
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync(Object instance, Object[] arguments) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionInvoker.cs:line 52
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeWithTimeoutAsync(IFunctionInvoker invoker, ParameterHelper parameterHelper, CancellationTokenSource timeoutTokenSource, CancellationTokenSource functionCancellationTokenSource, Boolean thro
wOnTimeout, TimeSpan timerInterval, IFunctionInstance instance) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 555
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithWatchersAsync(IFunctionInstanceEx instance, ParameterHelper parameterHelper, ILogger logger, CancellationTokenSource functionCancellationTokenSource) in C:\projects\azure-webjobs-sdk-r
qm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 503
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(IFunctionInstanceEx instance, FunctionStartedMessage message, FunctionInstanceLogEntry instanceLogEntry, ParameterHelper parameterHelper, ILogger logger, CancellationToken
 cancellationToken) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 281
   --- End of inner exception stack trace --

I didn’t see anything in the FunctionMetadata or HttpBindingMetadata that seems to control if the entrypoint is static.

Repro steps

Run code above and verify it works if the method is static. Now try running as an instance method.

Expected behavior

Both static and instance methods should be supported for functions, just like those bound with a functions.json file.

Actual behavior

Only static methods are supported.

Known workarounds

One hacky workaround would be to make the constructor set a static property which could then be used by the static trigger method. I’d rather stay away from static properties for a variety of reasons.

Related information

Also posted this question on StackOverflow

  • Package version

This is using Azure Functions v3 on .NET Core 3.1.

  • Links to source

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
MikeChristensencommented, Nov 8, 2021

@eminencegrs Nope, didn’t solve it. My work around is to make the trigger static, and now I have to set static properties in the constructor so I can access DI services. Kinda hacky, but it works for my use-case. I agree this is a bug and should be fixed. The entire IFunctionProvider mechanism seems unstable and undocumented, I think it’s a feature not really meant for production use yet.

0reactions
fabiocavcommented, Mar 14, 2022

@MikeChristensen apologies for the delayed response here, but you’re correct in your last comment. This is something that was introduced with a very narrow scope to support internal requirements and not positioned as a publicly supported feature, so it hasn’t really seen a lot of investment.

I’ll leave this open to track, but at the moment, there are no plans to make changes to this functionality.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Creating an IFunctionProvider with a non-static trigger
I have an IFunctionProvider implementation for an Azure Function that creates a route for /healthcheck . The entrypoint for my function ...
Read more >
Creating an IFunctionProvider with a non-static trigger
For Azure DocumentDB input binding, Is there a way to get the document id from the headers? Terraform script for Traffic Manager throws...
Read more >
Creating an IFunctionProvider with a non-static trigger - Coding ...
How to create api in azure that uploads file from SFTP to azure data lake storage · Error The parameter LinuxFxVersion has an...
Read more >
Troubleshoot issues with the Azure Functions trigger for ...
This article discusses common issues, workarounds, and diagnostic steps when you're using the Azure Functions trigger for Azure Cosmos DB.
Read more >
I need 3 different type triggered azure function in a single ...
I need to create a project with three different types of Azure Functions triggers: HTTP, Timer, and Queue. I want to have all...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found