HttpClient best practices in Azure Functions

15,058

Solution 1

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

Solution 2

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:

public class MyInjectedFunction
{
    private readonly HttpClient _http;
    
    public MyInjectedFunction(HttpClient httpClient)
    {
        _http = httpClient;
    }
    
    [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.

Share:
15,058
RPM1984
Author by

RPM1984

~ Past ~: Mainframes (Model 204, JCL) Java (J2SE, J2EE) Oracle VB.NET ASP.NET Web Forms/MVC ~ Present ~ .NET Core TDD, DDD (all the DDs!) Microservices Containers

Updated on July 22, 2022

Comments

  • RPM1984
    RPM1984 almost 2 years

    I need to build an Azure Function that:

    • Responds to a HTTP POST request
    • Does 7x HTTP HEAD requests based on the data.

    I've found some guidance here and here

    But, it's not entirely clear what to do, and how it works?

    As in the second link, i've currently just declared a private static HttpClient httpClient = new HttpClient(); instance, and re-used that in my 7x HTTP HEAD calls.

    My questions:

    1. Is that the most efficient use of HttpClient in a stateless Azure function?
    2. I'm currently just building up a List<Task>() for the http calls, then doing Task.WhenAll(tasks) on them to run them in parrallel. Would that be the quickest way to do these calls? Any other suggestions?

    This Function endpoint will be called a lot (multiple times a second), so need to be as efficient as possible to keep costs down.

    Thanks!

  • RPM1984
    RPM1984 almost 6 years
    Thanks. That article is 2016 though? Is there nothing more recent showing it's still the best way? Not doubting you, just want to make sure :)
  • Josh Carlisle
    Josh Carlisle almost 6 years
    At least in regards to 1.x of Azure Functions and the .net framework 4.x not a lot has changed that would affect the guidance since 2016 :) Azure Functions 2.x though may bring in some new options\best practices since it sits on .net core 2.1 . I suspect the guidance will largely be the same (maximize reuse) but there is some new httpclient related constructs such as HttpClientFactory (stevejgordon.co.uk/introduction-to-httpclientfactory-aspnet‌​core) that may introduce some new or additional options\guidance.
  • Zordid
    Zordid over 5 years
    This solution really is NOT a correct usage of HttpClient in general. Holding one instance is also wrong als DNS changes don't get through. You will eventually lose all connectivity. That's why there is HttpClientFactory - but only in ASP .Net Core 2.1. My question now is: what should we do now?
  • Zhaph - Ben Duguid
    Zhaph - Ben Duguid almost 5 years
    @RPM1984 - Official documentation from Microsoft on this can be found here. However as Zordid mentions, if you can use the newer HttpClientFactory that's better.
  • HisDivineShadow
    HisDivineShadow over 3 years
    I read this in the Azure docs but it's not clear about how it's creating the HttpClient in the function. Apparently Azure functions have a host DI container that is "holding" every requested instance of the function and providing the HttpClient as a singleton to ALL function instances and therefore you cannot change the BaseUri after the first time it's been configured. So, if it's in fact a singleton and can't be modified then where is the appropriate place to configure the HttpClient?