// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using PhenX.EntityFrameworkCore.BulkInsert.MySql; using PhenX.EntityFrameworkCore.BulkInsert.PostgreSql; using PhenX.EntityFrameworkCore.BulkInsert.SqlServer; using Squidex.Assets.TusAdapter; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Teams; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.Repositories; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Text; using Squidex.Domain.Apps.Entities.Contents.Text.State; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.History.Repositories; using Squidex.Domain.Apps.Entities.Rules; using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Repositories; using Squidex.Domain.Apps.Entities.Teams; using Squidex.Domain.Apps.Entities.Teams.Repositories; using Squidex.Domain.Users; using Squidex.Events.EntityFramework; using Squidex.Flows.EntityFramework; using Squidex.Infrastructure; using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Migrations; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.States; using Squidex.Infrastructure.UsageTracking; using Squidex.Messaging; using Squidex.Providers.MySql; using Squidex.Providers.MySql.App; using Squidex.Providers.MySql.Content; using Squidex.Providers.Postgres; using Squidex.Providers.Postgres.App; using Squidex.Providers.Postgres.Content; using Squidex.Providers.SqlServer; using Squidex.Providers.SqlServer.App; using Squidex.Providers.SqlServer.Content; using YDotNet.Server.EntityFramework; namespace Squidex; public static class ServiceExtensions { public static void AddSquidexEntityFramework(this IServiceCollection services, IConfiguration config) { var connectionString = config.GetRequiredValue("store:sql:connectionString"); config.ConfigureByOption("store:sql:provider", new Alternatives { ["MySql"] = () => { var versionString = config.GetOptionalValue("store:sql:version"); var version = !string.IsNullOrWhiteSpace(versionString) ? ServerVersion.Parse(versionString) : ServerVersion.AutoDetect(connectionString); services.AddPooledDbContextFactory(builder => { builder.SetDefaults(); builder.UseMySql(connectionString, version, options => { options.UseNetTopologySuite(); options.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically); }); builder.UseBulkInsertMySql(); }); services.AddNamedDbContext((builder, name) => { builder.SetDefaults(); builder.UseBulkInsertMySql(); builder.UseMySql(connectionString, version, options => { options.MigrationsHistoryTable($"{name}MigrationHistory"); options.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically); }); builder.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); }); services.AddSingleton(typeof(ISnapshotStore<>), typeof(MySqlSnapshotStore<>)); services.AddSquidexEntityFramework(config); services.AddSingletonAs() .As(); services.AddSingletonAs() .As(); }, ["Postgres"] = () => { services.AddPooledDbContextFactory(builder => { builder.SetDefaults(); builder.UseBulkInsertPostgreSql(); builder.UseNpgsql(connectionString, options => { options.UseNetTopologySuite(); }); }); services.AddNamedDbContext((builder, name) => { builder.SetDefaults(); builder.UseBulkInsertPostgreSql(); builder.UseNpgsql(connectionString, options => { options.MigrationsHistoryTable($"{name}MigrationHistory"); }); builder.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); }); services.AddSingleton(typeof(ISnapshotStore<>), typeof(PostgresSnapshotStore<>)); services.AddSquidexEntityFramework(config); services.AddSingletonAs() .As(); services.AddSingletonAs() .As(); }, ["SqlServer"] = () => { services.AddPooledDbContextFactory(builder => { builder.SetDefaults(); builder.UseSqlServer(connectionString, options => { options.UseNetTopologySuite(); }); builder.UseBulkInsertSqlServer(); }); services.AddNamedDbContext((builder, name) => { builder.SetDefaults(); builder.UseBulkInsertSqlServer(); builder.UseSqlServer(connectionString, options => { options.MigrationsHistoryTable($"{name}MigrationHistory"); }); builder.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); }); services.AddSingleton(typeof(ISnapshotStore<>), typeof(SqlServerSnapshotStore<>)); services.AddSquidexEntityFramework(config); services.AddSingletonAs() .As(); services.AddSingletonAs() .As(); }, }); } private static void AddSquidexEntityFramework(this IServiceCollection services, IConfiguration config) where TContext : AppDbContext where TContextContext : ContentDbContext { if (config.GetValue("store:sql:runMigration")) { services.AddSingletonAs>(); } services.AddOpenIddict() .AddCore(builder => { builder.UseEntityFrameworkCore() .UseDbContext(); }); services.AddIdentityCore() .AddEntityFrameworkStores(); services.AddYDotNet() .AddEntityFrameworkStorage(); services.AddAI() .AddEntityFrameworkChatStore(); services.AddMessaging() .AddEntityFrameworkDataStore(config); services.AddSingletonAs>() .As(); services.AddSingletonAs>() .As(); services.AddHealthChecks() .AddDbContextCheck(); services.AddSingletonAs>() .As().As>(); services.AddSingletonAs>() .As().As>().As(); services.AddSingletonAs>() .As().As>().As(); services.AddSingletonAs>() .As().As>().As(); services.AddSingletonAs>() .As().As(); services.AddSingletonAs>() .As(); services.AddSingletonAs>() .As().As>().As(); services.AddSingletonAs>() .As().As>().As().As(); services.AddSingletonAs>() .As().As>(); services.AddSingletonAs>() .As().As(); services.AddSingletonAs>() .As().As(); services.AddSingletonAs>() .As(); services.AddSingletonAs() .As(); services.AddSingletonAs() .As().As(); services.AddFlowsCore() .AddEntityFrameworkStore(); services.AddCronJobsCore() .AddEntityFrameworkStore(); services.AddEntityFrameworkAssetKeyValueStore(); } public static void AddSquidexEntityFrameworkEventStore(this IServiceCollection services, IConfiguration config) { config.ConfigureByOption("store:sql:provider", new Alternatives { ["MySql"] = () => { services.AddEntityFrameworkEventStore(config) .AddMysqlAdapter(); }, ["Postgres"] = () => { services.AddEntityFrameworkEventStore(config) .AddPostgresAdapter(); }, ["SqlServer"] = () => { services.AddEntityFrameworkEventStore(config) .AddSqlServerAdapter(); }, }); } public static MessagingBuilder AddSquidexEntityFrameworkTransport(this MessagingBuilder messaging, IConfiguration config) { config.ConfigureByOption("store:sql:provider", new Alternatives { ["MySql"] = () => { messaging.AddEntityFrameworkTransport(config); }, ["Postgres"] = () => { messaging.AddEntityFrameworkTransport(config); }, ["SqlServer"] = () => { messaging.AddEntityFrameworkTransport(config); }, }); return messaging; } public class MySqlSnapshotStore(IDbContextFactory dbContextFactory) : EFSnapshotStore>(dbContextFactory) { } public class PostgresSnapshotStore(IDbContextFactory dbContextFactory) : EFSnapshotStore>(dbContextFactory) { } public class SqlServerSnapshotStore(IDbContextFactory dbContextFactory) : EFSnapshotStore>(dbContextFactory) { } public static IdentityBuilder AddIdentityCore(this IServiceCollection services) { return new IdentityBuilder(typeof(IdentityUser), typeof(IdentityRole), services); } }