示例#1
0
        public SettingsMigrator(DefaultObjectContext ctx)
        {
            Guard.ArgumentNotNull(() => ctx);

            _ctx      = ctx;
            _settings = _ctx.Set <Setting>();
        }
        public LocaleResourcesMigrator(DefaultObjectContext ctx)
        {
            Guard.ArgumentNotNull(() => ctx);

            _ctx       = ctx;
            _languages = _ctx.Set <Language>();
            _resources = _ctx.Set <LocaleStringResource>();
        }
示例#3
0
        public static void MigrateSettings(this DefaultObjectContext ctx, Action <SettingsBuilder> fn)
        {
            Guard.ArgumentNotNull(() => ctx);
            Guard.ArgumentNotNull(() => fn);

            var builder = new SettingsBuilder();

            fn(builder);
            var entries = builder.Build();

            var migrator = new SettingsMigrator(ctx);

            migrator.Migrate(entries);
        }
示例#4
0
        public static void MigrateLocaleResources(this DefaultObjectContext ctx, Action <LocaleResourcesBuilder> fn, bool updateTouchedResources = false)
        {
            Guard.ArgumentNotNull(() => ctx);
            Guard.ArgumentNotNull(() => fn);

            var builder = new LocaleResourcesBuilder();

            fn(builder);
            var entries = builder.Build();

            var migrator = new LocaleResourcesMigrator(ctx);

            migrator.Migrate(entries, updateTouchedResources);
        }
示例#5
0
        public static void ExecutePendingResourceMigrations(string resPath, DefaultObjectContext dbContext)
        {
            Guard.ArgumentNotNull(() => dbContext);

            string headPath = Path.Combine(resPath, "head.txt");

            if (!File.Exists(headPath))
            {
                return;
            }

            string resHead = File.ReadAllText(headPath).Trim();

            if (!MigratorUtils.IsValidMigrationId(resHead))
            {
                return;
            }

            var migrator   = new DbMigrator(new MigrationsConfiguration());
            var migrations = GetPendingResourceMigrations(migrator, resHead);

            foreach (var id in migrations)
            {
                if (IsAutomaticMigration(id))
                {
                    continue;
                }

                if (!IsValidMigrationId(id))
                {
                    continue;
                }

                // Resolve and instantiate the DbMigration instance from the assembly
                var migration = CreateMigrationInstanceByMigrationId(id, migrator.Configuration);

                var provider = migration as ILocaleResourcesProvider;
                if (provider == null)
                {
                    continue;
                }

                var builder = new LocaleResourcesBuilder();
                provider.MigrateLocaleResources(builder);

                var resEntries  = builder.Build();
                var resMigrator = new LocaleResourcesMigrator(dbContext);
                resMigrator.Migrate(resEntries);
            }
        }
示例#6
0
        /// <summary>
        /// Migrates the database to the latest version
        /// </summary>
        /// <returns>The number of applied migrations</returns>
        public int RunPendingMigrations(TContext context)
        {
            var pendingMigrations = GetPendingMigrations().ToList();

            if (!pendingMigrations.Any())
            {
                return(0);
            }

            var coreSeeders             = new List <SeederEntry>();
            var externalSeeders         = new List <SeederEntry>();
            var isCoreMigration         = context is DefaultObjectContext;
            var initialMigration        = this.GetDatabaseMigrations().LastOrDefault() ?? "[Initial]";
            var lastSuccessfulMigration = initialMigration;

            IDataSeeder <DefaultObjectContext> coreSeeder     = null;
            IDataSeeder <TContext>             externalSeeder = null;

            int result = 0;

            // Apply migrations
            foreach (var migrationId in pendingMigrations)
            {
                if (MigratorUtils.IsAutomaticMigration(migrationId))
                {
                    continue;
                }

                if (!MigratorUtils.IsValidMigrationId(migrationId))
                {
                    continue;
                }

                // Resolve and instantiate the DbMigration instance from the assembly
                var migration = MigratorUtils.CreateMigrationInstanceByMigrationId(migrationId, Configuration);

                // Seeders for the core DbContext must be run in any case
                // (e.g. for Resource or Setting updates even from external plugins)
                coreSeeder     = migration as IDataSeeder <DefaultObjectContext>;
                externalSeeder = null;

                if (!isCoreMigration)
                {
                    // Context specific seeders should only be resolved
                    // when origin is external (e.g. a Plugin)
                    externalSeeder = migration as IDataSeeder <TContext>;
                }

                try
                {
                    // Call the actual Update() to execute this migration
                    Update(migrationId);
                    result++;
                }
                catch (AutomaticMigrationsDisabledException)
                {
                    if (context is DefaultObjectContext)
                    {
                        throw;
                    }

                    // DbContexts in plugin assemblies tend to produce
                    // this error, but obviously without any negative side-effect.
                    // Therefore catch and forget!
                    // TODO: (MC) investigate this and implement a cleaner solution
                }
                catch (Exception ex)
                {
                    result = 0;
                    throw new DbMigrationException(lastSuccessfulMigration, migrationId, ex.InnerException ?? ex, false);
                }

                if (coreSeeder != null)
                {
                    coreSeeders.Add(new SeederEntry {
                        DataSeeder          = coreSeeder,
                        MigrationId         = migrationId,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                if (externalSeeder != null)
                {
                    externalSeeders.Add(new SeederEntry {
                        DataSeeder          = externalSeeder,
                        MigrationId         = migrationId,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                lastSuccessfulMigration = migrationId;
            }

            // Apply core data seeders first
            DefaultObjectContext coreContext = null;

            if (coreSeeders.Any())
            {
                coreContext = isCoreMigration ? context as DefaultObjectContext : new DefaultObjectContext();
                RunSeeders <DefaultObjectContext>(coreSeeders, coreContext);
            }

            // Apply external data seeders
            RunSeeders <TContext>(externalSeeders, context);

            Logger.Information("Database migration successful: {0} >> {1}".FormatInvariant(initialMigration, lastSuccessfulMigration));

            return(result);
        }
示例#7
0
        protected virtual InstallationResult InstallCore(ILifetimeScope scope, InstallModel model)
        {
            UpdateResult(x =>
            {
                x.ProgressMessage = _locService.GetResource("Progress.CheckingRequirements");
                x.Completed       = false;
            });

            if (DataSettings.DatabaseIsInstalled())
            {
                return(UpdateResult(x =>
                {
                    x.Success = true;
                    x.RedirectUrl = Url.Action("Index", "Home");
                }));
            }

            //set page timeout to 5 minutes
            this.Server.ScriptTimeout = 300;

            if (model.DatabaseConnectionString != null)
            {
                model.DatabaseConnectionString = model.DatabaseConnectionString.Trim();
            }

            //SQL Server
            if (model.DataProvider.Equals("sqlserver", StringComparison.InvariantCultureIgnoreCase))
            {
                if (model.SqlConnectionInfo.Equals("sqlconnectioninfo_raw", StringComparison.InvariantCultureIgnoreCase))
                {
                    //raw connection string
                    if (string.IsNullOrEmpty(model.DatabaseConnectionString))
                    {
                        UpdateResult(x => x.Errors.Add(_locService.GetResource("ConnectionStringRequired")));
                    }

                    try
                    {
                        //try to create connection string
                        new SqlConnectionStringBuilder(model.DatabaseConnectionString);
                    }
                    catch
                    {
                        UpdateResult(x => x.Errors.Add(_locService.GetResource("ConnectionStringWrongFormat")));
                    }
                }
                else
                {
                    //values
                    if (string.IsNullOrEmpty(model.SqlServerName))
                    {
                        UpdateResult(x => x.Errors.Add(_locService.GetResource("SqlServerNameRequired")));
                    }

                    if (string.IsNullOrEmpty(model.SqlDatabaseName))
                    {
                        UpdateResult(x => x.Errors.Add(_locService.GetResource("DatabaseNameRequired")));
                    }

                    //authentication type
                    if (model.SqlAuthenticationType.Equals("sqlauthentication", StringComparison.InvariantCultureIgnoreCase))
                    {
                        //SQL authentication
                        if (string.IsNullOrEmpty(model.SqlServerUsername))
                        {
                            UpdateResult(x => x.Errors.Add(_locService.GetResource("SqlServerUsernameRequired")));
                        }

                        if (string.IsNullOrEmpty(model.SqlServerPassword))
                        {
                            UpdateResult(x => x.Errors.Add(_locService.GetResource("SqlServerPasswordRequired")));
                        }
                    }
                }
            }


            //Consider granting access rights to the resource to the ASP.NET request identity.
            //ASP.NET has a base process identity
            //(typically {MACHINE}\ASPNET on IIS 5 or Network Service on IIS 6 and IIS 7,
            //and the configured application pool identity on IIS 7.5) that is used if the application is not impersonating.
            //If the application is impersonating via <identity impersonate="true"/>,
            //the identity will be the anonymous user (typically IUSR_MACHINENAME) or the authenticated request user.
            var webHelper = scope.Resolve <IWebHelper>();
            //validate permissions
            var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(webHelper);

            foreach (string dir in dirsToCheck)
            {
                if (!FilePermissionHelper.CheckPermissions(dir, false, true, true, false))
                {
                    UpdateResult(x => x.Errors.Add(string.Format(_locService.GetResource("ConfigureDirectoryPermissions"), WindowsIdentity.GetCurrent().Name, dir)));
                }
            }

            var filesToCheck = FilePermissionHelper.GetFilesWrite(webHelper);

            foreach (string file in filesToCheck)
            {
                if (!FilePermissionHelper.CheckPermissions(file, false, true, true, true))
                {
                    UpdateResult(x => x.Errors.Add(string.Format(_locService.GetResource("ConfigureFilePermissions"), WindowsIdentity.GetCurrent().Name, file)));
                }
            }

            if (GetInstallResult().HasErrors)
            {
                return(UpdateResult(x =>
                {
                    x.Completed = true;
                    x.Success = false;
                    x.RedirectUrl = null;
                }));
            }
            else
            {
                DefaultObjectContext dbContext = null;
                var shouldDeleteDbOnFailure    = false;

                try
                {
                    string connectionString = null;
                    if (model.DataProvider.Equals("sqlserver", StringComparison.InvariantCultureIgnoreCase))
                    {
                        //SQL Server

                        if (model.SqlConnectionInfo.Equals("sqlconnectioninfo_raw", StringComparison.InvariantCultureIgnoreCase))
                        {
                            //raw connection string

                            //we know that MARS option is required when using Entity Framework
                            //let's ensure that it's specified
                            var sqlCsb = new SqlConnectionStringBuilder(model.DatabaseConnectionString);
                            sqlCsb.MultipleActiveResultSets = true;
                            connectionString = sqlCsb.ToString();
                        }
                        else
                        {
                            //values
                            connectionString = CreateConnectionString(
                                model.SqlAuthenticationType == "windowsauthentication",
                                model.SqlServerName, model.SqlDatabaseName,
                                model.SqlServerUsername, model.SqlServerPassword);
                        }

                        if (model.SqlServerCreateDatabase)
                        {
                            if (!SqlServerDatabaseExists(connectionString))
                            {
                                //create database
                                var collation             = model.UseCustomCollation ? model.Collation : "";
                                var errorCreatingDatabase = CreateDatabase(connectionString, collation);
                                if (errorCreatingDatabase.HasValue())
                                {
                                    return(UpdateResult(x =>
                                    {
                                        x.Errors.Add(errorCreatingDatabase);
                                        x.Completed = true;
                                        x.Success = false;
                                        x.RedirectUrl = null;
                                    }));
                                }
                                else
                                {
                                    // Database cannot be created sometimes. Weird! Seems to be Entity Framework issue
                                    // that's just wait 3 seconds
                                    Thread.Sleep(3000);

                                    shouldDeleteDbOnFailure = true;
                                }
                            }
                        }
                        else
                        {
                            //check whether database exists
                            if (!SqlServerDatabaseExists(connectionString))
                            {
                                return(UpdateResult(x =>
                                {
                                    x.Errors.Add(_locService.GetResource("DatabaseNotExists"));
                                    x.Completed = true;
                                    x.Success = false;
                                    x.RedirectUrl = null;
                                }));
                            }
                        }
                    }
                    else
                    {
                        // SQL CE
                        string databaseFileName = "SmartStore.Db.sdf";
                        string databasePath     = @"|DataDirectory|\" + databaseFileName;
                        connectionString = "Data Source=" + databasePath + ";Persist Security Info=False";

                        // drop database if exists
                        string databaseFullPath = HostingEnvironment.MapPath("~/App_Data/") + databaseFileName;
                        if (System.IO.File.Exists(databaseFullPath))
                        {
                            System.IO.File.Delete(databaseFullPath);
                        }

                        shouldDeleteDbOnFailure = true;
                    }

                    // save settings
                    var dataProvider = model.DataProvider;
                    var settings     = DataSettings.Current;
                    settings.AppVersion           = WorkVersion.Version;
                    settings.DataProvider         = dataProvider;
                    settings.DataConnectionString = connectionString;
                    settings.Save();

                    // init data provider
                    var dataProviderInstance = scope.Resolve <IEfDataProvider>();

                    // Although obsolete we have no other chance than using this here.
                    // Delegating this to DbConfiguration is not possible during installation.
                                        #pragma warning disable 618
                    Database.DefaultConnectionFactory = dataProviderInstance.GetConnectionFactory();
                                        #pragma warning restore 618

                    // resolve SeedData instance from primary language
                    var lazyLanguage = _locService.GetAppLanguage(model.PrimaryLanguage);
                    if (lazyLanguage == null)
                    {
                        return(UpdateResult(x =>
                        {
                            x.Errors.Add(_locService.GetResource("Install.LanguageNotRegistered").FormatInvariant(model.PrimaryLanguage));
                            x.Completed = true;
                            x.Success = false;
                            x.RedirectUrl = null;
                        }));
                    }

                    // create the DataContext
                    dbContext = new DefaultObjectContext();

                    // IMPORTANT: Migration would run way too early otherwise
                    Database.SetInitializer <DefaultObjectContext>(null);

                    // create Language domain object from lazyLanguage
                    var languages       = dbContext.Set <Language>();
                    var primaryLanguage = languages.Create();                     // create a proxied type, resources cannot be saved otherwise
                    primaryLanguage.Name              = lazyLanguage.Metadata.Name;
                    primaryLanguage.LanguageCulture   = lazyLanguage.Metadata.Culture;
                    primaryLanguage.UniqueSeoCode     = lazyLanguage.Metadata.UniqueSeoCode;
                    primaryLanguage.FlagImageFileName = lazyLanguage.Metadata.FlagImageFileName;

                    // Build the seed configuration model
                    var seedConfiguration = new SeedDataConfiguration
                    {
                        DefaultUserName     = model.AdminEmail,
                        DefaultUserPassword = model.AdminPassword,
                        SeedSampleData      = model.InstallSampleData,
                        Data                    = lazyLanguage.Value,
                        Language                = primaryLanguage,
                        StoreMediaInDB          = model.MediaStorage == "db",
                        ProgressMessageCallback = msg => UpdateResult(x => x.ProgressMessage = _locService.GetResource(msg))
                    };

                    var seeder = new InstallDataSeeder(seedConfiguration);
                    Database.SetInitializer(new InstallDatabaseInitializer()
                    {
                        DataSeeders = new[] { seeder }
                    });

                    UpdateResult(x => x.ProgressMessage = _locService.GetResource("Progress.BuildingDatabase"));
                    // ===>>> actually performs the installation by calling "InstallDataSeeder.Seed()" internally
                    dbContext.Database.Initialize(true);

                    // install plugins
                    PluginManager.MarkAllPluginsAsUninstalled();
                    var pluginFinder = scope.Resolve <IPluginFinder>();
                    var plugins      = pluginFinder.GetPlugins <IPlugin>(false)
                                       //.ToList()
                                       .OrderBy(x => x.PluginDescriptor.Group)
                                       .ThenBy(x => x.PluginDescriptor.DisplayOrder)
                                       .ToList();

                    var ignoredPluginsSetting            = CommonHelper.GetAppSetting <string>("sm:PluginsIgnoredDuringInstallation");
                    var pluginsIgnoredDuringInstallation = String.IsNullOrEmpty(ignoredPluginsSetting) ?
                                                           new List <string>() :
                                                           ignoredPluginsSetting
                                                           .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                                           .Select(x => x.Trim())
                                                           .ToList();

                    if (pluginsIgnoredDuringInstallation.Count > 0)
                    {
                        plugins = plugins.Where(x => !pluginsIgnoredDuringInstallation.Contains(x.PluginDescriptor.SystemName, StringComparer.OrdinalIgnoreCase)).ToList();
                    }

                    var pluginsCount = plugins.Count;
                    var idx          = 0;

                    using (var dbScope = new DbContextScope(autoDetectChanges: false, hooksEnabled: false)) {
                        foreach (var plugin in plugins)
                        {
                            try
                            {
                                idx++;
                                UpdateResult(x => x.ProgressMessage = _locService.GetResource("Progress.InstallingPlugins").FormatInvariant(idx, pluginsCount));
                                plugin.Install();
                                dbScope.Commit();
                            }
                            catch
                            {
                                if (plugin.PluginDescriptor.Installed)
                                {
                                    PluginManager.MarkPluginAsUninstalled(plugin.PluginDescriptor.SystemName);
                                }
                            }
                        }
                    }

                    UpdateResult(x => x.ProgressMessage = _locService.GetResource("Progress.Finalizing"));

                    // Register default permissions
                    var permissionProviders = new List <Type>();
                    permissionProviders.Add(typeof(StandardPermissionProvider));
                    foreach (var providerType in permissionProviders)
                    {
                        dynamic provider = Activator.CreateInstance(providerType);
                        scope.Resolve <IPermissionService>().InstallPermissions(provider);
                    }

                    // SUCCESS: Redirect to home page
                    return(UpdateResult(x =>
                    {
                        x.Completed = true;
                        x.Success = true;
                        x.RedirectUrl = Url.Action("Index", "Home");
                    }));
                }
                catch (Exception exception)
                {
                    // Clear provider settings if something got wrong
                    DataSettings.Delete();

                    // Delete Db if it was auto generated
                    if (dbContext != null && shouldDeleteDbOnFailure)
                    {
                        try
                        {
                            dbContext.Database.Delete();
                        }
                        catch { }
                    }

                    var msg           = exception.Message;
                    var realException = exception;
                    while (realException.InnerException != null)
                    {
                        realException = realException.InnerException;
                    }

                    if (!Object.Equals(exception, realException))
                    {
                        msg += " (" + realException.Message + ")";
                    }

                    return(UpdateResult(x =>
                    {
                        x.Errors.Add(string.Format(_locService.GetResource("SetupFailed"), msg));
                        x.Success = false;
                        x.Completed = true;
                        x.RedirectUrl = null;
                    }));
                }
                finally
                {
                    if (dbContext != null)
                    {
                        dbContext.Dispose();
                    }
                }
            }
        }