HttpClient best practices in Azure Functions

Yes - this is still the current guidance for Azure Functions 1.x (and applies to 2.x as well) to best avoid socket exhaustion. The static variable will ensures that it will be shared against all instances of the class. Another good article that covers this topic is https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong


As of 2019, and v2/v3+ of the runtime, you also have the option to use dependency injection in .NET Azure Functions. Be aware that this only applies to .NET functions (C#), and AFAIK is not available for the other flavours, like Python, JavaScript/TypeScript etc.

Simple answer is that you can add a Startup.cs class to your Azure Function where your register the dependencies:

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

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        // Note: Only register dependencies, do not depend or request those in Configure().
        // Dependencies are only usable during function execution, not before (like here).
        
        builder.Services.AddHttpClient();
        // builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
    }
}

Pretty much the same as any other web/api project with dotnet core. Next, in your function itself, add a constructor and register the dependencies as parameters. You also want to remove the static modifier from your function. An example: ref :https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#register-services

public class MyInjectedFunction
{
    private readonly HttpClient _http;
    
    public MyInjectedFunction(IHttpClientFactory httpClientFactory)
    {
        _http = httpClientFactory.CreateClient();
    }
    
    [FunctionName("my-injected-function")]
    public async Task RunAsync([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
    {
        var response = await _http.GetAsync("https://stackoverflow.com");
        
        if (response.IsSuccessStatusCode)
            log.LogInformation("Okidoki");
        else
            log.LogError($"{response.StatusCode} {response.ReasonPhrase}: ");
    }
}

By using DI you can explicitly register it as singleton as well. Or created typed HttpClients. And personally, I think this is quite elegant.