Azure Isolated Function .NET 8: All HttpClient requests result in timeout error (works locally, not in Azure)

Evan Levy 20 Reputation points
2025-01-08T19:26:28.8266667+00:00

I have a .NET 8 Azure Function using the Isolated model, which has a function that makes an external REST API call via HttpClient. The API call was previously working on the in-process model .NET 6 version without issue. After migrating to the isolated model with .NET 8, the API call consistently returns a timeout error: System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing. I have tried different API endpoints and all result in the same timeout error when running in Azure. However, this code works locally without issue. I have also taken the bearer token produced in the code (via logging) and attempted the exact same API call via the Postman application, in which the API call completes within less than a second successfully. When running in Azure, it seems to completely hang when it attempts the API call.

FYI the API call is routing to an Azure App Service .NET REST API. From what it looks like from the App Service's log stream, it does not appear that any action is happening when the API call initiates from the Function App. I also tested calling https://google.com in an additional request and this was successful when running from Azure. So could this be a networking issue between the Function App and App Service? If so, why would this happen for the isolated model but worked for the in-process model? We have a VNET configured for Outbound Traffic on the Function App and App Service, so would that be a potential issue when migrating to the isolated model?

Here is sample code of what I am attempting to get working.

Program.cs

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureFunctionsWebApplication()
            .ConfigureServices(services =>
            {
                services.AddHttpClient();
            })
            .Build();
        await host.RunAsync();
    }
}

SampleFunction

public class SampleFunction
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<SampleFunction> log;
    private string tokenEndpoint = "https://" + System.Environment.GetEnvironmentVariable("token_endpoint");
    public SampleFunction(ILogger<SampleFunction> logger, IHttpClientFactory factory)
    {
        log = logger;
        _httpClient = factory.CreateClient();
    }
    public KeyValuePair<string, string>[] GetBackendAppSettings()
    {
        var data = new[]
        {
            new KeyValuePair<string, string>("grant_type", "client_credentials"),
            new KeyValuePair<string, string>("client_id", System.Environment.GetEnvironmentVariable("client_id")!),
            new KeyValuePair<string, string>("client_secret", System.Environment.GetEnvironmentVariable("client_secret")!),
            new KeyValuePair<string, string>("scope", System.Environment.GetEnvironmentVariable("scope")!)
        };
        return data;
    }
    public async Task<string?> GetClientAuthToken()
    {
        string endpoint = tokenEndpoint;
        var response = await _httpClient.PostAsync(endpoint, new FormUrlEncodedContent(GetBackendAppSettings()));
        var accessToken = await response.Content.ReadAsStringAsync();
        var deToken = JsonConvert.DeserializeObject<dynamic>(accessToken);
        var token = (string?)deToken!["access_token"];
        return token;
    }
    [Function("SampleFunction")]
    public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
    {
        try
        {
			var token = await GetClientAuthToken();
			string apiURL = string.Format("https://" + System.Environment.GetEnvironmentVariable("api_url") + "/api/[REDACTED]");
            using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, apiURL))
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
                var response = await _httpClient.SendAsync(requestMessage);
                var apiResponse = await response.Content.ReadAsStringAsync();
            }
        }
        catch (Exception ex)
        {
            log.LogError(ex.Message);
            log.LogError(ex.StackTrace);
        }
    }
}


Additionally, here are relevant package versions installed on the project:

<PackageReference Include="Azure.Identity" Version="1.13.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Abstractions" Version="1.3.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.3.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,319 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,042 questions
{count} votes

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.