【问题标题】:ASP.NET Core does not replace IoC with StructureMapASP.NET Core 不会用 StructureMap 替换 IoC
【发布时间】:2018-10-25 08:58:13
【问题描述】:

我的应用程序基于 ASP.NET Core 2.1 和 .NET Core 2.1(从 2.2 降级)通用主机作为 Windows 服务。因此,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 仅用于演示目的,我只需要“服务”

LifetimeServicecontainer.AssertConfigurationIsValid() 期间初始化时,我得到
inCollection 为真
inContainer 为真
inProvider 为真
IServiceProviderStructureMapServiceProvider
/p>

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

我不打算将 IServiceProvider 或 IContainer 传递给构造函数,但似乎依赖关系是使用 IServiceProvider 而不是 IContainer 解决的,并且我得到空值。像sp.GetRequiredService&lt;IContainer&gt;().TryGetInstance&lt;IPlatformService&gt;() 这样的傻事确实有效。
有一些使用 WebHost 和 Startup 类的快乐路径示例,其中注入应该正常工作。似乎与通用主机无关……有一天它可能会取代 WebHost,但鲜为人知且未被广泛使用。好吧,也可能是由于 .NET Core 版本降级,但不太可能。我还尝试在 ConfigureServices() 期间从 IContainer 替换 IServiceProvider 和 IServiceScopeFactory ,但没有成功。我的想法是将内部容器替换或转发到 StructureMap。我可能误解了它应该如何工作......

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

【问题讨论】:

    标签: c# generics asp.net-core structuremap host


    【解决方案1】:

    我已经解决了这个难题!最后,根据一个过于简化的例子(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 并解析 LifetimeService 中的 IServiceProvider 类型为 StructureMapServiceProvider

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多