ApplicationSettingsBase.Upgrade() не обновляет настройки пользователя после перекомпиляции с .NET 4.0

У меня есть программа на С#, которая использует стандартный ApplicationSettingsBase для сохранения своих пользовательских настроек. Это отлично работает в .NET 3.5. И предоставленный метод Upgrade() правильно "перезагрузил" эти настройки всякий раз, когда была создана новая версия моей программы.

Недавно я перекомпилировал программу с .NET 4.0. Мой номер версии программы также увеличился. Но, когда я запускаю эту версию, Upgrade(), похоже, не обнаруживает никаких параметров предыдущей версии и не "перезагружает" их. Он начинает пустым.

В качестве теста я снова перекомпилировал, вернувшись к .NET 3.5. И на этот раз метод Upgrade() снова начал работать.

Есть ли способ разрешить Upgrade() работать при переключении фреймворков? Есть ли что-то еще, что мне не хватает?

Ответ 1

У меня была точно такая же проблема, и я снова несколько раз тестировал это из .NET 3.5, переработанного в .NET 4.0.

К сожалению, мое решение находится в vb.net, но я уверен, что вы можете использовать одну из многих программ преобразования, чтобы увидеть это в С#, например http://www.developerfusion.com/tools/convert/vb-to-csharp/

Он включает перечисление через все папки в % AppData%\CompanyName, чтобы найти последний файл user.config в имени папки версии, которую вы хотите обновить с.

Я обнаружил, что перекомпиляция моего приложения в .NET 4.0 в Visual Studio 2010 создаст новую папку с именем % AppData%\CompanyName\AppName.exe_Url_blahbahblah, хотя я не изменил абсолютно никаких других настроек или код вообще!

Все мои предыдущие выпуски до .NET 4.0 сохраняли одно и то же имя папки и успешно обновлялись. Копирование старого файла user.config(и имени папки версии) из старой папки в новую структуру папок, созданную под .NET 4.0 (с именем старой версии), устраняет проблему - теперь она будет обновлена.

В этом примере предполагается, что у вас есть пользовательский параметр с именем IUpgraded, который по умолчанию установлен на False (а позже установлен на True), чтобы проверить, не являются ли начальные настройки defalt или нет - вы можете использовать любую другую переменную, которую вы создали. В этом примере показано обновление с версии 1.2.0.0 до более позднего, которое вы можете изменить, изменив значение lastVersion.

Код должен быть размещен в верхней части формы. Загрузить событие последней версии (.NET 4.0):

Imports System
Imports System.IO

If Not My.Settings.IUpgraded Then 'Upgrade application settings from previous version
    My.Settings.Upgrade()
    'The following routine is only relevant upgrading version 1.2.0.0
    If Not My.Settings.IUpgraded Then 'enumerate AppData folder to find previous versions
        Dim lastVersion As String = "1.2.0.0" 'version to upgrade settings from
        Dim config_initial As System.Configuration.Configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal)
        Dim fpath As String = config_initial.FilePath
        For x = 1 To 3 'recurse backwards to find root CompanyName folder
            fpath = fpath.Substring(0, InStrRev(fpath, "\", Len(fpath) - 1))
        Next
        fpath = fpath.Substring(0, Len(fpath) - 1) 'remove trailing backslash
        Dim latestConfig As FileInfo 'If not set then no previous info found
        Dim di As DirectoryInfo = New DirectoryInfo(fpath)
        If di.Exists Then
            For Each diSubDir As DirectoryInfo In di.GetDirectories(lastVersion, SearchOption.AllDirectories)
                If InStr(diSubDir.FullName, ".vshost") = 0 Then 'don't find VS runtime copies
                    Dim files() As FileInfo = diSubDir.GetFiles("user.config", SearchOption.TopDirectoryOnly)
                    For Each File As FileInfo In files
                        Try
                            If File.LastWriteTime > latestConfig.LastWriteTime Then
                                latestConfig = File
                            End If
                        Catch
                            latestConfig = File
                        End Try
                    Next
                End If
            Next
        End If
        Try
            If latestConfig.Exists Then
                Dim newPath As String = config_initial.FilePath
                newPath = newPath.Substring(0, InStrRev(newPath, "\", Len(newPath) - 1))
                newPath = newPath.Substring(0, InStrRev(newPath, "\", Len(newPath) - 1))
                newPath &= lastVersion
                If Directory.Exists(newPath) = False Then
                    Directory.CreateDirectory(newPath)
                End If
                latestConfig.CopyTo(newPath & "\user.config")
                My.Settings.Upgrade() 'Try upgrading again now old user.config exists in correct place
            End If
        Catch : End Try
    End If
    My.Settings.IUpgraded = True 'Always set this to avoid potential upgrade loop
    My.Settings.Save()
End If

Ответ 2

Вот код.

public static class SettingsUpdate
{
    public static void Update()
    {
        try
        {
            var a = Assembly.GetExecutingAssembly();

            string appVersionString = a.GetName().Version.ToString();

            if( UserSettings.Default.internalApplicationVersion != appVersionString )
            {
                var currentConfig = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
                var exeName = "MyApplication.exe";
                var companyFolder = new DirectoryInfo( currentConfig.FilePath ).Parent.Parent.Parent;

                FileInfo latestConfig = null;

                foreach( var diSubDir in companyFolder.GetDirectories( "*" + exeName + "*", SearchOption.AllDirectories ) )
                {
                    foreach( var file in diSubDir.GetFiles( "user.config", SearchOption.AllDirectories ) )
                    {
                        if( latestConfig == null || file.LastWriteTime > latestConfig.LastWriteTime )
                        {
                            latestConfig = file;
                        }
                    }
                }

                if( latestConfig != null )
                {
                    var lastestConfigDirectoryName = Path.GetFileName( Path.GetDirectoryName( latestConfig.FullName ) );

                    var latestVersion = new Version( lastestConfigDirectoryName );
                    var lastFramework35Version = new Version( "4.0.4605.25401" );

                    if( latestVersion <= lastFramework35Version )
                    {
                        var destinationFile = Path.GetDirectoryName( Path.GetDirectoryName( currentConfig.FilePath ) );
                        destinationFile = Path.Combine( destinationFile, lastestConfigDirectoryName );

                        if( !Directory.Exists( destinationFile ) )
                        {
                            Directory.CreateDirectory( destinationFile );
                        }

                        destinationFile = Path.Combine( destinationFile, latestConfig.Name );

                        File.Copy( latestConfig.FullName, destinationFile );
                    }
                }

                Properties.Settings.Default.Upgrade();
                UserSettings.Default.Upgrade();
                UserSettings.Default.internalApplicationVersion = appVersionString;
                UserSettings.Default.Save();
            }
        }
        catch( Exception ex )
        {
            LogManager.WriteExceptionReport( ex );
        }
    }
}

Пусть это поможет вам:)

Ответ 3

Если Settings1.Upgrade() работает не так, как вы ожидали, может попытаться удалить предыдущие файлы конфигурации пользователя и повторить попытку.

В моем случае версии Release и Debug не соответствуют друг другу, тогда обновление, по-видимому, завершится неудачно, поскольку существует конфликт между версиями в одном каталоге, связанный с выходными данными отладки/выпуска.

Очистка всех предыдущих пользовательских конфигурационных файлов (appdata\local....), кажется, решает проблему, вызов Upgrade() работает, и предложенный здесь обходной путь работает.

Я надеюсь, что это работает для вас.