ASP.NET Core 中的自定义 IServiceProviderFactory

Joh*_*ohn 6 dependency-injection .net-core asp.net-core

我编写了一个自定义IServiceProviderFactory并将其安装在Program.cs一个新应用程序中,如下所示:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new PropertyInjectingContainerFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
Run Code Online (Sandbox Code Playgroud)

它确实会导致调用正确的配置函数Startup.cs

   public void ConfigureContainer(PropertyInjectingContainerFactory.Builder builder)
   {
        builder.AddInjectAttribute<InjectDependencyAttribute>();
   }
Run Code Online (Sandbox Code Playgroud)

但是,我创建的容器仅解析两个服务:IConfigurationIHost​​ 。

其他所有内容显然都由默认容器解决(例如ILogger<T>控制器上的服务)。我做错了什么?

这是我的自定义工厂的代码 - 请理解我可能应该使用现有的第三方容器,但我也想了解这一切如何组合在一起。

public class PropertyInjectingContainerFactory : IServiceProviderFactory<PropertyInjectingContainerFactory.Builder>
{
    public Builder CreateBuilder(IServiceCollection services)
    {
        return new Builder(services);
    }

    public IServiceProvider CreateServiceProvider(Builder containerBuilder)
    {
        return containerBuilder.CreateServiceProvider();
    }

    public class Builder
    {
        internal readonly IServiceCollection services;

        internal List<Type> attributeTypes = new List<Type>();

        public Builder(IServiceCollection services)
        {
            this.services = services;
        }

        public Builder AddInjectAttribute<A>()
            where A : Attribute
        {
            attributeTypes.Add(typeof(A));

            return this;
        }

        public IServiceProvider CreateServiceProvider()
            => new PropertyInjectingServiceProvider(services.BuildServiceProvider(), attributeTypes.ToArray());
    }

    class PropertyInjectingServiceProvider : IServiceProvider
    {
        private readonly IServiceProvider services;
        private readonly Type[] injectAttributes;

        public PropertyInjectingServiceProvider(IServiceProvider services, Type[] injectAttributes)
        {
            this.services = services;
            this.injectAttributes = injectAttributes;
        }

        // This function is only called for `IConfiguration` and `IHost` - why?
        public object GetService(Type serviceType)
        {
            var service = services.GetService(serviceType);

            InjectProperties(service);

            return service;
        }

        private void InjectProperties(Object target)
        {
            var type = target.GetType();

            var candidateProperties = type.GetProperties(System.Reflection.BindingFlags.Public);

            var props = from p in candidateProperties
                        where injectAttributes.Any(a => p.GetCustomAttributes(a, true).Any())
                        select p;

            foreach (var prop in props)
            {
                prop.SetValue(target, services.GetService(prop.PropertyType));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)