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