Почему поставщик услуг 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
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
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

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