我的应用程序基于Windows服务的ASP.NET Core 2.1和.NET Core 2.1(从2.2降级)通用主机。因此,IHostBuilder首先与其他服务和框架一起启动,然后(如果角色允许)使用IWebHostBuilder和所有WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().StartAsync()在顶部启动Web服务。备用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仅用于演示目的,我只需要“服务”

LifetimeService期间初始化container.AssertConfigurationIsValid()时,我得到
inCollection是真的
inContainer是真的
inProvider是真的
IServiceProviderStructureMapServiceProvider

实际的LifetimeService执行表明
inCollection为假
inContainer是真的
inProvider为假
IServiceProviderServiceProviderEngineScope

我不打算将IServiceProvider或IContainer传递给构造函数,但是似乎依赖项是使用IServiceProvider而不是IContainer解析的,并且我得到了null。像sp.GetRequiredService<IContainer>().TryGetInstance<IPlatformService>()这样的愚蠢东西确实有效。
有一些使用WebHost和Startup类的快乐路径示例,其中注入应该可以正常工作。似乎与通用主机无关……它有一天可能会取代WebHost,但鲜为人知且用途不广。好吧,也可能是由于.NET Core版本降级了,但是不太可能。我还尝试过在ConfigureServices()期间从IContainer替换IServiceProvider和IServiceScopeFactory的过程,但并不顺利。我的想法是替换内部容器或将其转发到StructureMap。我可能会误解它应该如何工作...

有没有人成功地尝试“嫁接”通用主机和外部IoC?

最佳答案

我解决了难题!最后,根据一个过于简化的示例(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中解析的LifetimeServiceStructureMapServiceProvider类型。

关于c# - ASP.NET Core不会用StructureMap替换IoC,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52985315/

10-10 07:43