public static ServiceProvider Build(ReverseEngineerOptions options)
        {
            // Add base services for scaffolding
            var serviceCollection = new ServiceCollection();

            serviceCollection
            .AddEntityFrameworkDesignTimeServices()
            .AddSingleton <IOperationReporter, OperationReporter>()
            .AddSingleton <IOperationReportHandler, OperationReportHandler>();

            if (options.UseHandleBars)
            {
                //TODO Consider being selective based on SelectedToBeGenerated
                var selected = Microsoft.EntityFrameworkCore.Design.ReverseEngineerOptions.DbContextAndEntities;
                var language = (LanguageOptions)options.SelectedHandlebarsLanguage;
                serviceCollection.AddHandlebarsScaffolding(selected, language);
                serviceCollection.AddSingleton <ITemplateFileService>(provider => new CustomTemplateFileService(options.ProjectPath));
            }

            if (options.CustomReplacers != null)
            {
                serviceCollection.AddSingleton <ICandidateNamingService>(provider => new ReplacingCandidateNamingService(options.CustomReplacers));
            }

            if (options.UseInflector)
            {
                if (options.UseLegacyPluralizer)
                {
                    serviceCollection.AddSingleton <IPluralizer, LegacyInflectorPluralizer>();
                }
                else
                {
                    serviceCollection.AddSingleton <IPluralizer, InflectorPluralizer>();
                }
            }

            // Add database provider services
            switch (options.DatabaseType)
            {
            case DatabaseType.SQLCE35:
                throw new NotImplementedException();

            case DatabaseType.SQLCE40:
                var sqlCeProvider = new SqlCeDesignTimeServices();
                sqlCeProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            case DatabaseType.SQLServer:
                var provider = new SqlServerDesignTimeServices();
                provider.ConfigureDesignTimeServices(serviceCollection);

                var spatial = new SqlServerNetTopologySuiteDesignTimeServices();
                spatial.ConfigureDesignTimeServices(serviceCollection);

                if (!string.IsNullOrEmpty(options.Dacpac))
                {
                    serviceCollection.AddSingleton <IDatabaseModelFactory, SqlServerDacpacDatabaseModelFactory>();
                }
                break;

            case DatabaseType.Npgsql:
                var npgsqlProvider = new NpgsqlDesignTimeServices();
                npgsqlProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            case DatabaseType.Mysql:
                var mysqlProvider = new MySqlDesignTimeServices();
                mysqlProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            case DatabaseType.SQLite:
                var sqliteProvider = new SqliteDesignTimeServices();
                sqliteProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(serviceCollection.BuildServiceProvider());
        }
        public EfCoreReverseEngineerResult GenerateFiles(ReverseEngineerOptions reverseEngineerOptions)
        {
            var errors   = new List <string>();
            var warnings = new List <string>();
            var reporter = new OperationReporter(
                new OperationReportHandler(
                    m => errors.Add(m),
                    m => warnings.Add(m)));

            // Add base services for scaffolding
            var serviceCollection = new ServiceCollection();

            serviceCollection
            .AddEntityFrameworkDesignTimeServices()
            .AddSingleton <IOperationReporter, OperationReporter>()
            .AddSingleton <IOperationReportHandler, OperationReportHandler>();

            if (reverseEngineerOptions.UseHandleBars)
            {
                //TODO Consider being selective based on SelectedToBeGenerated
                serviceCollection.AddHandlebarsScaffolding();
                serviceCollection.AddSingleton <ITemplateFileService>(provider => new CustomTemplateFileService(reverseEngineerOptions.ProjectPath));
            }

            if (reverseEngineerOptions.CustomReplacers != null)
            {
                serviceCollection.AddSingleton <ICandidateNamingService>(provider => new ReplacingCandidateNamingService(reverseEngineerOptions.CustomReplacers));
            }

            if (reverseEngineerOptions.UseInflector)
            {
                serviceCollection.AddSingleton <IPluralizer, InflectorPluralizer>();
            }

            // Add database provider services
            switch (reverseEngineerOptions.DatabaseType)
            {
            case DatabaseType.SQLCE35:
                throw new NotImplementedException();

            case DatabaseType.SQLCE40:
                var sqlCeProvider = new SqlCeDesignTimeServices();
                sqlCeProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            case DatabaseType.Npgsql:
                var npgsqlProvider = new NpgsqlDesignTimeServices();
                npgsqlProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            case DatabaseType.SQLServer:
                var provider = new SqlServerDesignTimeServices();
                provider.ConfigureDesignTimeServices(serviceCollection);
                if (!string.IsNullOrEmpty(reverseEngineerOptions.Dacpac))
                {
                    serviceCollection.AddSingleton <IDatabaseModelFactory, SqlServerDacpacDatabaseModelFactory>();
                }
                break;

            case DatabaseType.SQLite:
                var sqliteProvider = new SqliteDesignTimeServices();
                sqliteProvider.ConfigureDesignTimeServices(serviceCollection);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            var serviceProvider = serviceCollection.BuildServiceProvider();
            var scaffolder      = serviceProvider.GetService <IReverseEngineerScaffolder>();

            var schemas = new List <string>();

            if (reverseEngineerOptions.DefaultDacpacSchema != null)
            {
                schemas.Add(reverseEngineerOptions.DefaultDacpacSchema);
            }

            var @namespace = reverseEngineerOptions.ProjectRootNamespace;

            if (!string.IsNullOrEmpty(reverseEngineerOptions.OutputPath))
            {
                @namespace += "." + reverseEngineerOptions.OutputPath.Replace(Path.DirectorySeparatorChar, '.').Replace(Path.AltDirectorySeparatorChar, '.');
            }
            var modelOptions = new ModelReverseEngineerOptions
            {
                UseDatabaseNames = reverseEngineerOptions.UseDatabaseNames
            };

            var codeOptions = new ModelCodeGenerationOptions
            {
                UseDataAnnotations = !reverseEngineerOptions.UseFluentApiOnly
            };

            var scaffoldedModel = scaffolder.ScaffoldModel(
                reverseEngineerOptions.Dacpac != null
                        ? reverseEngineerOptions.Dacpac
                        : reverseEngineerOptions.ConnectionString,
                reverseEngineerOptions.Tables.Select(m => m.UnsafeFullName).ToArray(),
                schemas,
                @namespace,
                "C#",
                null,
                reverseEngineerOptions.ContextClassName,
                modelOptions,
                codeOptions);

            var filePaths = scaffolder.Save(
                scaffoldedModel,
                Path.Combine(reverseEngineerOptions.ProjectPath, reverseEngineerOptions.OutputPath),
                overwriteFiles: true);

            foreach (var file in filePaths.AdditionalFiles)
            {
                PostProcess(file, reverseEngineerOptions.IdReplace);
            }
            PostProcess(filePaths.ContextFile, reverseEngineerOptions.IdReplace);

            PostProcessContext(filePaths.ContextFile, reverseEngineerOptions);

            var result = new EfCoreReverseEngineerResult
            {
                EntityErrors        = errors,
                EntityWarnings      = warnings,
                EntityTypeFilePaths = filePaths.AdditionalFiles,
                ContextFilePath     = filePaths.ContextFile,
            };

            return(result);
        }