Azure / azure-functions-host

The host/runtime that powers Azure Functions
https://functions.azure.com
MIT License
1.92k stars 441 forks source link

Scope Disposed Error in V4 Functions #8610

Open roend83 opened 2 years ago

roend83 commented 2 years ago

I'm having an issue similar to #7874. I've attached a Visual Studio project with a minimal reproduction. The issue occurs when a service registered as a singleton accepts a dependency Func\<Service> where Service is registered as scoped or transient. Similar to #7874, the first request is successful, but the second request errors with the error "Scope disposed{no name} is disposed and scoped instances are disposed and no longer available.".

To reproduce, open the solution from the attached zip, run the function app, and make 2 requests to http://localhost:7071/api/Function1

V4BugRepro.zip

roend83 commented 2 years ago

I think I found a workaround. If I also register the Func as a singleton in my reproduction application it seems to work

builder.Services.AddSingleton<Func<TestSubService>>(provider => provider.GetRequiredService<TestSubService>);
roend83 commented 2 years ago

Actually the workaround isn't working right either. I end up getting the same instance of TestSubService every time. Given that it's scoped, I'd expect to get a new instance on each request.

roend83 commented 2 years ago

I backported the repro project to netcoreapp3.1 and v3 and I get a new instance of TestSubService on each request. This is definitely a regression that only exists in .net 6 and v4.

roend83 commented 2 years ago

I modified my previous reproduction solution to include both a V3 (Core 3.1) and V4 (Net 6) application. If you unzip and run the application, you can hit http://localhost:7071/api/Function1 to get the V4 result and http://localhost:7085/api/Function1 to hit the V3. Same code on both sides, but you'll see that it returns different results. V3 is exactly what I would expect. V4 throws in one case and ends up making a Scoped service a singleton in the others. V4BugRepro.zip

Ved2806 commented 2 years ago

Hi @roend83 Does this solved your issue? Please let us know do you still need help with this?

roend83 commented 2 years ago

No, this is not solved. If you unzip and run the 2nd zip file that I uploaded above you'll see that V3 and V4 functions produce different results. The V3 results are correct and V4 are not. The results are:

V3 Request 1: 0 0 0 Request 2: 0 0 0 Request 3: 0 0 0

V4 Request 1: 0 0 0 Request 2: -1 1 1 Request 3: -1 2 2

I think this actually indicates 2 problems:

  1. Injecting a Func\<TSubService> where TSubService is registered as scoped into a TService where TService is registered as a singleton works on the first request but throws a "Scope disposed{no name} is disposed and scoped instances are disposed and no longer available" error on every subsequent request. Look at TestService in my reproduction app for an example of this.

  2. Injecting an IServiceProvider into a TService where TService is registered as a singleton does not properly resolve services registered as scoped with the injected IServiceProvider. See TestService2 and TestService3 in my reproduction app for an example of this.

Ved2806 commented 1 year ago

Hi @fabiocav Could you please look into this issue?

kshyju commented 1 year ago

Hi @roend83

You should not inject a scoped dependency into a singleton class constructor. If you do, your scoped dependency will behave as singleton. See this for more details.

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0#service-lifetimes

roend83 commented 1 year ago

@kshyju,

Did you look reproduction application that I attached above? I'm not injecting a scoped dependency. I'm injecting either an IServiceProvider or a Func\ (which should use the service provider under the hood to create the service). The reproduction application has a V3 and V4 function that show different results with the same code. Something has changed in V4.

Ved2806 commented 1 year ago

Hi @kshyju Please provide your inputs on this