Kann ich den Speicherort der .NET-Benutzereinstellungen steuern, um zu vermeiden, dass Einstellungen beim Anwendungsupgrade verloren gehen?

104

Ich versuche, den Speicherort der user.configDatei anzupassen . Derzeit ist es mit einem Hash und einer Versionsnummer gespeichert

%AppData%\[CompanyName]\[ExeName]_Url_[some_hash]\[Version]\

Ich möchte, dass es für die Version der Anwendung agnostisch ist

%AppData%\[CompanyName]\[ProductName]\

Kann das gemacht werden und wie? Was sind die Auswirkungen? Verliert der Benutzer nach dem Upgrade seine Einstellungen aus der vorherigen Version?

Muxa
quelle
Während die Antwort von uzbones in Bezug auf den Speicherort der Datei informativ ist, glaube ich, dass die von Ian in Bezug auf das Upgrade korrekter ist.
Anthony Mastrean
4
@AnthonyMastrean Ich persönlich denke, dass wichtige Einstellungen nicht von der ApplicationSettings- Infrastruktur abhängen sollten, die mein Microsoft bereitgestellt hat. Muxa sollte Einstellungen nur dort speichern, %AppData%\[CompanyName]/[ProductName]wo wir darauf vertrauen können, dass sie erhalten bleiben.
Ian Boyd
2
Zweifellos war meine fortgesetzte Erfahrung mit der integrierten Anwendung und den Benutzereinstellungen schrecklich. Ich empfehle JSON-Dateien in App- oder Programmdaten.
Anthony Mastrean
Sie können Ihre Einstellungen auch in einer Registrierung speichern. Informationen zur Implementierung alternativer Einstellungsklassen finden Sie unter stackoverflow.com/a/12127888/1273550 .
Ravi Patel

Antworten:

39

Um die erste Frage zu beantworten, können Sie die Datei technisch an einer beliebigen Stelle ablegen. Sie müssen sie jedoch selbst codieren, da der Standardspeicherort der Datei das erste Ihrer beiden Beispiele ist. ( Link, wie man es selbst macht )

Die zweite Frage hängt davon ab, wie Sie die Anwendung bereitstellen. Wenn Sie über eine MSI-Datei bereitstellen, gibt es zwei Hashes in den Eigenschaften des Setup-Projekts (aus dem die MSI erstellt wurde), den 'Upgrade-Code' und den 'Produktcode'. Diese bestimmen, wie die MSI installiert werden kann und ob sie neben einer anderen Version derselben Anwendung aktualisiert, überschrieben oder installiert wird.

Wenn Sie beispielsweise zwei Versionen Ihrer Software haben und diese unterschiedliche Upgrade-Codes haben, handelt es sich bei Windows um völlig unterschiedliche Softwareteile, unabhängig vom Namen. Wenn der 'Upgrade'-Code derselbe ist, der' Produkt'-Code jedoch anders ist, werden Sie beim Versuch, die 2. msi zu installieren, gefragt, ob Sie ein Upgrade durchführen möchten. Zu diesem Zeitpunkt sollen die Werte aus dem Code kopiert werden alte Konfiguration zu einer neuen Konfiguration. Wenn beide Werte gleich sind und sich die Versionsnummer nicht geändert hat, befindet sich die neue Konfiguration am selben Speicherort wie die alte Konfiguration und muss nichts tun. MSDN-Dokumentation

ClickOnce ist ein bisschen anders, da es mehr auf der ClickOnce-Versionsnummer und dem URL-Pfad basiert. Ich habe jedoch festgestellt, dass die neue Version der Anwendung weiterhin die Datei verwendet, solange Sie weiterhin am selben Speicherort veröffentlichen vorhandene Konfiguration. ( Link zum Umgang von ClickOnce mit Updates )

Ich weiß auch, dass es eine Möglichkeit gibt, Konfigurationen während der Installation der MSI mithilfe von benutzerdefinierten Installationsskripten manuell zusammenzuführen, aber ich erinnere mich nicht an die genauen Schritte, um dies zu tun ... (siehe diesen Link für die Vorgehensweise mit einem Web. config)

Uzbones
quelle
Ist der Upgrade-Code nicht derjenige, der konstant bleiben soll, und der Produktcode derjenige, der sich zwischen den Versionen ändern soll? blogs.msdn.com/b/pusu/archive/2009/06/10/understanding-msi.aspx
estanford
Doh! Sie haben Recht, ich kann nicht glauben, dass ich das rückwärts bekommen habe (und es hat 2 Jahre gedauert, um es zu fangen). Es war, als würde ich irgendwann in meiner Vergangenheit eine Weile Robo-signieren :(
uzbones
Bedeutet das, dass nur die installierende Benutzerin ihre Einstellungen aktualisiert bekommt?
Micha Wiedenmann
79

Ich wollte diesen zitierten Text als Referenz hinzufügen, wenn ich dieses Problem in Zukunft habe. Angeblich können Sie die ApplicationSettings-Infrastruktur anweisen, Einstellungen aus einer früheren Version zu kopieren, indem Sie Upgrade aufrufen :

Properties.Settings.Value.Upgrade();

Aus dem FAQ- Blogbeitrag zu den Kundeneinstellungen: ( Archiv )

F: Warum enthält der Pfad user.config eine Versionsnummer? Wenn ich eine neue Version meiner Anwendung bereitstelle, verliert der Benutzer dann nicht alle Einstellungen, die in der vorherigen Version gespeichert wurden?

A: Es gibt mehrere Gründe, warum der Pfad user.config versionierungsabhängig ist.

(1) Um die parallele Bereitstellung verschiedener Versionen einer Anwendung zu unterstützen (Sie können dies beispielsweise mit Clickonce tun). Es ist möglich, dass für verschiedene Versionen der Anwendung unterschiedliche Einstellungen gespeichert werden.

(2) Wenn Sie eine Anwendung aktualisieren, wurde die Einstellungsklasse möglicherweise geändert und ist möglicherweise nicht mit den gespeicherten Daten kompatibel, was zu Problemen führen kann.

Wir haben es jedoch einfach gemacht, Einstellungen von einer früheren Version der Anwendung auf die neueste Version zu aktualisieren. Rufen Sie einfach ApplicationSettingsBase.Upgrade () auf, um Einstellungen aus der vorherigen Version abzurufen, die mit der aktuellen Version der Klasse übereinstimmen, und speichern Sie sie in der Datei user.config der aktuellen Version. Sie haben auch die Möglichkeit, dieses Verhalten entweder in Ihrer Einstellungsklasse oder in Ihrer Provider-Implementierung zu überschreiben.

F: Okay, aber woher weiß ich, wann ich Upgrade anrufen soll?

A: Gute Frage. Wenn Sie in Clickonce eine neue Version Ihrer Anwendung installieren, erkennt ApplicationSettingsBase diese und aktualisiert die Einstellungen für Sie automatisch, sobald die Einstellungen geladen sind. In Fällen ohne Clickonce gibt es kein automatisches Upgrade - Sie müssen Upgrade selbst aufrufen. Hier ist eine Idee, um zu bestimmen, wann Upgrade aufgerufen werden soll:

Haben Sie eine boolesche Einstellung namens CallUpgrade und geben Sie den Standardwert true an. Wenn Ihre App gestartet wird, können Sie Folgendes tun:

if (Properties.Settings.Value.CallUpgrade)
{
   Properties.Settings.Value.Upgrade();
   Properties.Settings.Value.CallUpgrade = false;    
}

Dadurch wird sichergestellt, dass Upgrade () nur beim ersten Ausführen der Anwendung nach der Bereitstellung einer neuen Version aufgerufen wird.

Ich glaube keine Sekunde lang, dass es tatsächlich funktionieren könnte - Microsoft würde diese Fähigkeit auf keinen Fall bereitstellen, aber die Methode ist genauso.

Ian Boyd
quelle
3
DAS FUNKTIONIERT VOLLSTÄNDIG! Ich habe nur die einfache if(CallUpgrade) { Upgrade(); }Aussage verwendet.
Anthony Mastrean
@ Ian Boyd: Ich mag diese Idee und bin total begeistert von einer möglichen Lösung, aber ich bin verwirrt über eine Sache. Ich habe kein Properties.Settings.Value Ich habe das Properties.SettingsTeil, aber vermisse ich etwas oder ist das spezifisch für dich?
Refracted Paladin
8
Dies funktioniert gut, aber ich erinnere die Leser daran, dass der Pfad der Konfiguration bis einschließlich der Versionsnummer identisch sein muss. dh siehe @ Amrs Antwort. Wenn beispielsweise eine neue Version der App über einen anderen Dateipfad als eine frühere Version gestartet wird, Upgradefunktioniert dies nicht.
Stephen Swensen
1
@ RefractedPaladin es istProperties.Settings.Default.Upgrade()
Stephen Swensen
5
Vergessen Sie nicht, Properties.Settings.Default.Save();nach dem Ändern in false hinzuzufügen :-)
Jeff
32

Die Datei user.config wird unter gespeichert

c:\Documents and Settings>\<username>\[Local Settings\]Application Data\<companyname>\<appdomainname>_<eid>_<hash>\<verison>

<c:\Documents and Settings>ist das Benutzerdatenverzeichnis, entweder ohne Roaming (lokale Einstellungen oben) oder als Roaming.
<username>ist der Benutzername.
<companyname>ist der CompanyNameAttribute-Wert, falls verfügbar. Andernfalls ignorieren Sie dieses Element.
<appdomainname>ist der AppDomain.CurrentDomain.FriendlyName. Dies ist normalerweise der Standardname .exe.
<eid>ist die URL, der starke Name oder der Pfad, basierend auf den für den Hash verfügbaren Beweisen.
<hash>ist ein SHA1-Hash von Beweisen, die aus der CurrentDomain in der folgenden bevorzugten Reihenfolge gesammelt wurden:
1. StrongName
2. URL:
Wenn keines davon verfügbar ist, verwenden Sie den EXE-Pfad.
<version>ist die AssemblyVersionAttribute-Einstellung von AssemblyInfo.

Die vollständige Beschreibung finden Sie hier http://msdn.microsoft.com/en-us/library/ms379611.aspx

Amr
quelle
4

(Ich würde dies als Kommentar zu @ Amrs Antwort hinzufügen, aber ich habe noch nicht genug Repräsentanten, um das zu tun.)

Die Informationen im MSDN-Artikel sind sehr klar und scheinen weiterhin zu gelten. Es wird jedoch nicht erwähnt, dass der SHA1-Hash eher als Basis 32 codiert als als die typischere Basis 16 ausgeschrieben ist.

Ich glaube, der verwendete Algorithmus ist in implementiert ToBase32StringSuitableForDirName, der hier in der Microsoft-Referenzquelle zu finden ist .

JulianRendell
quelle