dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.35k stars 9.99k forks source link

"Cannot resolve scoped service" in Development environment #34714

Closed verdysh closed 3 years ago

verdysh commented 3 years ago

Hi!

Environment: Windows 10 Visual studio 2019 Version 16.10.3 Asp.NET core 3.1

I have simple asp.net core app which launched with Kestrel. I am experimenting with HttpClientFactory and have caught an interesting behaviour. I have 2 services. First:

public interface IService1
{
    void Inc();
    string ToString();
}

public class Service1: IService1
{
    public int _count = 0;

    public Service1(HttpClient client, IService2 s2)
    {

    }

    public void Inc()
    {
        _count++;
    }

    public override string ToString()
    {
        return $"{nameof(Service1)}, count {_count}";
    }
}

Second:

public interface IService2
{
    void Inc();
    string ToString();
}

public class Service2 : IService2
{
    public int _count = 0;

    public Service2()
    {

    }

    public void Inc()
    {
        _count++;
    }

    public override string ToString()
    {
        return $"{nameof(Service2)}, count {_count}";
    }
}

I have registered them inside ConfigureServices:

services.AddScoped<IService2, Service2>();
services.AddHttpClient<IService1, Service1>();

And in Configure(...) method I am tryin call my Service1:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    var s1 = app.ApplicationServices.GetRequiredService<IService1>();
    s1.Inc();

    s1 = app.ApplicationServices.GetRequiredService<IService1>();
    s1.Inc();

    Console.WriteLine(s1);
    ...
}

If I start this code in Visual Studio (doesn't matter in Debug or Release mode), exception is throwing: System.InvalidOperationException: 'Cannot resolve scoped service 'WebApplication1.IService2' from root provider.'

If I start application with double click on exe file, application successfully starts. Difference was in "ASPNETCORE_ENVIRONMENT" variable. As I removed it from Visual Studio debug settings, the app was started successfully in Visual Studio as well.

Is this behaviour a bug or a feature?

Thank in advance!

Vake93 commented 3 years ago

It's a feature; when you run the project from VS, it sets the ASPNETCORE_ENVIRONMENT variable to Development. (Check your launchSettings.json file) And if the environment is Development, it validates the scopes of the services.

More info: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-5.0#scope-validation

https://github.com/dotnet/aspnetcore/blob/5db32c0392fea7165b2d3566ec6dde4a062559f3/src/DefaultBuilder/src/WebHost.cs#L207

verdysh commented 3 years ago

It's a feature; when you run the project from VS, it sets the ASPNETCORE_ENVIRONMENT variable to Development. (Check your launchSettings.json file) And if the environment is Development, it validates the scopes of the services.

More info: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-5.0#scope-validation

https://github.com/dotnet/aspnetcore/blob/5db32c0392fea7165b2d3566ec6dde4a062559f3/src/DefaultBuilder/src/WebHost.cs#L207

Thanks for the answer! It seems, this validation should prevent incorrect resources utilization. If it's true, why this validation is turn off for production environment, where resources utilization usually are more important then in development environment?

Vake93 commented 3 years ago

Not 100% sure about this, but I think there is a performance impact when you validate the scopes when dependencies are resolved. So that is probably why it is skipped by default in the production environment. Also, since you would have tested the application in development before pushing it to production, you would catch the issue.

verdysh commented 3 years ago

Not 100% sure about this, but I think there is a performance impact when you validate the scopes when dependencies are resolved. So that is probably why it is skipped by default in the production environment. Also, since you would have tested the application in development before pushing it to production, you would catch the issue.

Again thanks for the answer!

davidfowl commented 3 years ago

@Vake93 is correct, it's the performance impact.

Vake93 commented 3 years ago

@Vake93 is correct, it's the performance impact.

Thanks for confirming. I was pretty sure it was but didn't find docs on design reasons behind that choice. So I didn't confirm.

ghost commented 3 years ago

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.