Angenommen, ich erstelle eine App namens ConsoleApp2 .
Aufgrund einiger Bibliotheken von Drittanbietern, die ich verwende, generiert meine Standarddatei app.config Code wie
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Das liegt daran, dass meine Lösung auf verschiedene Versionen einer Bibliothek verweist. Daher muss sie allen mitteilen: " Hey, wenn Sie nach einer alten Version dieser Bibliothek suchen , verwenden Sie einfach newVersion. " Und das ist in Ordnung.
Das Problem ist, dass ich eine separate Konfigurationsdatei "test.exe.config" definieren möchte, in der ich einige Einstellungen habe und die automatisch generierte entfernen möchte.
Um meine App über die neue Konfigurationsdatei zu informieren, verwende ich Code wie
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");
Und das funktioniert (fast) perfekt. Und ich habe dort " fast " geschrieben, da der <appSettings>
Abschnitt zwar korrekt gelesen wird, der <runtime>
Abschnitt jedoch nicht in meiner benutzerdefinierten Konfigurationsdatei angezeigt wird, sondern die App ihn stattdessen in der Standardkonfigurationsdatei sucht, was ein Problem ist, da ich dies möchte in der Lage sein, diese später zu löschen.
Wie kann ich meine Anwendung anweisen, auch die <runtime>
Informationen aus meiner benutzerdefinierten Konfigurationsdatei zu lesen ?
So reproduzieren Sie das Problem
Ein einfaches Beispiel zur Reproduktion meines Problems lautet wie folgt:
Erstellen Sie eine Bibliothek mit dem Namen ClassLibrary2 ( .Net Framework v4.6 ) mit einer einzelnen Klasse wie folgt
using Newtonsoft.Json.Linq;
using System;
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
var json = new JObject();
json.Add("Succeed?", true);
Reash = json.ToString();
}
public String Reash { get; set; }
}
}
Beachten Sie den Verweis auf das Newtonsoft- Paket. Die in der Bibliothek installierte Version ist 10.0.2 .
Erstellen Sie nun eine Konsolenanwendung mit dem Namen ConsoleApp2 ( .Net Framework v4.6 ) mit einer Klasse namens Program, deren Inhalt einfach wie folgt lautet:
using System;
using System.Configuration;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");
var AppSettings = ConfigurationManager.AppSettings;
Console.WriteLine($"{AppSettings.Count} settings found");
Console.WriteLine($"Calling ClassLibrary2: {Environment.NewLine}{new ClassLibrary2.Class1().Reash}");
Console.ReadLine();
}
}
}
Diese Anwendung sollte auch Newtonsoft installiert haben , jedoch in einer anderen Version v12.0.3 .
Erstellen Sie die Anwendung im Debug-Modus. Erstellen Sie dann im Ordner ConsoleApp2 / ConsoleApp2 / bin / Debug eine Datei mit dem Namen test.exe.config mit folgendem Inhalt
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<appSettings>
<add key="A" value="1"/>
<add key="B" value="1"/>
<add key="C" value="1"/>
</appSettings>
</configuration>
und beachten Sie, dass sich in demselben Debug- Ordner auch die Standardkonfigurationsdatei ConsoleApp2.exe.config mit einem Inhalt wie befindet
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Wenn Sie die Anwendung an diesem Punkt ausführen, wird sie problemlos kompiliert, und Sie sollten eine Konsole wie diese sehen
Beachten Sie, dass die (3) Einstellungen korrekt aus meiner benutzerdefinierten Konfigurationsdatei gelesen wurden. So weit, ist es gut...
Benennen Sie nun die Standardkonfigurationsdatei in _ConsoleApp2.exe.config um und führen Sie die Anwendung erneut aus. Sie sollten jetzt eine FileLoadException erhalten .
Wie kann ich meine Anwendung anweisen, die <runtime>
Informationen aus meiner benutzerdefinierten Konfigurationsdatei zu lesen ?
Begründung
Der Grund, warum ich eine Antwort auf diese Frage suche, ist folgender:
Wenn wir unsere Anwendung freigeben, legen wir alle EXE- und DLL-Dateien in einem Ordner und unsere benutzerdefinierte Konfigurationsdatei (mit Einstellungen usw.) in einem anderen Ordner ab, in dem unsere Clients ähnliche Dateien haben.
In dem Ordner mit den EXE- und DLL-Dateien versuchen wir, so wenig wie möglich zu behalten, daher wurde ich gebeten, einen Weg zu finden, um diese ConsoleApp2.exe.config nach Möglichkeit zu entfernen . Da die oben genannten Bindungen in diese Konfigurationsdatei geschrieben wurden, habe ich nur versucht, diese Informationen in unsere benutzerdefinierte Konfigurationsdatei zu verschieben ... aber bisher habe ich es nicht geschafft: Die Bindungsumleitungen werden immer versucht, von dieser ConsoleApp2.exe gelesen zu werden .config , sobald ich es entferne, bekomme ich Ausnahmen ...
quelle
<runtime>
Abschnitt aus einer anderen Konfiguration anzuwenden , aber das Problem tritt aufgrund der Art und Weise auf, wie Sie die allgemeine Konfiguration verwalten. Wenn Sie die allgemeine Konfiguration auf andere Weise verwalten, ist dieses Problem nicht mehr relevant. Bitte überprüfen Sie meine Antwort und ziehen Sie in Betracht, Konfigurationstransformationen zu verwenden, anstatt die Laufzeit zu optimieren.Antworten:
Sie suchen wahrscheinlich nach Konfigurationsumwandlungen :
Die Idee dahinter ist, dass Sie in Visual Studio mehrere Konfigurationen wie Debug, Release, Production, Test ... im Konfigurationsmanager und eine Standardkonfigurationsdatei sowie sogenannte Transformationen erstellen.
Beachten Sie, dass Sie im Konfigurationsmanager so viele Konfigurationen erstellen können, wie Sie möchten. Um neue hinzuzufügen, klicken Sie auf Lösungskonfigurationen (die Dropdown-Liste zeigt "Debug" oder "Release") und wählen Sie "Configuration Manager ...". Öffnen Sie es und Sie sehen eine Liste aller derzeit vorhandenen Konfigurationen. Lassen Sie das Kombinationsfeld "Active Solution-Konfiguration" fallen und wählen Sie "
<New...>
", um weitere hinzuzufügen.Diese Transformationen geben an, was die spezifische Konfiguration von der Standardkonfiguration unterscheidet. Sie müssen also nicht wiederholen, was Sie bereits in der Standardkonfiguration angegeben haben. Stattdessen erwähnen Sie nur die Unterschiede, zum Beispiel:
Hiermit wird die relevante Einstellung anhand des Schlüssels ermittelt
ClientSessionTimeout
und der Wert100
durch Ersetzen des ursprünglichen Werts in der Konfigurationsdatei festgelegt (diesxdt:Transform="SetAttributes" xdt:Locator="Match(key)"
bedeuten die zusätzlichen Transformationsattribute ). Sie können auch festlegen, dass vorhandene Einstellungen entfernt werden sollen (indem Siexdt:Transform="Remove"
stattdessen angeben ), zwürde eine Benutzer-ID entfernen, die nur zum Debuggen und nicht für die Version vorhanden sein sollte (Weitere Informationen zu verfügbaren Optionen finden Sie hier - beschrieben für Web.config, aber auch für App.config).
Zusätzlich zu der
App.Config
Datei haben Sie eine Datei pro Konfiguration, dhApp.Debug.Config
für Debug,App.Release.Config
Release usw. Visual Studio hilft Ihnen beim Erstellen.Ich habe hier und da bereits Antworten in StackOverflow erstellt , die es ausführlich beschreiben. Bitte schauen Sie.
Wenn Sie Probleme beim Anzeigen in Visual Studio haben, sehen Sie hier nach .
In Bezug auf Ihre Begründung :
Transformationen erstellen eine vollständige Konfigurationsdatei, indem die Transformationsdatei auf die Standardkonfigurationsdatei angewendet wird. Die resultierende Datei wird kompiliert und zusammen mit den anderen kompilierten Dateien in den Ordner "bin" gestellt. Wenn Sie also die Konfiguration "Release" ausgewählt haben, werden alle Dateien einschließlich der transformierten Konfigurationsdatei in "bin \ Release" kompiliert.
Und die Konfigurationsdatei wird genauso benannt wie die exe-Datei plus ".config" am Ende angehängt (mit anderen Worten, es gibt keine ".Release.config" im Binärordner, sondern eine "MySuperCoolApp.exe.config" erstellt - für die Anwendung "MySuperCoolApp.exe").
Gleiches gilt auch für die andere Konfiguration - jede Konfiguration erstellt einen Unterordner innerhalb von "bin" -. Wenn Sie Skripts verwenden, kann auf diesen Unterordner wie
$(TargetDir)
in einem Post-Build-Ereignis verwiesen werden .quelle
Konfiguration konfigurieren
Angesichts des Problems, das auftritt, wenn Sie versuchen, eine andere (nicht native) Konfigurationsdatei zu verwenden, versuchen Sie, eine Lösung zu finden, um diese ordnungsgemäß zu ersetzen. In meiner Antwort möchte ich ein wenig zurücktreten und mich auf den Grund konzentrieren, warum Sie ihn ersetzen möchten. Basierend auf dem, was Sie in der Frage beschrieben haben, müssen Sie benutzerdefinierte Anwendungseinstellungen definieren. Wenn ich es richtig verstanden habe, planen Sie, es mit dem Zielprojekt zu verknüpfen. Setzen Sie die Eigenschaft "In Ausgabe kopieren" auf "Immer" und Sie erhalten es in der Nähe der Anwendung.
Anstatt die neue Konfigurationsdatei zu kopieren, gibt es in Ihrem Fall eine Möglichkeit, vorhandene (native) zu transformieren -
ConsoleApp2.exe.config
mithilfe von Xdt-Transformationen . Um dies zu erreichen, erstellen Sie eine Transformationsdatei und deklarieren dort nur die Abschnitte, die Sie transformieren möchten, zum Beispiel:Vorteile eines solchen Ansatzes sind:
Der einzige Nachteil dieses Ansatzes ist die Lernkurve: Sie müssen die Syntax lernen und wissen, wie Sie Transformationen in Ihre Konfigurationen in MSBuild kleben.
.NET Core unterstützt die Transformation. Hier ist ein Beispiel zum Erstellen von Transformationen für web.config. Sie können jedoch Transformationen auf alle Konfigurationen anwenden.
Wenn Sie .NET-Anwendungen (nicht .NET Core) entwickeln, würde ich empfehlen, sich Slowcheetah anzusehen .
Es gibt viele Ressourcen und nützliche Blogbosts über Transformation, es ist ziemlich weit verbreitet. Bitte kontaktieren Sie mich, wenn Sie Schwierigkeiten haben.
Aus meiner Sicht ist config transforms eine richtige Lösung, um Ihr Ziel zu erreichen. Ich würde daher dringend empfehlen, dies in Betracht zu ziehen, anstatt die Laufzeit zu optimieren.
Externalisieren Sie Konfigurationsabschnitte
Wenn Sie appSettings weiterhin am gemeinsamen Speicherort behalten möchten, können Sie Konfigurationsabschnitte mit dem ConfigSource- Attribut externalisieren . Überprüfen Sie dies und diesen Thread für Details:
Der Abschnitt AppSettings enthält das Attribut Datei , mit dem Sie Parameter aus einer anderen Datei zusammenführen können.
Mit dieser Option können Sie bestimmte Abschnitte der Konfiguration ersetzen, jedoch nicht den gesamten Inhalt. Wenn Sie also nur appSettings benötigen, ist dies völlig zutreffend. Sie legen einfach die Konfigurationsdatei mit appSettings an einem gemeinsamen Speicherort ab, der für Benutzer und Patch-Konfigurationsdatei (Hinzufügen
file
oderconfigSource
Attribut) freigegeben ist, um diesen Abschnitt von diesem Speicherort aus zu beziehen . Wenn Sie weitere Abschnitte benötigen, müssen Sie diese als separate Dateien extrahieren.quelle
Um ordnungsgemäß mit anderen
.config
Dateien zu arbeiten, können Sie die Standarddatei zum Verwalten von Biding-Weiterleitungen und eine andere für Ihre Anwendungsparameter beibehalten. Um dies zu tun Standard ändern app.config zur Laufzeit sieht gut aus .Sie können auch die automatische Generierung der Bindungsumleitung herunterfahren und nur eine handgefertigte Datei app.config verwenden. Hier ist ein Beispiel: Benötigen Sie eine Möglichkeit, auf zwei verschiedene Versionen derselben DLL eines Drittanbieters zu verweisen
Bearbeiten Unter Berücksichtigung der Gründe: Wenn ich es verstehe, möchten Sie die Datei app.exe.config überhaupt nicht. Sie schaffen es bereits, benutzerdefinierte Contants an einer anderen Stelle abzulegen und zu lesen.
Es bleibt nur die verbindliche Weiterleitung.
Sie können es entfernen, indem Sie die Bindungsumleitung zur Laufzeit wie hier beschrieben verwalten: https://stackoverflow.com/a/32698357/361177 Sie können auch einen konfigurierbaren Bindungsauflöser neu erstellen, indem Sie Ihren Code in der Konfigurationsdatei anzeigen lassen.
Meine zwei Cent hier: Es ist machbar, aber ich denke nicht, dass es das wert ist.
Bearbeiten 2 Diese Lösung sieht vielversprechend aus https://stackoverflow.com/a/28500477/361177
quelle
AppDomain.CurrentDomain.AssemblyResolve
Ereignis registrieren und diese Methode veranlassen, die Bindungsregeln aus der Konfigurationsdatei abzurufen.