Ejemplo n.º 1
0
        public IServiceProvider CreateContainer(ShellSettings settings, ShellBlueprint blueprint)
        {
            var tenantServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            tenantServiceCollection.AddSingleton(settings);
            tenantServiceCollection.AddSingleton(sp =>
            {
                // Resolve it lazily as it's constructed lazily
                var shellSettings = sp.GetRequiredService <ShellSettings>();
                return(shellSettings.ShellConfiguration);
            });

            tenantServiceCollection.AddSingleton(blueprint.Descriptor);
            tenantServiceCollection.AddSingleton(blueprint);

            AddCoreServices(tenantServiceCollection);

            // Execute IStartup registrations

            var moduleServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            foreach (var dependency in blueprint.Dependencies.Where(t => typeof(IStartup).IsAssignableFrom(t.Key)))
            {
                moduleServiceCollection.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IStartup), dependency.Key));
                tenantServiceCollection.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IStartup), dependency.Key));
            }

            // To not trigger features loading before it is normally done by 'ShellHost',
            // init here the application feature in place of doing it in the constructor.
            EnsureApplicationFeature();

            foreach (var rawStartup in blueprint.Dependencies.Keys.Where(t => t.Name == "Startup"))
            {
                // Startup classes inheriting from IStartup are already treated
                if (typeof(IStartup).IsAssignableFrom(rawStartup))
                {
                    continue;
                }

                // Ignore Startup class from main application
                if (blueprint.Dependencies.TryGetValue(rawStartup, out var startupFeature) && startupFeature.FeatureInfo.Id == _applicationFeature.Id)
                {
                    continue;
                }

                // Create a wrapper around this method
                var configureServicesMethod = rawStartup.GetMethod(
                    nameof(IStartup.ConfigureServices),
                    BindingFlags.Public | BindingFlags.Instance,
                    null,
                    CallingConventions.Any,
                    new Type[] { typeof(IServiceCollection) },
                    null);

                var configureMethod = rawStartup.GetMethod(
                    nameof(IStartup.Configure),
                    BindingFlags.Public | BindingFlags.Instance);

                var orderProperty = rawStartup.GetProperty(
                    nameof(IStartup.Order),
                    BindingFlags.Public | BindingFlags.Instance);

                var configureOrderProperty = rawStartup.GetProperty(
                    nameof(IStartup.ConfigureOrder),
                    BindingFlags.Public | BindingFlags.Instance);

                // Add the startup class to the DI so we can instantiate it with
                // valid ctor arguments
                moduleServiceCollection.AddSingleton(rawStartup);
                tenantServiceCollection.AddSingleton(rawStartup);

                moduleServiceCollection.AddSingleton <IStartup>(sp =>
                {
                    var startupInstance = sp.GetService(rawStartup);
                    return(new StartupBaseMock(startupInstance, configureServicesMethod, configureMethod, orderProperty, configureOrderProperty));
                });

                tenantServiceCollection.AddSingleton <IStartup>(sp =>
                {
                    var startupInstance = sp.GetService(rawStartup);
                    return(new StartupBaseMock(startupInstance, configureServicesMethod, configureMethod, orderProperty, configureOrderProperty));
                });
            }

            // Make shell settings available to the modules
            moduleServiceCollection.AddSingleton(settings);
            moduleServiceCollection.AddSingleton(sp =>
            {
                // Resolve it lazily as it's constructed lazily
                var shellSettings = sp.GetRequiredService <ShellSettings>();
                return(shellSettings.ShellConfiguration);
            });

            var moduleServiceProvider = moduleServiceCollection.BuildServiceProvider(true);

            // Index all service descriptors by their feature id
            var featureAwareServiceCollection = new FeatureAwareServiceCollection(tenantServiceCollection);

            var startups = moduleServiceProvider.GetServices <IStartup>();

            // IStartup instances are ordered by module dependency with an Order of 0 by default.
            // OrderBy performs a stable sort so order is preserved among equal Order values.
            startups = startups.OrderBy(s => s.Order);

            // Let any module add custom service descriptors to the tenant
            foreach (var startup in startups)
            {
                var feature = blueprint.Dependencies.FirstOrDefault(x => x.Key == startup.GetType()).Value?.FeatureInfo;

                // If the startup is not coming from an extension, associate it to the application feature.
                // For instance when Startup classes are registered with Configure<Startup>() from the application.

                featureAwareServiceCollection.SetCurrentFeature(feature ?? _applicationFeature);
                startup.ConfigureServices(featureAwareServiceCollection);
            }

            (moduleServiceProvider as IDisposable).Dispose();

            var shellServiceProvider = tenantServiceCollection.BuildServiceProvider(true);

            // Register all DIed types in ITypeFeatureProvider
            var typeFeatureProvider = shellServiceProvider.GetRequiredService <ITypeFeatureProvider>();

            foreach (var featureServiceCollection in featureAwareServiceCollection.FeatureCollections)
            {
                foreach (var serviceDescriptor in featureServiceCollection.Value)
                {
                    var type = serviceDescriptor.GetImplementationType();

                    if (type != null)
                    {
                        var feature = featureServiceCollection.Key;

                        if (feature == _applicationFeature)
                        {
                            var attribute = type.GetCustomAttributes <FeatureAttribute>(false).FirstOrDefault();

                            if (attribute != null)
                            {
                                feature = featureServiceCollection.Key.Extension.Features
                                          .FirstOrDefault(f => f.Id == attribute.FeatureName)
                                          ?? feature;
                            }
                        }

                        typeFeatureProvider.TryAdd(type, feature);
                    }
                }
            }

            return(shellServiceProvider);
        }
        public IServiceProvider CreateContainer(ShellSettings settings, ShellBlueprint blueprint)
        {
            var tenantServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            tenantServiceCollection.AddSingleton(settings);
            tenantServiceCollection.AddSingleton <IShellConfiguration>(sp =>
            {
                // Resolve it lazily as it's constructed lazily
                var shellSettings = sp.GetRequiredService <ShellSettings>();
                return(shellSettings.ShellConfiguration);
            });

            tenantServiceCollection.AddSingleton(blueprint.Descriptor);
            tenantServiceCollection.AddSingleton(blueprint);

            AddCoreServices(tenantServiceCollection);

            // Execute IStartup registrations

            // TODO: Use StartupLoader in RTM and then don't need to register the classes anymore then

            var moduleServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            foreach (var dependency in blueprint.Dependencies.Where(t => typeof(Modules.IStartup).IsAssignableFrom(t.Key)))
            {
                moduleServiceCollection.AddSingleton(typeof(Modules.IStartup), dependency.Key);
                tenantServiceCollection.AddSingleton(typeof(Modules.IStartup), dependency.Key);
            }

            // Add a default configuration if none has been provided
            var configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();

            moduleServiceCollection.TryAddSingleton(configuration);
            tenantServiceCollection.TryAddSingleton(configuration);

            // Make shell settings available to the modules
            moduleServiceCollection.AddSingleton(settings);
            moduleServiceCollection.AddSingleton <IShellConfiguration>(sp =>
            {
                // Resolve it lazily as it's constructed lazily
                var shellSettings = sp.GetRequiredService <ShellSettings>();
                return(shellSettings.ShellConfiguration);
            });

            var moduleServiceProvider = moduleServiceCollection.BuildServiceProvider(true);

            // Index all service descriptors by their feature id
            var featureAwareServiceCollection = new FeatureAwareServiceCollection(tenantServiceCollection);

            var startups = moduleServiceProvider.GetServices <Modules.IStartup>();

            // IStartup instances are ordered by module dependency with an Order of 0 by default.
            // OrderBy performs a stable sort so order is preserved among equal Order values.
            startups = startups.OrderBy(s => s.Order);

            // To not trigger features loading before it is normally done by 'ShellHost',
            // init here the application feature in place of doing it in the constructor.
            EnsureApplicationFeature();

            // Let any module add custom service descriptors to the tenant
            foreach (var startup in startups)
            {
                var feature = blueprint.Dependencies.FirstOrDefault(x => x.Key == startup.GetType()).Value?.FeatureInfo;

                // If the startup is not coming from an extension, associate it to the application feature.
                // For instance when Startup classes are registered with Configure<Startup>() from the application.

                featureAwareServiceCollection.SetCurrentFeature(feature ?? _applicationFeature);
                startup.ConfigureServices(featureAwareServiceCollection);
            }

            (moduleServiceProvider as IDisposable).Dispose();

            var shellServiceProvider = tenantServiceCollection.BuildServiceProvider(true);

            // Register all DIed types in ITypeFeatureProvider
            var typeFeatureProvider = shellServiceProvider.GetRequiredService <ITypeFeatureProvider>();

            foreach (var featureServiceCollection in featureAwareServiceCollection.FeatureCollections)
            {
                foreach (var serviceDescriptor in featureServiceCollection.Value)
                {
                    if (serviceDescriptor.ImplementationType != null)
                    {
                        typeFeatureProvider.TryAdd(serviceDescriptor.ImplementationType, featureServiceCollection.Key);
                    }
                    else if (serviceDescriptor.ImplementationInstance != null)
                    {
                        typeFeatureProvider.TryAdd(serviceDescriptor.ImplementationInstance.GetType(), featureServiceCollection.Key);
                    }
                    else
                    {
                        // Factory, we can't know which type will be returned
                    }
                }
            }

            return(shellServiceProvider);
        }
        public IServiceProvider CreateContainer(ShellSettings settings, ShellBlueprint blueprint)
        {
            IServiceCollection tenantServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            tenantServiceCollection.AddSingleton(settings);
            tenantServiceCollection.AddSingleton(blueprint.Descriptor);
            tenantServiceCollection.AddSingleton(blueprint);

            AddCoreServices(tenantServiceCollection);

            // Execute IStartup registrations

            // TODO: Use StartupLoader in RTM and then don't need to register the classes anymore then

            IServiceCollection moduleServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);

            foreach (var dependency in blueprint.Dependencies.Where(t => typeof(OrchardCore.Modules.IStartup).IsAssignableFrom(t.Key)))
            {
                moduleServiceCollection.AddSingleton(typeof(OrchardCore.Modules.IStartup), dependency.Key);
                tenantServiceCollection.AddSingleton(typeof(OrchardCore.Modules.IStartup), dependency.Key);
            }

            // Add a default configuration if none has been provided
            var configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();

            moduleServiceCollection.TryAddSingleton(configuration);
            tenantServiceCollection.TryAddSingleton(configuration);

            // Make shell settings available to the modules
            moduleServiceCollection.AddSingleton(settings);

            var moduleServiceProvider = moduleServiceCollection.BuildServiceProvider(true);

            // Index all service descriptors by their feature id
            var featureAwareServiceCollection = new FeatureAwareServiceCollection(tenantServiceCollection);

            var startups = moduleServiceProvider.GetServices <OrchardCore.Modules.IStartup>();

            // IStartup instances are ordered by module dependency with an Order of 0 by default.
            // OrderBy performs a stable sort so order is preserved among equal Order values.
            startups = startups.OrderBy(s => s.Order);

            // Let any module add custom service descriptors to the tenant
            foreach (var startup in startups)
            {
                var feature = blueprint.Dependencies.FirstOrDefault(x => x.Key == startup.GetType()).Value.FeatureInfo;
                featureAwareServiceCollection.SetCurrentFeature(feature);

                startup.ConfigureServices(featureAwareServiceCollection);
            }

            (moduleServiceProvider as IDisposable).Dispose();

            // add already instanciated services like DefaultOrchardHost
            var applicationServiceDescriptors = _applicationServices.Where(x => x.Lifetime == ServiceLifetime.Singleton);

            var shellServiceProvider = tenantServiceCollection.BuildServiceProvider(true);

            // Register all DIed types in ITypeFeatureProvider
            var typeFeatureProvider = shellServiceProvider.GetRequiredService <ITypeFeatureProvider>();

            foreach (var featureServiceCollection in featureAwareServiceCollection.FeatureCollections)
            {
                foreach (var serviceDescriptor in featureServiceCollection.Value)
                {
                    if (serviceDescriptor.ImplementationType != null)
                    {
                        typeFeatureProvider.TryAdd(serviceDescriptor.ImplementationType, featureServiceCollection.Key);
                    }
                    else if (serviceDescriptor.ImplementationInstance != null)
                    {
                        typeFeatureProvider.TryAdd(serviceDescriptor.ImplementationInstance.GetType(), featureServiceCollection.Key);
                    }
                    else
                    {
                        // Factory, we can't know which type will be returned
                    }
                }
            }

            return(shellServiceProvider);
        }