Почему поставщик услуг aspnet возвращает неправильный результат?

У меня проблема с пониманием основного поставщика услуг asp net. Я регистрирую тип службы с неуниверсальной конкретной и открытой общей регистрацией,

AddTransient(typeof(IBase<Config>), typeof(Base));
AddTransient(typeof(IBase<>), typeof(BaseGeneric<>));

когда я пытаюсь разрешить все службы, поведение не такое, как я ожидал.

Я создаю пустое веб-приложение с помощью:

dotnet new web

и измените program.cs следующим образом

ServiceCollection sc = new ServiceCollection();

sc.AddTransient(typeof(IBase<Config>), typeof(Base));
sc.AddTransient(typeof(IBase<>), typeof(BaseGeneric<>));
var serviceProvider = sc.BuildServiceProvider();
var services2 = serviceProvider.GetServices(typeof(IBase<Config>));

foreach (var s in services2){
   Console.WriteLine(s.GetType());
}
Console.WriteLine();
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient(typeof(IBase<Config>), typeof(Base));
builder.Services.AddTransient(typeof(IBase<>), typeof(BaseGeneric<>));

var app = builder.Build();

var services = app.Services.GetServices(typeof(IBase<Config>));

foreach (var s in services){
   Console.WriteLine(s.GetType());
}
app.MapGet("/", () => "Hello World!");

app.Run();

public class Config { }
public interface IBase<T> { }
public class BaseGeneric<T> : IBase<T> { }
public class Base : IBase<Config> { }

вывод двух foreach

Base
BaseGeneric`1[Config]

Base
Base

Я ожидаю, что два foreach напечатают один и тот же результат, но, как вы можете видеть, они возвращают разные результаты. Верно ли это предположение, что они должны работать как друг друга? если да, то в чем здесь проблема? и еще одна вещь, которую я обнаружил, это то, что если вы измените порядок регистрации builder.Services, результат будет в порядке.

Интересная вещь - если вы измените порядок регистрации во втором случае, вы получите "ожидаемый" результат.

Guru Stron 18.11.2022 15:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это ошибка в "Microsoft.Extensions.DependencyInjection" из версии 6.0.0:

https://github.com/dotnet/runtime/issues/65145

Когда опция ValidateOnBuild включена в поставщике услуг, это приводит к странному поведению при получении общей зависимости.

Исправление планируется до .NET 8.


Он воспроизводится с помощью:

>dotnet new console -f net7.0
>dotnet add package Microsoft.Extensions.DependencyInjection --version 6.0.0

Измените «Program.cs»:

using Microsoft.Extensions.DependencyInjection;

ServiceCollection sc = new ServiceCollection();

sc.AddTransient(typeof(IBase<Config>), typeof(Base));
sc.AddTransient(typeof(IBase<>), typeof(BaseGeneric<>));

LogServices(sc, false);
LogServices(sc, true);

void LogServices(ServiceCollection sc, bool validate)
{
    Console.WriteLine("ValidateOnBuild: " + validate);
    var serviceProvider = sc.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = validate });
    var services = serviceProvider.GetServices(typeof(IBase<Config>));

    foreach (var s in services)
    {
        Console.WriteLine(s.GetType());
    }
}

public class Config { }
public interface IBase<T> { }
public class BaseGeneric<T> : IBase<T> { }
public class Base : IBase<Config> { }

Этот баг воспроизводится:

dotnet run
ValidateOnBuild: False
Base
BaseGeneric`1[Config]
ValidateOnBuild: True
Base
Base

Если мы понизим версию «Microsoft.Extensions.DependencyInjection» до предыдущей:

>dotnet add package Microsoft.Extensions.DependencyInjection --version 5.0.2
>dotnet run
ValidateOnBuild: False
Base
BaseGeneric`1[Config]
ValidateOnBuild: True
Base
BaseGeneric`1[Config]

Это ожидаемое поведение.


В ASP.NET Core, когда среда «Разработка», построитель служб создается с параметром ValidateOnBuild, и у вас есть такое поведение. Протестируйте в производстве, и вы получите ожидаемое поведение.

Большое спасибо, помогло, не нашел ответа

Milad 18.11.2022 16:51

существует ли он в «Microsoft.Extensions.DependencyInjection» версии 7?

Milad 18.11.2022 16:53

@Milad - Да, .NET 7 был выпущен на прошлой неделе.

vernou 18.11.2022 16:57

Ничего себе, я искал причину в изменениях HostApplicationBuilder, внесенных в serviceCollection!

MD Zand 18.11.2022 17:58

@MDZand — см. HostApplicationBuilder.cs и HostingHostBuilderExtensions.cs

vernou 18.11.2022 18:03

Другие вопросы по теме