Hallo Allerseits,
ich möchte gerne ein Verzeichnis erstellen z.B. "C:\C#_DLLs" in dem alle meine Standardbibliotheken liegen (DruckDLL, EMailDLL usw.). Alle "Released"-Programme sollen die benötigten Bibliotheken in diesem Verzeichnis suchen und natürlich auch finden.
Die System-Path - Variable habe ich schon gesetzt.
Wenn ich jetzt mit VS2015 die Release-Version erstelle z.B. in C:\MeinProgramm\ liegt dort die EXE und auch meine Referenz-DLLs. Die DLLs sollen aber im obigen Verzeichnis liegen. Wenn ich manuell die DLLs umkopiere/verschiebe, startet das Programm nicht mehr.
Leider finde ich dazu keine rechte Anleitung. Es ist bestimmt ganz einfach.
Danke schonmal für evtl. Hilfe
Hallo,
mehrere Möglichkeiten:
GAC
Du kannst Deine DLLs statt in einen eigenen Ordner, in den GAC installieren. Dann werden sie von jeder .NET-Anwendung gefunden.
Referenzen anpassen
Stell Deine DLL-Projekte so ein, dass sie direkt in Deinen Zielpfad bauen, oder kopiere diese von Hand dahin. Passe dann in dem Projekt, das die DLLs verwenden soll, die Referenzen (im Eigenschaftenfenster) so an, dass nicht mehr die Projekte, sondern die DLLs direkt verwiesen werden, und dass "Copy local" auf false steht. Dann müsste die DLL immer in diesem Verzeichnis gesucht werden.
AppDomain.AssemblyResolve
Du kannst mit den Anwendungen, die die DLLs nutzen sollen, das AppDomain.AssemblyResolve-Ereignis abonnieren und dort den gewünschten Pfad selbst auflösen.
Bei all diesen Möglichkeiten bedenke aber Folgendes:
Wenn Du die DLLs an einem zentralen Ort ablegst, bekommst Du ein Problem, wenn Du in einer der gemeinsam genutzten DLLs einen "Breaking Change" machst, müssen ggf. alle Anwendungen aktualisiert werden. Wenn Du wie bisher mit lokalen Kopien der DLLs arbeiuest, bekommst Du dieses Problem nicht.
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
@MarsStein:
Schritt 2 werde ich mal probieren. Das klingt nach dem was ich suche.
@p!lle:
Mein Ziel: Ich habe einen Haufen kleine Progrämmchen, die Prozesse vereinfachen sollen. Jedes Programm nutzt dabei immer meine DruckDLL oder meine AdressDLL usw. Diese DLLs werden eigentlich nie geändert und wenn, bin ich mir bewusst, das alle Programme neu kompiliert werden müssen.
a) aus Platzgründen muss nicht in jedem Programmverzeichnis die DLL stehen, die sowieso jedes Programm benutzt.
b) der Übersicht halber. Ziel ist es in den jeweiligen Verzeichnissen wenn möglich nur die EXE und jeweiligen Daten liegen zu haben.
c) so kann ich theoretisch die EXE irgendwohin kopieren und dann dort ausführen.
Ganz so funktioniert .NET bzw. allgemein der Umgang mit DLLs nicht.
Siehe: How the Runtime Locates Assemblies
Assemblies im GAC müssen einen Strong Name besitzen.
Aber um ehrlich zu sein: das, was Du da vor hast ist genau das, was man heute nicht mehr will 😉
Wenn das für Dich persönlich so ist; dann mach das, was Dich weiter bringt. Ich rate aber massiv davon ab, das für größere Dinge oder Dritte zu nutzen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
zu a) Platz sollte wirklich keine Rolle spielen.
zu b) Wenn du nur 1 Exe haben willst schau dir mal ILMerge an.
zu c) Die Exe mal eben auf einen anderen Rechner kopieren und Ausführen geht so nicht. Und lokal die Exe hin und her zu Kopieren machen jetzt die wenigsten.
Ich würde dir auch davon abraten, im Endeffekt macht es mehr Probleme als es Vorteile hat.
Sollte man mal gelesen haben:
fast alle Programme, die ich schreibe sind kleine Tools, manchmal sogar nur für eine einmalige Verwendung (Datenaufbereitung, kleine Werteerfassung, Importtools, usw.). Diese werden mal auf diesem und mal auf jenem Rechner benötigt.
Diese Programme sind auch nicht für andere gedacht und werden auch nicht weiter gegeben. Ich habe gerade mal durchgesehen, es sind inzwischen über 100 Tools und Progrämmchen ...
Deshalb diese Vereinfachung.
Danke trotzdem für Eure Tipps. Bei großen Programmen sehe ich das ja genau so.
Dann mach Dir nen lokales NuGet Repository und arbeite mit ILMerge.
Mach ich auch und kann das Vorgehen nur empfehlen. Zehn mal weniger Stress als sich da irgendein unstabiles Konstrukt zu basteln, das auch noch mehr Zeit kostet 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Halte es persönlich für keine gute Idee.
Sofern du einen Bugfix in einer der zentralen DLLs vornimmst, könnte es sein, dass deine 100 Programme nicht mehr laufen, da die Version der zentralen DLL nicht mehr stimmt.
Dann lieber mit ILMerge arbeiten oder es eben in Kauf nehmen, dass im Output-Verzeichnis 2, 3 kleine DLLs mehr liegen.
Als alternative zu ILMerge wäre noch Costura.Fody zu empfehlen. Du installierst das Nuget-Package und bist fertig. Die kompilierte exe enthält sämtliche Abhängigkeiten und du brauchst die dll's nicht daneben liegen haben.
Wenn du deine Projekt-Datei anpasst:
<Target
AfterTargets="AfterBuild;NonWinFodyTarget"
Name="CleanReferenceCopyLocalPaths" >
<Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
Bekommst du auch noch ein sauberes Output-Directory.
Als alternative zu ILMerge wäre noch Costura.Fody zu empfehlen. Du installierst das Nuget-Package und bist fertig. Die kompilierte exe enthält sämtliche Abhängigkeiten und du brauchst die dll's nicht daneben liegen haben.
Gleich mal ausprobiert. Das ist wirklich genial einfach. 👍 😁
Ich schließ mich da mal an:
Danke für den Tipp, der ist super! 😄
Hab's einfach installiert und es lief, genial einfach.
Naja, wiederspricht das Zusammenpacken von DLL's zur Exe nicht ein wenig dem Konzept, dass einzelne Module leicht austauschbar sein sollten?
Ich habe es lieben gelernt, dass ich nicht immer das ganze Programm ersetzen muss sondern nur die erweiterte Assembly. Wird diese nun in das Programm fest eingebunden, ist das nicht mehr möglich und je nach Projekt hat man dann eine mords Dateigröße.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
Stimmt schon, es kann aber dennoch mal sinnvoll sein, ilmerge wird ja auch genutzt.
Ich finde einfach nur die extreme Einfachheit dieser Variante klasse, da hier alles automatisch passiert.
Für so kleine Tools ist das Merging schon praktisch.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Noch was zu Costura.Fody:
Ich hatte das in meiner aktuellen Solution in einem Dummy-Projekt installiert.
Der Test hat wunderbar funktioniert, aber scheinbar wird es nicht richtig deinstalliert.
Ich habe es über den NugetManager deinstalliert, der Hacken zum Entfernen der Abhängigkeiten war drin.
Nun habe ich das Problem, dass ich ein anderes Projekt, was mit dem Test-Projekt nichts zu tun hat, nicht mehr builden kann, weil jedes mal ein Fehler von Costura.Fody kommt, der besagt, dass es seine config, die eigentlich im Projekt liegen sollte, nicht findet.
Eine Lösung habe ich noch nicht gefunden, daher die Info an Alle: Lieber eine eigene Solution zum Rumspielen erstellen 😃
PS:
Ich hab in der csproj-Datei ganz unten folgenden Abschnitt gefunden:
<UsingTask TaskName="CosturaCleanup" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" TaskFactory="CodeTaskFactory">
<ParameterGroup>
<Config Output="false" Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem" />
<Files Output="false" Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]" />
</ParameterGroup>
<Task Evaluate="true">
<Reference xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Include="System.Xml" />
<Reference xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Include="System.Xml.Linq" />
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System" />
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.IO" />
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.Xml.Linq" />
<Code xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Type="Fragment" Language="cs"><![CDATA[
var config = XElement.Load(Config.ItemSpec).Elements("Costura").FirstOrDefault();
if (config == null) return true;
var excludedAssemblies = new List<string>();
var attribute = config.Attribute("ExcludeAssemblies");
if (attribute != null)
foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty))
excludedAssemblies.Add(item);
var element = config.Element("ExcludeAssemblies");
if (element != null)
foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty))
excludedAssemblies.Add(item);
var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase));
foreach (var item in filesToCleanup)
File.Delete(item);
]]></Code>
</Task>
</UsingTask>
<Target Name="CleanReferenceCopyLocalPaths" AfterTargets="AfterBuild;NonWinFodyTarget">
<CosturaCleanup Config="FodyWeavers.xml" Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
Wie der da rein kommt, weiß ich nicht, aber der muss raus, dann läuft's wieder.
Rein kommt er via PowerShell-Script. Ist oft so, dass NuGet Pakete nur ein Install.ps1 haben aber kein Uninstall-Script.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code