У меня проблема с пониманием основного поставщика услуг 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, результат будет в порядке.
Это ошибка в "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
, и у вас есть такое поведение. Протестируйте в производстве, и вы получите ожидаемое поведение.
Большое спасибо, помогло, не нашел ответа
существует ли он в «Microsoft.Extensions.DependencyInjection» версии 7?
@Milad - Да, .NET 7 был выпущен на прошлой неделе.
Ничего себе, я искал причину в изменениях HostApplicationBuilder, внесенных в serviceCollection!
@MDZand — см. HostApplicationBuilder.cs и HostingHostBuilderExtensions.cs
Интересная вещь - если вы измените порядок регистрации во втором случае, вы получите "ожидаемый" результат.