Azure-functions-host: HttpClientFactory + DryIoc.ContainerException

Created on 2 Apr 2020  路  17Comments  路  Source: Azure/azure-functions-host

Issue Description

We are building RESTFul backend using Azure Functions. We are leveraging HttpClientFactory via DI which seems to work for about an hour and then starts to throw following exception:

exception:DryIoc.ContainerException: Scope disposed{no name, Parent=disposed{no name}} is disposed and scoped instances are disposed and no longer available.

Side note: our issue resembles the bug reported here #5590.

Investigative information

  • Timestamp: March 31, 2020
  • Function App version: Runtime version is 3.0.13139.0 (~3)
  • Function App name: not providing
  • Function name(s) (as appropriate): not providing
  • Invocation ID: 6a5cacf8-c872-41c4-a940-cadf712e5b5a and 04/01/2020 19:32:28
  • Region: west us 2

Project Setup:

Nuget packages: note removed few packages that were not relevant

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
    <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.7.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.0.2" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.3" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<ItemGroup>

Startup (DI registration):
```c#
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddTransient();

        ... other services here ....
    }
}
API Service:
```c#
public class APIService : IAPIService
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public ApiService(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        public void MakeRequest()
        {
            var httpClient = _httpClientFactory.CreateClient();
            httpClient.PostAsync(...);
        }
    }

Function Call:
```c#
public class MyFunction
{
private readonly IAPIService _apiService;

    public MyTrigger(IAPIService apiService)
    {
        _apiService = apiService;
    }

// Runs every hour
[FunctionName(nameof(MyTimerTrigger))]
public async Task MyTimerTrigger([TimerTrigger("0 23 * * * *", RunOnStartup = false)]TimerInfo timerInfo, ILogger logger)
{
logger.LogStartFunction();

        await _apiService.Process();

        logger.LogExitFunction();
    }
#### Expected behavior
This timer based function and other RESTFul functions continue to serve requests.

#### Actual behavior
After one hour or so of being operational, all services start returning 500 and following exception is logged in the App Insight:
> Exception: function:MyFunctions.MyEndPoint msg: exception:DryIoc.ContainerException: Scope disposed{no name, Parent=disposed{no name}} is disposed and scoped instances are disposed and no longer available.
   at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 8990
   at DryIoc.Scope.TryGet(Object& item, Int32 id) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7880
   at DryIoc.Container.InstanceFactory.GetAndUnwrapOrDefault(IScope scope, Int32 factoryId) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1479
   at DryIoc.Container.InstanceFactory.GetInstanceFromScopeChainOrSingletons(IResolverContext r) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1468
   at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, Object serviceKey, IfUnresolved ifUnresolved, Type requiredServiceType, Request preResolveParent, Object[] args) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 307
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(Exception source)
   at System.Linq.Expressions.Interpreter.ExceptionHelpers.UnwrapAndRethrow(TargetInvocationException exception)
   at System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Run(InterpretedFrame frame)
   at System.Linq.Expressions.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Linq.Expressions.Interpreter.LightLambda.Run(Object[] arguments)
   at Thunk(Func`2 , IResolverContext )
   at DryIoc.Container.ResolveAndCacheDefaultFactoryDelegate(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 223
   at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 194
   at Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection.ScopedServiceProvider.GetService(Type serviceType) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\ScopedServiceProvider.cs:line 25
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry(String name)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass14_0.<.ctor>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String name)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String name)
   at System.Net.Http.HttpClientFactoryExtensions.CreateClient(IHttpClientFactory factory)

#### Possible workarounds (do not know if following is MS recommended approach)
Since DI is not supported for HttpClient, we will manually create an instance and use that.

```c#
public class APIService : IAPIService
    {
        private readonly HttpClient _client;

        public APIService()
        {
            _client = new HttpClient();
        }

        [FunctionName("GetPosts")]
        public async Task<IActionResult> Get(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = "posts")] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            var res = await _client.GetAsync("https://microsoft.com");
            await _service.AddResponse(res);

            return new OkResult();
        }
    }

Most helpful comment

@ankitkumarr @fabiocav We are seeing this issue as well. We are an internal MS team so if you would like us to share more details directly with you, just let me know.

All 17 comments

+@fabiocav
Had an internal customer report for this issue as well.

Also seeing this same error. Is there an update? We're using durable functions, and the orchestration that got this exception is in a hanging state, where it's running. The control queues are empty so i can't get it to continue after restarting the function app

@ankitkumarr @fabiocav We are seeing this issue as well. We are an internal MS team so if you would like us to share more details directly with you, just let me know.

Seeing this behavior as well. :(

our team is geeting the same error. Can't inject IHttpClientFactory in AZF.
We're using Microsoft.Extensions.Http Version="3.1.5", Microsoft.NET.Sdk.Functions Version="1.0.31", Microsoft.Extensions.Http Version="3.1.5"

I'm also experiencing this error in azure functions.

Same here :(

Same here :/

Have created a custom trigger which uses the IHttpClientFactory to create a named client in the IListner it uses to refresh information.
Works as expected on startup, but after ~2 hours it starts to fail.

Tried to instead pass inn a IServiceProvider, with using (var scope = sp.CreateScope()) { ... }, to get a new ihttpclientfactory. Changed the code to refresh info every 1 minute.
The next call to var factory = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>(); var client = factory.CreateClient("myName"); failed when trying to create the new client immediatly.

Microsoft.NET.Sdk.Functions 3.0.7

Our team is experiencing the same issue.
Tried to bump referenced Microsoft nuget packages to latest versions, but still fails.
Last tested using Microsoft.NET.Sdk.Functions 3.0.7

We're also facing the same issue, any news on this one?

Anyone here in this tread, looking into this with Priority. Its like a dead end. Not sure what is to be done to solve this annoying and weird issue.
Is there any connection with having async call ? My first async call works fine, then the next call to the same object fails, where its again trying to get the service using
using (var scope = _serviceScopeFactory.CreateScope())
{
return (T)scope.ServiceProvider.GetRequiredService(typeof(T));
}
This statement : (T)scope.ServiceProvider.GetRequiredService(typeof(T)); gives the following error.
Scope disposed{no name} is disposed and scoped instances are disposed and no longer available

I'm working in durable functions, .NET Core 3.1, - I've had no luck injecting IHttpClientFactory, nor HttpClient.

Is this issue still outstanding?

No workaround. Problem is with scoped DI entities
See https://github.com/Azure/azure-functions-host/issues/4914

i麓m with the same error

the code:

    public class WebClientService : IWebClientService
    {
        private readonly IHttpClientFactory _httpClientFactory;

       public WebClientService(IHttpClientFactory httpClientFactory)
       {
           _httpClientFactory = httpClientFactory;
       }


    public async Task<HttpResponseMessage> PostAsync(string url, string body, Dictionary<string, string> headers = null)
    {
        using (var client = _httpClientFactory.CreateClient())
        {
            if (headers != null)
            {
                foreach (var head in headers)
                {
                    client.DefaultRequestHeaders.Add(head.Key, head.Value);
                }
            }

            HttpContent httpContent = new StringContent(body, Encoding.UTF8, "application/json");

            return await client.PostAsync(url, httpContent);
        }
    }
}

Message: Scope disposed{no name, Parent=disposed{no name, Parent=disposed{no name, Parent=disposed{no name}}}} is disposed and scoped instances are disposed and no longer available.

StackTrace: at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 9000rn at DryIoc.Scope.TryGet(Object& item, Int32 id) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7890rn at DryIoc.Container.InstanceFactory.GetAndUnwrapOrDefault(IScope scope, Int32 factoryId) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1481rn at DryIoc.Container.InstanceFactory.GetInstanceFromScopeChainOrSingletons(IResolverContext r) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1467rn at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, Object serviceKey, IfUnresolved ifUnresolved, Type requiredServiceType, Request preResolveParent, Object[] args) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 309rn at lambda_method(Closure , IResolverContext )rn at DryIoc.Container.ResolveAndCacheDefaultFactoryDelegate(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 225rn at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 196rn at Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection.ScopedServiceProvider.GetService(Type serviceType) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\ScopedServiceProvider.cs:line 25rn at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)rn at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServiceTrn at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry(String name)rn at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass14_0.<.ctor>b__1()rn at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Lazy1.CreateValue()rn at System.Lazy1.get_Value()\r\n at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String name)\r\n at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String name)\r\n at System.Net.Http.HttpClientFactoryExtensions.CreateClient(IHttpClientFactory factory)\r\n at Marketplace.B2C.Offers.Infra.Services.WebClientService.PostAsync(String url, String body, Dictionary2 headers)rn at Marketplace.B2C.Offers.Domain.Aggregate.Events.Services.CRMService.SendEventToCrm(CRMEvent crmEvent) in D:\a\1\s\src\Marketplace.B2C.Offers.Domain\Aggregate\Events\Services\CRMService.cs:line 209rn at Marketplace.B2C.Offers.Domain.Aggregate.Events.Services.CRMService.ProcessEventAsync(String eventType, String source, String target, String channelCommunicationId, String dynamicsCustomerId) in D:\a\1\s\src\Marketplace.B2C.Offers.Domain\Aggregate\Events\Services\CRMService.cs:line 176rn at Marketplace.B2C.Offers.Domain.Aggregate.Events.Services.CRMService.ProcessEvent(String eventType, String source, String target, String offerNumber) in D:\a\1\s\src\Marketplace.B2C.Offers.Domain\Aggregate\Events\Services\CRMService.cs:line 61rn at Marketplace.B2C.Offers.Domain.Aggregate.Offer.Services.OfferService.GetOfferByOfferNumber(String offerNumber, String language, String customerId) in D:\a\1\s\src\Marketplace.B2C.Offers.Domain\Aggregate\Offer\Services\OfferService.cs:line 116rn at Marketplace.B2C.Offers.Application.Services.Offer.OfferAppService.GetOfferByOfferNumber(String offerNumber, String language, String customerId) in D:\a\1\s\src\Marketplace.B2C.Offers.Application\Services\Offer\OfferAppService.cs:line 61rn at Marketplace.B2C.Offers.Function.FOffer.OfferGet(HttpRequest req, String customerId) in D:\a\1\s\src\Marketplace.B2C.Offers.Functions\FOffer.cs:line 119rn at Marketplace.B2C.Offers.Function.FOffer.Run(HttpRequest req, ILogger log) in D:\a\1\s\src\Marketplace.B2C.Offers.Functions\FOffer.cs:line 58"

Is this solved? I got the same issue

The problem still ... now in another part of my code

"Message: Scope disposed{no name, Parent=disposed{no name, Parent=disposed{no name, Parent=disposed{no name}}}} is disposed and scoped instances are disposed and no longer available.

StackTrace: at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 9000rn at DryIoc.Scope.TryGet(Object& item, Int32 id) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7890rn at DryIoc.Container.InstanceFactory.GetAndUnwrapOrDefault(IScope scope, Int32 factoryId) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1481rn at DryIoc.Container.InstanceFactory.GetInstanceFromScopeChainOrSingletons(IResolverContext r) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 1467rn at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, Object serviceKey, IfUnresolved ifUnresolved, Type requiredServiceType, Request preResolveParent, Object[] args) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 309rn at lambda_method(Closure , IResolverContext )rn at DryIoc.Container.ResolveAndCacheDefaultFactoryDelegate(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 225rn at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 196rn at Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection.ScopedServiceProvider.GetService(Type serviceType) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\ScopedServiceProvider.cs:line 25rn at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)rn at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServiceTrn at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry(String name)rn at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass14_0.<.ctor>b__1()rn at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Lazy1.CreateValue()rn at System.Lazy`1.get_Value()rn at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String name)rn at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String name)rn at Marketplace.B2C.Offers.Infra.Services.CRM.Events.SendEvent(String body) in C:\ProjProjeto_X\Marketplace.B2C.Functions.Offers\src\Marketplace.B2C.Offers.Infra.Services\CRM\Events.cs:line 18rn at Marketplace.B2C.Offers.Domain.Aggregate.Events.Services.CRMService.SendEventToCRM(EventType eventType, String source, String target, String channelCommunicationId, String dynamicsCustomerId)rn at Marketplace.B2C.Offers.Domain.Aggregate.Events.Services.CRMService.SendEventToCRM(EventType eventType, String source, String target, String offerNumber)rn at Marketplace.B2C.Offers.Domain.Aggregate.Offer.Services.OfferService.GetOffer(String offerNumber, String language, String weChatId)rn at Marketplace.B2C.Offers.Application.Services.Offer.OfferAppService.GetOffer(String offerNumber, String language, String weChatId) in C:\ProjProjeto_X\Marketplace.B2C.Functions.Offers\src\Marketplace.B2C.Offers.Application\Services\Offer\OfferAppService.cs:line 48rn at Marketplace.B2C.Offers.Function.Offer.OfferGet(HttpRequest req, String weChatId) in C:\ProjProjeto_X\Marketplace.B2C.Functions.Offers\src\Marketplace.B2C.Offers.Functions\Functions\Offer.cs:line 120rn at Marketplace.B2C.Offers.Function.Offer.Run(HttpRequest req, ILogger log) in C:\ProjProjeto_X\Marketplace.B2C.Functions.Offers\src\Marketplace.B2C.Offers.Functions\Functions\Offer.cs:line 59"

I change my implementation, and now is Ok - but I need to remove IHttpClientFactory!

namespace XX.YY.ZZ
{
    public class Class1 : Interface1
    {
        private readonly ApplicationSettings _applicationSettings;

        public Class1(IOptions<ApplicationSettings> applicationSettings)
        {
            _applicationSettings = applicationSettings.Value;
        }

        public async Task<HttpResponseMessage> SendXXX(string body)
        {
            var httpRequestMessage = new HttpRequestMessage();
            httpRequestMessage.Method = HttpMethod.Post;
            httpRequestMessage.RequestUri = new Uri(_applicationSettings.VARIABLE);

            HttpContent httpContent = new StringContent(body, Encoding.UTF8, "application/json");
            httpRequestMessage.Content = httpContent;

            HttpClient _client = null;
            _client = new HttpClient();

            return await _client.SendAsync(httpRequestMessage);
        }
    }
}
Was this page helpful?
0 / 5 - 0 ratings