public IServiceProvider CreateContainer(ShellSettings settings, ShellBlueprint blueprint) { IServiceCollection tenantServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices); tenantServiceCollection.AddSingleton(settings); tenantServiceCollection.AddSingleton(blueprint.Descriptor); tenantServiceCollection.AddSingleton(blueprint); AddCoreServices(tenantServiceCollection); // Sure this is right? tenantServiceCollection.AddSingleton(_loggerFactory); foreach (var dependency in blueprint.Dependencies) { foreach (var interfaceType in dependency.Type.GetInterfaces()) { // GetInterfaces returns the full hierarchy of interfaces if (interfaceType == typeof(ISingletonDependency) || interfaceType == typeof(ITransientDependency) || interfaceType == typeof(IDependency) || !typeof(IDependency).IsAssignableFrom(interfaceType)) { continue; } if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Type: {0}, Interface Type: {1}", dependency.Type, interfaceType); } if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddSingleton(interfaceType, dependency.Type); } else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddTransient(interfaceType, dependency.Type); } else if (typeof(IDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddScoped(interfaceType, dependency.Type); } } } // Register components foreach (var dependency in blueprint.Dependencies) { var serviceComponentAttribute = dependency.Type.GetTypeInfo().GetCustomAttribute <ServiceScopeAttribute>(); if (serviceComponentAttribute != null) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Type: {0}, Interface Type: {1}", dependency.Type, serviceComponentAttribute.ServiceType); } serviceComponentAttribute.Register(tenantServiceCollection, dependency.Type); } } // Configure event handlers, they are not part of the blueprint, so they have // to be added manually. Or need to create a module for this. tenantServiceCollection.AddScoped <IEventBus, DefaultOrchardEventBus>(); tenantServiceCollection.AddSingleton <IEventBusState, EventBusState>(); //// Apply custom options for the tenant //var options = blueprint //.Dependencies //.Where(x => typeof(IConfigure).IsAssignableFrom(x.Type)) //.Select(x => x.Type).ToArray(); //// TODO: Group all options by type and reuse the same configuration object //// such that multiple feature can update the same configuration object. //foreach (var type in options) //{ // var optionType = type // .GetInterfaces() // .Where(x => typeof(IConfigure).IsAssignableFrom(x)) // .FirstOrDefault() // .GetGenericArguments() // .FirstOrDefault(); // if(optionType == null) // { // // Ignore non-generic implementation // continue; // } // var optionObject = Activator.CreateInstance(optionType); // var configureMethod = type.GetMethod("Configure"); // var optionHost = Activator.CreateInstance(type); // configureMethod.Invoke(optionHost, new[] { optionObject }); // tenantServiceCollection.ConfigureOptions(optionObject); //} // 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(IStartup).IsAssignableFrom(t.Type))) { moduleServiceCollection.AddSingleton(typeof(IStartup), dependency.Type); tenantServiceCollection.AddSingleton(typeof(IStartup), dependency.Type); } // Make shell settings available to the modules moduleServiceCollection.AddSingleton(settings); var moduleServiceProvider = moduleServiceCollection.BuildServiceProvider(); // Let any module add custom service descriptors to the tenant foreach (var service in moduleServiceProvider.GetServices <IStartup>()) { service.ConfigureServices(tenantServiceCollection); } // Configuring data access var indexes = tenantServiceCollection .Select(x => x.ImplementationType) .Where(t => t != null && typeof(IIndexProvider).IsAssignableFrom(t) && t.GetTypeInfo().IsClass) .Distinct() .ToArray(); if (settings.DatabaseProvider != null) { var store = new Store(cfg => { IConnectionFactory connectionFactory = null; switch (settings.DatabaseProvider) { case "SqlConnection": connectionFactory = new DbConnectionFactory <SqlConnection>(settings.ConnectionString); break; case "SqliteConnection": connectionFactory = new DbConnectionFactory <SqliteConnection>(settings.ConnectionString); break; default: throw new ArgumentException("Unknown database provider: " + settings.DatabaseProvider); } cfg.ConnectionFactory = connectionFactory; cfg.IsolationLevel = IsolationLevel.ReadUncommitted; if (!String.IsNullOrWhiteSpace(settings.TablePrefix)) { cfg.TablePrefix = settings.TablePrefix + "_"; } #if SQL var sqlFactory = new SqlDocumentStorageFactory(connectionFactory); sqlFactory.IsolationLevel = IsolationLevel.ReadUncommitted; sqlFactory.ConnectionFactory = connectionFactory; if (!String.IsNullOrWhiteSpace(settings.TablePrefix)) { sqlFactory.TablePrefix = settings.TablePrefix + "_"; } cfg.DocumentStorageFactory = sqlFactory; #else var storageFactory = new LightningDocumentStorageFactory(Path.Combine(_appDataFolderRoot.RootFolder, "Sites", settings.Name, "Documents")); cfg.DocumentStorageFactory = storageFactory; #endif //cfg.RunDefaultMigration(); } ); var idGenerator = new LinearBlockIdGenerator(store.Configuration.ConnectionFactory, 20, "contentitem", store.Configuration.TablePrefix); store.RegisterIndexes(indexes); tenantServiceCollection.AddSingleton <IStore>(store); tenantServiceCollection.AddSingleton <LinearBlockIdGenerator>(idGenerator); tenantServiceCollection.AddScoped <ISession>(serviceProvider => store.CreateSession()); } // Register event handlers on the event bus var eventHandlers = tenantServiceCollection .Select(x => x.ImplementationType) .Distinct() .Where(t => t != null && typeof(IEventHandler).IsAssignableFrom(t) && t.GetTypeInfo().IsClass) .ToArray(); foreach (var handlerClass in eventHandlers) { tenantServiceCollection.AddScoped(handlerClass); // Register dynamic proxies to intercept direct calls if an IEventHandler is resolved, dispatching the call to // the event bus. foreach (var i in handlerClass.GetInterfaces().Where(t => typeof(IEventHandler).IsAssignableFrom(t))) { tenantServiceCollection.AddScoped(i, serviceProvider => { var proxy = DefaultOrchardEventBus.CreateProxy(i); proxy.EventBus = serviceProvider.GetService <IEventBus>(); return(proxy); }); } } var shellServiceProvider = tenantServiceCollection.BuildServiceProvider(); var eventBusState = shellServiceProvider.GetService <IEventBusState>(); // Register any IEventHandler method in the event bus foreach (var handlerClass in eventHandlers) { foreach (var handlerInterface in handlerClass.GetInterfaces().Where(x => typeof(IEventHandler).IsAssignableFrom(x) && typeof(IEventHandler) != x)) { foreach (var interfaceMethod in handlerInterface.GetMethods()) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"{handlerClass.Name}/{handlerInterface.Name}.{interfaceMethod.Name}"); } //var classMethod = handlerClass.GetMethods().Where(x => x.Name == interfaceMethod.Name && x.GetParameters().Length == interfaceMethod.GetParameters().Length).FirstOrDefault(); Func <IServiceProvider, IDictionary <string, object>, Task> d = (sp, parameters) => DefaultOrchardEventBus.Invoke(sp, parameters, interfaceMethod, handlerClass); eventBusState.Add(handlerInterface.Name + "." + interfaceMethod.Name, d); } } } 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); // Sure this is right? tenantServiceCollection.AddSingleton(_loggerFactory); foreach (var dependency in blueprint.Dependencies) { foreach (var interfaceType in dependency.Type.GetInterfaces()) { // GetInterfaces returns the full hierarchy of interfaces if (interfaceType == typeof(ISingletonDependency) || interfaceType == typeof(ITransientDependency) || interfaceType == typeof(IDependency) || !typeof(IDependency).IsAssignableFrom(interfaceType)) { continue; } if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Type: {0}, Interface Type: {1}", dependency.Type, interfaceType); } if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddSingleton(interfaceType, dependency.Type); } else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddTransient(interfaceType, dependency.Type); } else if (typeof(IDependency).IsAssignableFrom(interfaceType)) { tenantServiceCollection.AddScoped(interfaceType, dependency.Type); } } } // Register components foreach (var dependency in blueprint.Dependencies) { var serviceComponentAttribute = dependency.Type.GetTypeInfo().GetCustomAttribute<ServiceScopeAttribute>(); if (serviceComponentAttribute != null) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Type: {0}, Interface Type: {1}", dependency.Type, serviceComponentAttribute.ServiceType); } serviceComponentAttribute.Register(tenantServiceCollection, dependency.Type); } } // Configure event handlers, they are not part of the blueprint, so they have // to be added manually. Or need to create a module for this. tenantServiceCollection.AddScoped<IEventBus, DefaultOrchardEventBus>(); tenantServiceCollection.AddSingleton<IEventBusState, EventBusState>(); //// Apply custom options for the tenant //var options = blueprint //.Dependencies //.Where(x => typeof(IConfigure).IsAssignableFrom(x.Type)) //.Select(x => x.Type).ToArray(); //// TODO: Group all options by type and reuse the same configuration object //// such that multiple feature can update the same configuration object. //foreach (var type in options) //{ // var optionType = type // .GetInterfaces() // .Where(x => typeof(IConfigure).IsAssignableFrom(x)) // .FirstOrDefault() // .GetGenericArguments() // .FirstOrDefault(); // if(optionType == null) // { // // Ignore non-generic implementation // continue; // } // var optionObject = Activator.CreateInstance(optionType); // var configureMethod = type.GetMethod("Configure"); // var optionHost = Activator.CreateInstance(type); // configureMethod.Invoke(optionHost, new[] { optionObject }); // tenantServiceCollection.ConfigureOptions(optionObject); //} // 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(IStartup).IsAssignableFrom(t.Type))) { moduleServiceCollection.AddSingleton(typeof(IStartup), dependency.Type); tenantServiceCollection.AddSingleton(typeof(IStartup), dependency.Type); } // Make shell settings available to the modules moduleServiceCollection.AddSingleton(settings); var moduleServiceProvider = moduleServiceCollection.BuildServiceProvider(); // Let any module add custom service descriptors to the tenant foreach (var service in moduleServiceProvider.GetServices<IStartup>()) { service.ConfigureServices(tenantServiceCollection); } // Configuring data access var indexes = tenantServiceCollection .Select(x => x.ImplementationType) .Where(t => t != null && typeof(IIndexProvider).IsAssignableFrom(t) && t.GetTypeInfo().IsClass) .Distinct() .ToArray(); if (settings.DatabaseProvider != null) { var store = new Store(cfg => { IConnectionFactory connectionFactory = null; switch (settings.DatabaseProvider) { case "SqlConnection": connectionFactory = new DbConnectionFactory<SqlConnection>(settings.ConnectionString); break; case "SqliteConnection": connectionFactory = new DbConnectionFactory<SqliteConnection>(settings.ConnectionString); break; default: throw new ArgumentException("Unknown database provider: " + settings.DatabaseProvider); } cfg.ConnectionFactory = connectionFactory; cfg.IsolationLevel = IsolationLevel.ReadUncommitted; if (!String.IsNullOrWhiteSpace(settings.TablePrefix)) { cfg.TablePrefix = settings.TablePrefix + "_"; } #if SQL var sqlFactory = new SqlDocumentStorageFactory(connectionFactory); sqlFactory.IsolationLevel = IsolationLevel.ReadUncommitted; sqlFactory.ConnectionFactory = connectionFactory; if (!String.IsNullOrWhiteSpace(settings.TablePrefix)) { sqlFactory.TablePrefix = settings.TablePrefix + "_"; } cfg.DocumentStorageFactory = sqlFactory; #else var storageFactory = new LightningDocumentStorageFactory(Path.Combine(_appDataFolderRoot.RootFolder, "Sites", settings.Name, "Documents")); cfg.DocumentStorageFactory = storageFactory; #endif //cfg.RunDefaultMigration(); } ); var idGenerator = new LinearBlockIdGenerator(store.Configuration.ConnectionFactory, 20, "contentitem", store.Configuration.TablePrefix); store.RegisterIndexes(indexes); tenantServiceCollection.AddSingleton<IStore>(store); tenantServiceCollection.AddSingleton<LinearBlockIdGenerator>(idGenerator); tenantServiceCollection.AddScoped<ISession>(serviceProvider => store.CreateSession()); } // Register event handlers on the event bus var eventHandlers = tenantServiceCollection .Select(x => x.ImplementationType) .Distinct() .Where(t => t != null && typeof(IEventHandler).IsAssignableFrom(t) && t.GetTypeInfo().IsClass) .ToArray(); foreach (var handlerClass in eventHandlers) { tenantServiceCollection.AddScoped(handlerClass); // Register dynamic proxies to intercept direct calls if an IEventHandler is resolved, dispatching the call to // the event bus. foreach (var i in handlerClass.GetInterfaces().Where(t => typeof(IEventHandler).IsAssignableFrom(t))) { tenantServiceCollection.AddScoped(i, serviceProvider => { var proxy = DefaultOrchardEventBus.CreateProxy(i); proxy.EventBus = serviceProvider.GetService<IEventBus>(); return proxy; }); } } var shellServiceProvider = tenantServiceCollection.BuildServiceProvider(); var eventBusState = shellServiceProvider.GetService<IEventBusState>(); // Register any IEventHandler method in the event bus foreach (var handlerClass in eventHandlers) { foreach (var handlerInterface in handlerClass.GetInterfaces().Where(x => typeof(IEventHandler).IsAssignableFrom(x) && typeof(IEventHandler) != x)) { foreach (var interfaceMethod in handlerInterface.GetMethods()) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"{handlerClass.Name}/{handlerInterface.Name}.{interfaceMethod.Name}"); } //var classMethod = handlerClass.GetMethods().Where(x => x.Name == interfaceMethod.Name && x.GetParameters().Length == interfaceMethod.GetParameters().Length).FirstOrDefault(); Func<IServiceProvider, IDictionary<string, object>, Task> d = (sp, parameters) => DefaultOrchardEventBus.Invoke(sp, parameters, interfaceMethod, handlerClass); eventBusState.Add(handlerInterface.Name + "." + interfaceMethod.Name, d); } } } return shellServiceProvider; }