Azure Function - How to initialize a DI injected class constructor before the HttpTrigger

Alex Perez 1 Reputation point
2022-10-21T17:14:10.467+00:00

I have an HTTP trigger Azure Function ("FUNCTIONS_WORKER_RUNTIME": "dotnet"). The function uses dependency injection, and one of the injected services is a class (FileFeedAlertProcessor) that needs to be initialized as soon as the application starts.

It seems that an HttpTrigger function will initialize all its injected services on the first call and not when the application starts. I'm struggling to find a way to build the services and get the service I want during the "Configure" method.

public class Startup : FunctionsStartup  
{  
    public override void Configure(IFunctionsHostBuilder builder)  
    {  
        builder.Services.AddSingleton<FileFeedAlertProcessor>();  
        builder.Services.AddHttpClient<HttpClientService>()  
            .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]  
        {  
            TimeSpan.FromSeconds(5),  
            TimeSpan.FromSeconds(5),  
            TimeSpan.FromSeconds(5)  
        }));  
  
        // Initialize the constructor of FileFeedAlertProcessor before the HttpTrigger.   
        builder.Services.BuildServiceProvider().GetRequiredService<FileFeedAlertProcessor>();  
  
        // The above throws: 'Unable to resolve service for type 'Microsoft.Azure.WebJobs.Script.IFileLoggingStatusManager'  
        // while attempting to activate 'Microsoft.Azure.WebJobs.Script.Diagnostics.HostFileLoggerProvider'.'  
    }  
}  

I'm able to solve this problem if I use "dotnet-insolated" function, because the HostBuilder class do have the option to build, but "dotnet-insolated" is not what I need.

var host = new HostBuilder()  
    .ConfigureFunctionsWorkerDefaults()  
    .ConfigureServices(s =>  
    {  
        s.AddSingleton<FileFeedAlertProcessor>();  
        s.AddHttpClient<HttpClientService>()  
            .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]  
            {  
                TimeSpan.FromSeconds(1),  
                TimeSpan.FromSeconds(5),  
                TimeSpan.FromSeconds(10)  
            }));  
    }).Build();  
  
// Starting the FileFeedAlertProcessor before function execution.   
host.Services.GetRequiredService<FileFeedAlertProcessor>().Start();  
  
host.Run();  

The trick I'm using is rather weird. I had to create a TimeTrigger function that runs once a year with RunOnStarup = true just to call FileFeedAlertProcessor service and initialize its constructor when the application starts.

public class FileFeedFunction  
{  
    private readonly FileFeedAlertProcessor _fileFeedAlertProcessor;  
    public FileFeedFunction(FileFeedAlertProcessor fileFeedAlertProcessor)  
    {  
        _fileFeedAlertProcessor = fileFeedAlertProcessor;  
    }  
  
    // The purpose of this TimeTrigger function is to initialize the constructor of FileFeedAlertProcessor  
    // every time the application is restarted.   
    [FunctionName("Starter")]  
    public void Starter([TimerTrigger("0 0 1 1 *", RunOnStartup = true)] TimerInfo myTimer, ILogger log)  
    {  
        _fileFeedAlertProcessor.Start();  
    }  
  
  
  
    [FunctionName("FileFeed")]  
    public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "{source}")] HttpRequest req, string source, ILogger log)  
    {  
        // Do other stuff  
    }  
  
}  

I'm sure there is a cleaner way to do this, but is not well documented.

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
4,907 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,853 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. MuthuKumaranMurugaachari-MSFT 22,311 Reputation points
    2022-10-25T19:58:23.947+00:00

    @Alex Perez Thank you for reaching out to Microsoft Q&A. Based on my understanding, you are using a dependency injection FileFeedAlertProcessor and when trying to initialize, facing the below error with line: builder.Services.BuildServiceProvider().GetRequiredService<FileFeedAlertProcessor>(); in .dotnet (works with dotnet-insolated). Is that correct?

    'Unable to resolve service for type 'Microsoft.Azure.WebJobs.Script.IFileLoggingStatusManager' while attempting to activate Microsoft.Azure.WebJobs.Script.Diagnostics.HostFileLoggerProvider'.'

    Refer to docs: Caveats which describes startup class is meant only for set up and registration and the above would not work since ILogger cannot be injected at this point. Check #5782 comment by our product team on this issue.

    254044-image.png

    Based on a discussion with our product team, IHostedService is not supported in-proc scenario (which is ultimately you want in this scenario). If you still prefer to achieve this way, then you can create either a new HostBuilder() inside the startup or a new class without DI and run it. But please note long-running classes are really not recommended. If you have any feedback related to this feature or product, feel free to submit via Azure Functions directly to our product team. I will also share the feedback internally with them.

    Also, would like to let you know that our roadmap is going to be on dotnet-isolated and refer https://techcommunity.microsoft.com/t5/apps-on-azure-blog/net-on-azure-functions-roadmap/ba-p/2197916 describing the same.

    I hope this answers your question and feel free to add a comment if you have any other questions. We would be happy to assist you. Please 'Accept as answer' and ‘Upvote’ if it helped so that it can help others in the community.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.