Example #1
0
        /// <summary>
        /// Adds tenant level configuration to serve static files from modules
        /// </summary>
        private static void AddStaticFiles(BlocksCoreBuilder builder)
        {
            builder.Configure((app, routes, serviceProvider) =>
            {
                var env        = serviceProvider.GetRequiredService <IHostingEnvironment>();
                var appContext = serviceProvider.GetRequiredService <IApplicationContext>();

                IFileProvider fileProvider;
                if (env.IsDevelopment())
                {
                    var fileProviders = new List <IFileProvider>();
                    fileProviders.Add(new ModuleProjectStaticFileProvider(appContext));
                    fileProviders.Add(new ModuleEmbeddedStaticFileProvider(appContext));
                    fileProvider = new CompositeFileProvider(fileProviders);
                }
                else
                {
                    fileProvider = new ModuleEmbeddedStaticFileProvider(appContext);
                }

                var options = serviceProvider.GetRequiredService <IOptions <StaticFileOptions> >().Value;

                options.RequestPath  = "";
                options.FileProvider = fileProvider;

                // Cache static files for a year as they are coming from embedded resources and should not vary
                options.OnPrepareResponse = ctx =>
                {
                    ctx.Context.Response.Headers[HeaderNames.CacheControl] = "max-age=" + (int)TimeSpan.FromDays(365).TotalSeconds;
                };

                app.UseStaticFiles(options);
            });
        }
Example #2
0
        /// <summary>
        /// Adds BlocksCore services to the host service collection.
        /// </summary>
        public static BlocksCoreBuilder AddBlocksCore(this IServiceCollection services)
        {
            // If an instance of BlocksCoreBuilder exists reuse it,
            // so we can call AddBlocksCore several times.
            var builder = services
                          .LastOrDefault(d => d.ServiceType == typeof(BlocksCoreBuilder))?
                          .ImplementationInstance as BlocksCoreBuilder;

            if (builder == null)
            {
                builder = new BlocksCoreBuilder(services);
                services.AddSingleton(builder);

                AddDefaultServices(services);
                AddShellServices(services);
                AddExtensionServices(builder);
                AddStaticFiles(builder);

                AddAntiForgery(builder);
                AddAuthentication(builder);
                AddDataProtection(builder);

                // Register the list of services to be resolved later on
                services.AddSingleton(services);
            }

            return(builder);
        }
        /// <summary>
        /// Adds tenant level caching services.
        /// </summary>
        public static BlocksCoreBuilder AddCaching(this BlocksCoreBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                services.AddTransient <ITagCache, DefaultTagCache>();
                services.AddSingleton <ISignal, Signal>();
                services.AddScoped <ICacheContextManager, CacheContextManager>();
                services.AddScoped <ICacheScopeManager, CacheScopeManager>();

                services.AddScoped <ICacheContextProvider, FeaturesCacheContextProvider>();
                services.AddScoped <ICacheContextProvider, QueryCacheContextProvider>();
                services.AddScoped <ICacheContextProvider, RolesCacheContextProvider>();
                services.AddScoped <ICacheContextProvider, RouteCacheContextProvider>();
                services.AddScoped <ICacheContextProvider, UserCacheContextProvider>();
                services.AddScoped <ICacheContextProvider, KnownValueCacheContextProvider>();

                // IMemoryCache is registered at the tenant level so that there is one instance for each tenant.
                services.AddSingleton <IMemoryCache, MemoryCache>();

                // MemoryDistributedCache needs to be registered as a singleton as it owns a MemoryCache instance.
                services.AddSingleton <IDistributedCache, MemoryDistributedCache>();
            });

            return(builder);
        }
        /// <summary>
        /// Registers a default tenant with a set of features that are used to setup and configure the actual tenants.
        /// For instance you can use this to add a custom Setup module.
        /// </summary>
        public static BlocksCoreBuilder AddSetupFeatures(this BlocksCoreBuilder builder, params string[] featureIds)
        {
            foreach (var featureId in featureIds)
            {
                builder.ApplicationServices.AddTransient(sp => new ShellFeature(featureId));
            }

            return(builder);
        }
        /// <summary>
        /// Host services to load site settings from the file system
        /// </summary>
        public static BlocksCoreBuilder AddSitesFolder(this BlocksCoreBuilder builder)
        {
            var services = builder.ApplicationServices;

            services.AddSingleton <IShellSettingsConfigurationProvider, ShellSettingsConfigurationProvider>();
            services.AddSingleton <IShellSettingsManager, ShellSettingsManager>();
            services.AddTransient <IConfigureOptions <ShellOptions>, ShellOptionsSetup>();

            return(builder);
        }
        /// <summary>
        /// Adds tenant level deferred tasks services.
        /// </summary>
        public static BlocksCoreBuilder AddDeferredTasks(this BlocksCoreBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                services.TryAddScoped <IDeferredTaskEngine, DeferredTaskEngine>();
                services.TryAddScoped <IDeferredTaskState, HttpContextTaskState>();
            });

            return(builder);
        }
Example #7
0
        /// <summary>
        /// Adds host level services to provide CLI commands.
        /// </summary>
        public static BlocksCoreBuilder AddCommands(this BlocksCoreBuilder builder)
        {
            var services = builder.ApplicationServices;

            services.AddScoped <ICommandManager, DefaultCommandManager>();
            services.AddScoped <ICommandHandler, HelpCommand>();

            services.AddScoped <ICommandParametersParser, CommandParametersParser>();
            services.AddScoped <ICommandParser, CommandParser>();

            return(builder);
        }
        /// <summary>
        /// Registers tenants defined in configuration.
        /// </summary>
        public static BlocksCoreBuilder WithTenants(this BlocksCoreBuilder builder)
        {
            var services = builder.ApplicationServices;

            services.AddSingleton <IShellSettingsConfigurationProvider, FileShellSettingsConfigurationProvider>();
            services.AddScoped <IShellDescriptorManager, FileShellDescriptorManager>();
            services.AddSingleton <IShellSettingsManager, ShellSettingsManager>();
            services.AddTransient <IConfigureOptions <ShellOptions>, ShellOptionsSetup>();
            services.AddScoped <ShellSettingsWithTenants>();

            return(builder);
        }
Example #9
0
        private static void AddExtensionServices(BlocksCoreBuilder builder)
        {
            builder.ApplicationServices.AddSingleton <IModuleNamesProvider, AssemblyAttributeModuleNamesProvider>();
            builder.ApplicationServices.AddSingleton <IApplicationContext, ModularApplicationContext>();

            builder.ApplicationServices.AddExtensionManagerHost();

            builder.ConfigureServices(services =>
            {
                services.AddExtensionManager();
            });
        }
        /// <summary>
        /// Registers at the tenant level a set of features which are always enabled.
        /// </summary>
        public static BlocksCoreBuilder AddTenantFeatures(this BlocksCoreBuilder builder, params string[] featureIds)
        {
            builder.ConfigureServices(services =>
            {
                foreach (var featureId in featureIds)
                {
                    services.AddTransient(sp => new ShellFeature(featureId, alwaysEnabled: true));
                }
            });

            return(builder);
        }
        /// <summary>
        /// Adds services at the host level to load site settings from the file system
        /// and tenant level services to store states and descriptors in the database.
        /// </summary>
        public static BlocksCoreBuilder AddDataStorage(this BlocksCoreBuilder builder)
        {
            builder.AddSitesFolder()
            .ConfigureServices(services =>
            {
                services.AddScoped <IShellDescriptorManager, ShellDescriptorManager>();
                services.AddScoped <IShellStateManager, ShellStateManager>();
                services.AddScoped <IShellFeaturesManager, ShellFeaturesManager>();
                services.AddScoped <IShellDescriptorFeaturesManager, ShellDescriptorFeaturesManager>();
            });

            return(builder);
        }
Example #12
0
        /// <summary>
        /// Adds tenant level data protection services.
        /// </summary>
        private static void AddDataProtection(BlocksCoreBuilder builder)
        {
            builder.ConfigureServices((services, serviceProvider) =>
            {
                var settings = serviceProvider.GetRequiredService <ShellSettings>();
                var options  = serviceProvider.GetRequiredService <IOptions <ShellOptions> >();

                var directory = Directory.CreateDirectory(Path.Combine(
                                                              options.Value.ShellsApplicationDataPath,
                                                              options.Value.ShellsContainerName,
                                                              settings.Name, "DataProtection-Keys"));

                // Re-register the data protection services to be tenant-aware so that modules that internally
                // rely on IDataProtector/IDataProtectionProvider automatically get an isolated instance that
                // manages its own key ring and doesn't allow decrypting payloads encrypted by another tenant.
                // By default, the key ring is stored in the tenant directory of the configured App_Data path.
                var collection = new ServiceCollection()
                                 .AddDataProtection()
                                 .PersistKeysToFileSystem(directory)
                                 .SetApplicationName(settings.Name)
                                 .Services;

                // Retrieve the implementation type of the newly startup filter registered as a singleton
                var startupFilterType = collection.FirstOrDefault(s => s.ServiceType == typeof(IStartupFilter))?.ImplementationType;

                if (startupFilterType != null)
                {
                    // Remove any previously registered data protection startup filters.
                    var descriptors = services.Where(s => s.ServiceType == typeof(IStartupFilter) &&
                                                     (s.ImplementationInstance?.GetType() == startupFilterType ||
                                                      s.ImplementationType == startupFilterType)).ToArray();

                    foreach (var descriptor in descriptors)
                    {
                        services.Remove(descriptor);
                    }
                }

                // Remove any previously registered options setups.
                services.RemoveAll <IConfigureOptions <KeyManagementOptions> >();
                services.RemoveAll <IConfigureOptions <DataProtectionOptions> >();

                services.Add(collection);
            });
        }
Example #13
0
        /// <summary>
        /// Adds host and tenant level antiforgery services.
        /// </summary>
        private static void AddAntiForgery(BlocksCoreBuilder builder)
        {
            builder.ApplicationServices.AddAntiforgery();

            builder.ConfigureServices((services, serviceProvider) =>
            {
                var settings = serviceProvider.GetRequiredService <ShellSettings>();

                var tenantName   = settings.Name;
                var tenantPrefix = "/" + settings.RequestUrlPrefix;

                services.AddAntiforgery(options =>
                {
                    options.Cookie.Name = "orchantiforgery_" + tenantName;
                    options.Cookie.Path = tenantPrefix;
                });
            });
        }
Example #14
0
        /// <summary>
        /// Adds host and tenant level authentication services and configuration.
        /// </summary>
        private static void AddAuthentication(BlocksCoreBuilder builder)
        {
            builder.ApplicationServices.AddAuthentication();

            builder.ConfigureServices(services =>
            {
                services.AddAuthentication();

                // IAuthenticationSchemeProvider is already registered at the host level.
                // We need to register it again so it is taken into account at the tenant level
                // because it holds a reference to an underlying dictionary, responsible of storing
                // the registered schemes which need to be distinct for each tenant.
                services.AddSingleton <IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();
            })
            .Configure(app =>
            {
                app.UseAuthentication();
            });
        }
Example #15
0
        public static BlocksCoreBuilder AddDataAccess(this BlocksCoreBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                services.TryAddDataProvider(name: "Sql Server", value: "SqlConnection", hasConnectionString: true,
                                            hasTablePrefix: true, isDefault: false);
                services.TryAddDataProvider(name: "Sqlite", value: "Sqlite", hasConnectionString: false,
                                            hasTablePrefix: false, isDefault: true);
                services.TryAddDataProvider(name: "MySql", value: "MySql", hasConnectionString: true,
                                            hasTablePrefix: true, isDefault: false);
                services.TryAddDataProvider(name: "Postgres", value: "Postgres", hasConnectionString: true,
                                            hasTablePrefix: true, isDefault: false);

                services.AddDbContext <DbContext, BlocksCoreDbContext>();


                services.AddScoped <IDataContext, DataContext>();
            });

            return(builder);
        }
        /// <summary>
        /// Registers and configures a background hosted service to manage tenant background tasks.
        /// </summary>
        public static BlocksCoreBuilder AddBackgroundService(this BlocksCoreBuilder builder)
        {
            builder.ApplicationServices.AddSingleton <IHostedService, ModularBackgroundService>();

            return(builder);
        }
 /// <summary>
 /// Adds tenant level MVC services and configuration.
 /// </summary>
 public static BlocksCoreBuilder AddMvc(this BlocksCoreBuilder builder)
 {
     return(builder.RegisterStartup <Startup>());
 }