ASP.NET Core не заменяет IoC на StructureMap - PullRequest
0 голосов
/ 25 октября 2018

Мое приложение основано на универсальном узле ASP.NET Core 2.1 и .NET Core 2.1 (более ранней версии 2.2) в качестве службы Windows.Итак, IHostBuilder запускается сначала с другими службами и средами, а затем (если позволяет роль) веб-служба запускается поверх, используя IWebHostBuilder со всем этим WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().StartAsync().Вторичный WebHost - это другая история;он инициализирован и работает, но я еще не проверил, имеет ли замена IoC ту же проблему, что и общий хост.

На данный момент, общая инициализация хоста:

new HostBuilder().ConfigureServices((hostContext, services) =>
{
    services.AddHostedService<LifetimeService>(); // Gets launched when host is up
    var container = ContainerBuilder.BuildBaseContainer(services, new WorkingPath());
    services.AddSingleton<IContainer>(container);
    services.AddStructureMap(); // Has no effect
});

Инициализация IContainer:

public static Container BuildBaseContainer(IServiceCollection services, IWorkingPath workingPath)
{
    var container = new Container();
    container.Configure(config =>
    {
        config.Scan(scan =>
        {
            workingPath.OwnLoadedAssemblies.Where(asm => !asm.IsDynamic).ForEach(scan.Assembly);
            scan.LookForRegistries();
            scan.AddAllTypesOf<IPlatformService>();
        });
        config.For<IContainer>().Use(() => container);                
        config.Populate(services);
    });
    container.AssertConfigurationIsValid();
    return container;
}

И проблема здесь, в конструкторе этой зарегистрированной размещенной службы (илигде-нибудь еще)

public LifetimeService(IEnumerable<IPlatformService> services,
                       IServiceProvider sp, IContainer c)
{
    var inCollection = services.Any();
    var inContainer = c.TryGetInstance<IPlatformService>() != default;
    var inProvider = sp.GetRequiredService<IPlatformService>() != default;
}

ps: IServiceProvider и IContainer предназначены только для демонстрационных целей, мне нужны только 'services'

Когда LifetimeService инициализируется во время container.AssertConfigurationIsValid() Я получаю
inCollection верно
inContainer верно
inProvider верно
IServiceProvider равно StructureMapServiceProvider

Фактическое LifetimeService выполнение показывает, что
inCollection неверно
inContainer верно
inProvider ложно
IServiceProvider равно ServiceProviderEngineScope

Я не планирую передавать IServiceProvider или IContainerв конструкторы, но кажется, что зависимости разрешаются с помощью IServiceProvider, а не IContainer, и я получаю нулевые значения.Глупая штука вроде sp.GetRequiredService<IContainer>().TryGetInstance<IPlatformService>() работает.
Было несколько примеров «счастливого пути», использующих классы WebHost и Startup, где внедрение должно работать должным образом.Не кажется актуальным для универсального хоста ... который может заменить WebHost однажды, но мало известен и не широко используется.Ну, это может быть связано с понижением версии .NET Core, но это маловероятно.Я также попытался заменить IServiceProvider и IServiceScopeFactory из IContainer во время ConfigureServices () без удачи.Моя идея - заменить или переслать внутренний контейнер в StructureMap.Возможно, я неправильно понимаю, как это должно работать ...

Кто-нибудь успешно пытался "жениться" на общем хосте и внешнем IoC?

1 Ответ

0 голосов
/ 25 октября 2018

Я решил головоломку!Наконец, согласно слишком упрощенному примеру (https://github.com/aspnet/Hosting/blob/master/samples/GenericHostSample/ProgramFullControl.cs), мне пришлось изменить HostBuilder инициализацию на

new HostBuilder()
.UseServiceProviderFactory(new StructureMapContainerFactory(workingPath))
.ConfigureServices((hostContext, services) =>
{                   
    services.AddHostedService<LifetimeService>();
});

и ввести саму фабрику провайдера

public class StructureMapContainerFactory : IServiceProviderFactory<IContainer>
{
    private readonly IWorkingPath workingPath;
    // pass any dependencies to your factory
    public StructureMapContainerFactory(IWorkingPath workingPath)
    {
        this.workingPath = workingPath;
    }

    public IContainer CreateBuilder(IServiceCollection services)
    {
        services.AddStructureMap();
        return ContainerBuilder.BuildBaseContainer(services, workingPath);
    }

    public IServiceProvider CreateServiceProvider(IContainer containerBuilder)
    {
        return containerBuilder.GetInstance<IServiceProvider>();
    }
}

Теперь внутренняяконтейнер заменяется StructureMap и разрешается IServiceProvider в LifetimeService типа StructureMapServiceProvider.

...