Stanza
Stanza

Reputation: 565

"Value cannot be null. (Parameter 'logger')" - Durable Function Activity

I have the following activity function:

 [FunctionName("LoadSubscriptionAnalytics_Activity")]
        public static async Task<IActionResult> RunActivity([ActivityTrigger] ILogger log
        )
        {                              
            log.LogInformation("Activity function");
        }

Log.LogInformation fails with error: Value cannot be null. (Parameter 'logger')

The logger works in my orchestrator function:

 [FunctionName("LoadSubscriptionAnalytics_Orchestrator")]
        public static async Task<List<Task<IActionResult>>> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            var outputs = new List<Task<IActionResult>>();
         
            log.LogInformation("Orchestrator function");
            
            outputs.Add(await context.CallActivityAsync<Task<IActionResult>>("LoadSubscriptionAnalytics_Activity", null));          
           
            return outputs;
        }

Why is this dependency injection not working? I am using Functions V2 with .Net Core 3.1

Upvotes: 1

Views: 8897

Answers (2)

Stanza
Stanza

Reputation: 565

I managed to resolve it, had to pass a context object -IDurableOrchestrationContext context from the orchestrator so that the activity function could detect it as a parameter. My code is:

Orchestrator

[FunctionName("LoadSubscriptionAnalytics_Orchestrator")]
        public static async Task<List<Task<IActionResult>>> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            var outputs = new List<Task<IActionResult>>();

            log = context.CreateReplaySafeLogger(log);
            log.LogInformation("Calling LoadSubscriptionAnalytics_Activity");
            outputs.Add(await context.CallActivityAsync<Task<IActionResult>>("LoadSubscriptionAnalytics_Activity", context));

            log.LogInformation("Done !");
           
            return outputs;
        }

Activity

[FunctionName("LoadSubscriptionAnalytics_Activity")]
        public static async Task<IActionResult> RunActivity([ActivityTrigger] IDurableActivityContext activityContext, ILogger log
        )
        {
            //This works               
            log.LogInformation("Activity function");
        }

Thanks

Upvotes: 2

Dai
Dai

Reputation: 155145

  • LogInformation is an extension-method for ILogger, defined in Microsoft.Extensions.Logging.Abstractions.dll.

  • Because it's an extension-method rather than a real instance method, when it's invoked it's the same as a static method call, and the .NET runtime will not check that the subject/instance reference is null or not - so you don't get a NullReferenceException.

    • Which can be useful, actually - I have my own utility library with a syntactically-succinct extension-method alternative to String.IsNullOrWhiteSpace:

      // Declaration:
      public static Boolean IsSet( this String str ) => !String.IsNullOrWhiteSpace( str ):
      
      // Usage:
      String x = null;
      Console.WriteLine( x.IsSet() ); // Prints "false" with no NullReferenceException
      
  • So in your case, when log.LogInformation("Activity function"); runs, the log argument to RunActivity is null.

  • I assume log is intended to be optional - so use ?. to skirt around it - or if it's required then throw your own ArgumentNullException exception:

[FunctionName("LoadSubscriptionAnalytics_Activity")]
public static async Task<IActionResult> RunActivity( [ActivityTrigger] ILogger log )
{
    log?.LogInformation("Activity function");
}

[FunctionName("LoadSubscriptionAnalytics_Activity")]
public static async Task<IActionResult> RunActivity( [ActivityTrigger] ILogger log )
{
    if( log is null ) throw new ArgumentNullException( nameof(log) );
    log.LogInformation("Activity function");
}
  • As for why the log parameter's argument is null in the first place - have you configured your DI container correctly in ConfigureServices? I'll admit I'm not too familiar with Azure Durable Functions - but in .NET in general DI is only set-up for constructors, not static methods - though some environments do allow DI use for static method parameters.

Upvotes: 0

Related Questions