简体   繁体   English

ASP.NET Core 不会用 StructureMap 替换 IoC

[英]ASP.NET Core does not replace IoC with StructureMap

My application is based on ASP.NET Core 2.1 and .NET Core 2.1 (downgraded from 2.2) generic host as Windows Service.我的应用程序基于 ASP.NET Core 2.1 和 .NET Core 2.1(从 2.2 降级)通用主机作为 Windows 服务。 So, IHostBuilder is launched first with other services and frameworks and then (if role permits) web service gets launched on top using IWebHostBuilder with all that WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().StartAsync() .因此, IHostBuilder首先与其他服务和框架一起启动,然后(如果角色允许)使用IWebHostBuilder和所有WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().StartAsync()在顶部启动 Web 服务。 Secondary WebHost is another story;二级 WebHost 是另一回事; it is initialized and works, but I haven't checked yet if IoC replacement has the same trouble as generic host.它已初始化并工作,但我还没有检查 IoC 替换是否与通用主机有相同的问题。

For now, generic host initialization:现在,通用主机初始化:

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 initialization: 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;
}

And the trouble is here, in the constructor of that registered hosted service (or anywhere else)问题就在这里,在该注册托管服务(或其他任何地方)的构造函数中

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 and IContainer are for demonstration purposes only, I only need 'services' ps:IServiceProvider 和 IContainer 仅用于演示目的,我只需要“服务”

When LifetimeService is initialized during container.AssertConfigurationIsValid() I getLifetimeServicecontainer.AssertConfigurationIsValid()期间初始化时,我得到
inCollection is true inCollection为真
inContainer is true inContainer为真
inProvider is true inProvider为真
IServiceProvider is StructureMapServiceProvider IServiceProviderStructureMapServiceProvider

Actual LifetimeService execution shows that实际LifetimeService执行表明
inCollection is false inCollection是假的
inContainer is true inContainer为真
inProvider is false inProvider是假的
IServiceProvider is ServiceProviderEngineScope IServiceProviderServiceProviderEngineScope

I don't plan to pass IServiceProvider or IContainer into constructors, but it seems that dependencies are resolved using IServiceProvider, not IContainer, and I get nulls.我不打算将 IServiceProvider 或 IContainer 传递给构造函数,但似乎使用 IServiceProvider 而不是 IContainer 来解决依赖关系,并且我得到了空值。 Silly thing like sp.GetRequiredService<IContainer>().TryGetInstance<IPlatformService>() does work.sp.GetRequiredService<IContainer>().TryGetInstance<IPlatformService>()这样愚蠢的事情确实有效。
There been some happy-path examples using WebHost and Startup classes where injection ought to be working properly.有一些使用 WebHost 和 Startup 类的快乐路径示例,其中注入应该正常工作。 Doesn't seem relevant for generic host ...which might replace WebHost one day, but is little known and not widely used.似乎与通用主机无关……它可能有一天会取代 WebHost,但鲜为人知且未广泛使用。 Well, could be due to .NET Core version downgrade too, but quite unlikely.嗯,也可能是由于 .NET Core 版本降级,但不太可能。 I've also tried replacing IServiceProvider and IServiceScopeFactory from IContainer during ConfigureServices() without luck.我还尝试在 ConfigureServices() 期间从 IContainer 替换 IServiceProvider 和 IServiceScopeFactory ,但没有运气。 My idea is to replace or forward internal container to StructureMap.我的想法是将内部容器替换或转发到 StructureMap。 I might be misunderstanding how that should work...我可能误解了它应该如何工作......

Has anyone successfully tried to 'marry' generic host and external IoC?有没有人成功地尝试“结合”通用主机和外部 IoC?

I've solved the puzzle!我已经解开了谜题! Finally, according to a too much simplified example ( https://github.com/aspnet/Hosting/blob/master/samples/GenericHostSample/ProgramFullControl.cs ), I had to change HostBuilder initialization to最后,根据一个过于简化的示例( https://github.com/aspnet/Hosting/blob/master/samples/GenericHostSample/ProgramFullControl.cs ),我不得不将HostBuilder初始化更改为

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

and introduce provider factory itself并介绍提供者工厂本身

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>();
    }
}

Now internal container is substituted with StructureMap and resolved IServiceProvider in LifetimeService is of type StructureMapServiceProvider .现在内部容器被 StructureMap 替换,并且LifetimeService解析的IServiceProviderStructureMapServiceProvider类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM