Home > front end >  Azure Durable Functions - where's the HostBuilder equivalent?
Azure Durable Functions - where's the HostBuilder equivalent?

Time:02-07

I'm using an Azure Durable Function to orchestrate other functions, currently contained in the same project. I want to configure services and logging for those orchestrated functions. How can I do that?

Here is some more detail:

In a "normal" Azure Function I have a Program.cs and a Main method with the following code that sets up the environment for the function execution:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureLogging(loggingBuilder => { loggingBuilder.SetMinimumLevel(LogLevel.Trace); })... etc. pp.

Using the HostBuilder I can add additional logging providers, add caching services etc. Those services are then injected via the constructor of the Azure Function.

Now in comparison when creating a Durable Function project via the VS Code "Durable Function Orchestration" template there is no Program.cs, no HostBuilder and no constructor. There are just some static methods representing the orchestrator and an orchestrated function.

As there is no out-of-the-box HostBuilder in the "Durable Function Orchestration" template - how does the HostBuilder equivalent look like for Durable Functions? Whats the pattern or convention here? Do I write it myself? Or is there some instance floating around or initialization I can hook into? Or should orchestrated functions be put into separate Azure Function projects where I can make use of the HostBuilder?

Any hints are appreciated.

CodePudding user response:

By default the ILogger instance is injected in your functions, unless you are using DI.All you need to do is Use the ILogger.

[FunctionName("funcname")]
public async static Task RunOrchestrator(
    [OrchestrationTrigger] DurableOrchestrationContext context,
    ILogger log)
{
    log.LogInformation("Starting Orchestration");
}

Check Incase if you using Dependency injection you should just do the below in your startup builder.Services.AddLogging();

Also check

CodePudding user response:

So the solution is to use a FunctionsStartup class as outlined here. This should make dependency injection work, also for Durable Functions.

For me it did not work immediately though and it took a while to figure out why. What I tried is adding an additional parameter (myService) to the static methods like so:

[FunctionName("DurableFunctionsOrchestrationCSharp1_Hello")]
public static string SayHello([ActivityTrigger] string name, ILogger log, IMyService myService)
{
    log.LogInformation($"Saying hello to {name}.");
    return $"Hello {name}!";
}

I also added the startup class according to the documentation that is supposed to provide the implementation for IMyService.

This did never work. The error I got is this:

Microsoft.Azure.WebJobs.Host: Error indexing method 'DurableFunctionsOrchestrationCSharp1_Hello'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'myService' to type IMyService. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

This error message suggests that it should work while in reality it never does.

The solution was to get rid of the static methods and use classes with constructors. Constructor injection WORKS.

The working class looks like this:

public class Activities
{
    IMyService _service;
    public Activities(IMyService service)
    {
        _service = service;
    }

    [FunctionName("DurableFunctionsOrchestrationCSharp1_Hello")]
    public string SayHello([ActivityTrigger] string name, ILogger log)
    {
        log.LogInformation($"Saying hello to {name} {_service.GetType()}.");

        return $"Hello {name}!";
    }
}

Note that I moved the function here and made it non-static.

The constructor is properly invoked, given a IMyService instance created by the Startup class and then the function is executed.

The minimal startup class I used for testing looks like this:

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace
{
    public interface IMyService
    {    
    }
    public class MyService : IMyService
    {    
    }

    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<IMyService>((s) => {
                return new MyService();
            });
        }
    }
}

So dependency injection works for Durable Functions, if you are injecting into constructors.

  •  Tags:  
  • Related