Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Eine der wichtigsten Aufgaben in MSBuild und der .NET-Buildprozess ist das Auflösen von Assemblyverweisen, was in der ResolveAssemblyReference Aufgabe geschieht. In diesem Artikel werden einige Details zur Funktionsweise von ResolveAssemblyReference sowie zur Fehlerbehebung bei Build-Fehlern erläutert, die auftreten können, wenn ResolveAssemblyReference eine Referenz nicht aufgelöst werden kann. Um Assemblyverweisfehler zu untersuchen, sollten Sie den Strukturierten Protokoll-Viewer installieren, um MSBuild-Protokolle anzuzeigen. Die Screenshots in diesem Artikel stammen aus dem Strukturierten Protokoll-Viewer.
Der Zweck ResolveAssemblyReference besteht darin, alle in .csproj Dateien (oder an anderer Stelle) angegebenen Verweise über das <Reference> Element zu übernehmen und sie Pfaden zu Assemblydateien im Dateisystem zuzuordnen.
Die Compiler können nur einen .dll Pfad im Dateisystem als Verweis akzeptieren, daher konvertiert ResolveAssemblyReference Zeichenfolgen wie mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, die in Projektdateien erscheinen, in Pfade wie C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll, die dann über die /r Option an den Compiler übergeben werden.
ResolveAssemblyReference Bestimmt außerdem den vollständigen Satz (tatsächlich die transitive Schließung in Begriffen der Graphentheorie) aller .dll und .exe Verweise rekursiv und entscheidet für jeden von ihnen, ob er in das Buildausgabeverzeichnis kopiert werden soll oder nicht. Das eigentliche Kopieren (das später nach dem tatsächlichen Kompilierungsschritt behandelt wird) wird nicht ausgeführt, aber es bereitet eine Elementliste der zu kopierenden Dateien vor.
ResolveAssemblyReference wird vom ResolveAssemblyReferences Ziel aufgerufen:
Wenn Sie die Reihenfolge bemerken, ResolveAssemblyReferences geschieht vor Compile, und natürlich geschieht CopyFilesToOutputDirectory nach Compile.
Hinweis
ResolveAssemblyReference die Aufgabe wird in der Standarddatei .targetsMicrosoft.Common.CurrentVersion.targets in den MSBuild-Installationsordnern aufgerufen. Sie können sich auch die .NET SDK MSBuild-Ziele online ansehen unter https://github.com/dotnet/msbuild/blob/a936b97e30679dcea4d99c362efa6f732c9d3587/src/Tasks/Microsoft.Common.CurrentVersion.targets#L1991-L2140. Dieser Link zeigt genau an, wo die ResolveAssemblyReference Aufgabe in der .targets Datei aufgerufen wird.
Eingaben für ResolveAssemblyReference
ResolveAssemblyReference ist umfassend in der Protokollierung seiner Eingaben:
Der Parameters Knoten ist Standard für alle Aufgaben, protokolliert zusätzlich ResolveAssemblyReference seine eigenen Informationen unter "Eingaben" (die im Grunde identisch mit denen unter Parameters sind, aber anders strukturiert sind).
Die wichtigsten Eingaben sind Assemblies und AssemblyFiles:
<ResolveAssemblyReference
Assemblies="@(Reference)"
AssemblyFiles="@(_ResolvedProjectReferencePaths);@(_ExplicitReference)"
Assemblies verwendet den Inhalt des Reference MSBuild-Elements im Moment, wenn ResolveAssemblyReference für das Projekt aufgerufen wird. Alle Metadaten- und Assemblyverweise, einschließlich Ihrer NuGet-Verweise, sollten in diesem Element enthalten sein. Jeder Verweis weist einen umfangreichen Satz von Metadaten auf:
AssemblyFiles stammt aus dem ResolveProjectReference-Ausgabeelement des Ziels namens _ResolvedProjectReferencePaths.
ResolveProjectReference wird vor ResolveAssemblyReference ausgeführt und konvertiert <ProjectReference> Elemente in die Pfade der erstellten Assemblys auf dem Datenträger. Daher enthalten die AssemblyFiles Assemblys, die von allen referenzierten Projekten des aktuellen Projekts erstellt wurden:
Eine weitere nützliche Eingabe ist der boolesche FindDependencies Parameter, der seinen Wert aus der _FindDependencies Eigenschaft verwendet:
FindDependencies="$(_FindDependencies)"
Sie können diese Eigenschaft auf false in Ihrem Build setzen, um die Analyse transitiver Abhängigkeitsasssemblies auszuschalten.
ResolveAssemblyReference-Algorithmus
Der vereinfachte Algorithmus für die ResolveAssemblyReference Aufgabe lautet wie folgt:
- Protokolleingaben.
- Überprüfen Sie die Umgebungsvariable
MSBUILDLOGVERBOSERARSEARCHRESULTS. Legen Sie diese Variable auf einen beliebigen Wert fest, um detailliertere Protokolle abzurufen. - Initialisieren Sie die Tabelle des Verweisesobjekts.
- Lesen Sie die Cachedatei aus dem
objVerzeichnis (sofern vorhanden). - Berechnen des Schließens von Abhängigkeiten.
- Erstellen Sie die Ausgabetabellen.
- Schreiben Sie die Cachedatei in das
objVerzeichnis. - Protokollieren Sie die Ergebnisse.
Der Algorithmus verwendet die Eingabeliste von Assemblys (sowohl aus Metadaten als auch Projektverweise), ruft die Liste der Verweise für jede Assembly ab, die verarbeitet wird (durch Lesen von Metadaten) und erstellt einen vollständigen Satz (transitives Schließen) aller referenzierten Assemblys und löst sie von verschiedenen Speicherorten (einschließlich GAC, AssemblyFoldersEx usw.) auf.
Referenzierte Assemblys werden der Liste iterativ hinzugefügt, bis keine neuen Verweise hinzugefügt werden. Anschließend stoppt der Algorithmus.
Direkte Verweise, die Sie für die Aufgabe angegeben haben, werden als primäre Verweise bezeichnet. Indirekte Assemblys, die dem Satz aufgrund eines transitiven Verweises hinzugefügt wurden, werden als Abhängigkeit bezeichnet. Der Eintrag für jede indirekte Assembly zeichnet alle primären („Stamm“) Elemente auf, die zu ihrer Aufnahme geführt haben, und die entsprechenden Metadaten.
Ergebnisse der ResolveAssemblyReference-Aufgabe
ResolveAssemblyReference bietet eine detaillierte Protokollierung der Ergebnisse:
Gelöste Assemblys sind in zwei Kategorien unterteilt: Primäre Verweise und Abhängigkeiten. Primäre Verweise wurden explizit als Verweise auf das zu erstellende Projekt angegeben. Abhängigkeiten wurden transitiv von Verweisen von Verweisen abgeleitet.
Von Bedeutung
ResolveAssemblyReference liest Assemblymetadaten, um die Verweise einer bestimmten Assembly zu bestimmen. Wenn der C#-Compiler eine Assembly ausgibt, werden nur Verweise auf Assemblys hinzugefügt, die tatsächlich benötigt werden. Wenn Sie also ein bestimmtes Projekt kompilieren, kann das Projekt einen nicht benötigten Verweis angeben, der nicht in die Assembly integriert wird. Es ist OK, Verweise auf Projekt hinzuzufügen, die nicht benötigt werden; sie werden ignoriert.
CopyLocal-Objektmetadaten
Verweise können auch über die CopyLocal Metadaten verfügen oder nicht. Wenn der Verweis CopyLocal = true vorhanden ist, wird er später vom CopyFilesToOutputDirectory-Ziel in das Ausgabeverzeichnis kopiert. In diesem Beispiel ist DataFlow auf CopyLocal true gesetzt, während dies bei Immutable nicht der Fall ist.
Wenn die CopyLocal Metadaten vollständig fehlen, wird davon ausgegangen, dass sie standardmäßig "true" ist. Versucht ResolveAssemblyReference standardmäßig, Abhängigkeiten in die Ausgabe zu kopieren, es sei denn, es gibt einen Grund dagegen.
ResolveAssemblyReference zeichnet die Gründe auf, warum ein bestimmter Verweis ausgewählt wurde CopyLocal oder nicht.
Alle möglichen Gründe für die CopyLocal Entscheidung werden in der folgenden Tabelle aufgelistet. Es ist hilfreich, diese Zeichenfolgen zu kennen, um in Buildprotokollen nach diesen Zeichenfolgen zu suchen.
| CopyLocal-Zustand | Description |
|---|---|
Undecided |
Der lokale Kopierstatus ist derzeit unentschieden. |
YesBecauseOfHeuristic |
Der Verweis sollte haben CopyLocal='true' , weil er aus irgendeinem Grund nicht "nein" war. |
YesBecauseReferenceItemHadMetadata |
Der Verweis sollte CopyLocal='true' beinhalten, da sein Quellelement "Private='true'" hat. |
NoBecauseFrameworkFile |
Der Verweis sollte aufweisen CopyLocal='false' , da es sich um eine Frameworkdatei handelt. |
NoBecausePrerequisite |
Der Verweis sollte CopyLocal='false' enthalten, da es sich um eine erforderliche Datei handelt. |
NoBecauseReferenceItemHadMetadata |
Der Verweis sollte CopyLocal='false' aufweisen, da das Private Attribut im Projekt auf "false" festgelegt ist. |
NoBecauseReferenceResolvedFromGAC |
Der Verweis sollte CopyLocal='false' aufweisen, da er vom GAC aufgelöst worden ist. |
NoBecauseReferenceFoundInGAC |
Legacy-Verhalten, CopyLocal='false' wenn die Assembly im GAC gefunden wird (auch wenn sie an anderer Stelle aufgelöst wurde). |
NoBecauseConflictVictim |
Der Verweis sollte CopyLocal='false' enthalten, da ein Konflikt mit einer gleichnamigen Assembly-Datei verloren wurde. |
NoBecauseUnresolved |
Der Verweis war nicht gelöst. Sie kann nicht in das Bin-Verzeichnis kopiert werden, da es nicht gefunden wurde. |
NoBecauseEmbedded |
Der Verweis wurde eingebettet. Sie sollte nicht in das Bin-Verzeichnis kopiert werden, da sie zur Laufzeit nicht geladen wird. |
NoBecauseParentReferencesFoundInGAC |
Die Eigenschaft copyLocalDependenciesWhenParentReferenceInGac ist auf "false" festgelegt, und alle übergeordneten Quellelemente wurden im GAC gefunden. |
NoBecauseBadImage |
Die bereitgestellte Assembly-Datei sollte nicht kopiert werden, da es sich um ein schlechtes Abbild handeln könnte, möglicherweise nicht verwaltet wird und möglicherweise gar keine Assembly ist. |
Metadaten für private Elemente
Ein wichtiger Bestandteil der Bestimmung von CopyLocal sind die Private Metadaten aller primären Verweise. Jeder Verweis (primärer oder abhängiger Verweis) verfügt über eine Liste aller primären Verweise (Quellelemente), die zu dessen Aufnahme in den Abschluss beigetragen haben.
- Wenn keines der Quellelemente Metadaten
Privatespezifiziert, wirdCopyLocalaufTruefestgelegt (oder nicht festgelegt ist, was standardmäßig aufTruefestgelegt wird). - Wenn eines der Quellelemente
Private=trueangibt, wirdCopyLocalaufTruegesetzt. - Wenn keine der Quellassemblys das
Private=trueangibt und mindestens eine dasPrivate=falseangibt, wirdCopyLocalaufFalsegesetzt.
Welche Referenz setzt private auf false?
Der letzte Punkt ist ein häufig verwendeter Grund dafür, CopyLocal auf "false" gesetzt zu werden: This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true".
MSBuild teilt uns nicht mit, welcher Verweis Private auf 'false' gesetzt hat, aber der strukturierte Protokoll-Viewer fügt die Private Metadaten zu den Elementen hinzu, für die es oben angegeben wurde.
Dies vereinfacht Untersuchungen und informiert Sie genau, welcher Verweis dazu geführt hat, dass die betreffende Abhängigkeit mit CopyLocal=false festgelegt wurde.
Globaler Assemblycache
Der globale Assemblycache (Global Assembly Cache, GAC) spielt eine wichtige Rolle bei der Bestimmung, ob Verweise auf die Ausgabe kopiert werden sollen. Dies ist bedauerlich, weil der Inhalt des GAC maschinenspezifisch ist und dies zu Problemen bei reproduzierbaren Builds führt (wo sich das Verhalten auf unterschiedlichen Computern unterscheidet, die vom Computerzustand abhängig sind, z. B. das GAC).
Kürzlich wurden Korrekturen an ResolveAssemblyReference vorgenommen, um die Situation zu lindern. Sie können das Verhalten über diese beiden neuen Eingaben zu ResolveAssemblyReference steuern:
CopyLocalDependenciesWhenParentReferenceInGac="$(CopyLocalDependenciesWhenParentReferenceInGac)"
DoNotCopyLocalIfInGac="$(DoNotCopyLocalIfInGac)"
AssemblySearchPaths
Es gibt zwei Möglichkeiten, die Liste der Pfade, in denen ResolveAssemblyReference nach einer Assembly sucht, anzupassen. Um die Liste vollständig anzupassen, kann die Eigenschaft AssemblySearchPaths vorab festgelegt werden. Die Reihenfolge ist wichtig; wenn sich eine Assembly an zwei Speicherorten befindet, ResolveAssemblyReference endet der Vorgang, nachdem sie am ersten Speicherort gefunden wurde.
AssemblySearchPaths ist eine durch Semikolons getrennte Liste. Sie unterstützt eine Reihe integrierter Platzhalter (z. B. {HintPathFromItem} und {GAC}), die während des Auflösens auf tatsächliche Positionen erweitert werden.
Standardmäßig verwenden Projekte im Nicht-SDK-Stil die folgende Suchpfadreihenfolge:
- Kandidatenassemblydateien (
{CandidateAssemblyFiles}) - Die
ReferencePathEigenschaft ($(ReferencePath)) - Hinweispfade aus
<Reference>Elementen ({HintPathFromItem}) - Das Zielframeworkverzeichnis (
{TargetFrameworkDirectory}) - Assembly-Ordner von
AssemblyFolders.config($(AssemblyFoldersConfigFileSearchPath)) - Die Registrierung (
{Registry:...}) - Ältere registrierte Assemblyordner (
{AssemblyFolders}) - Globaler Assemblycache (GAC) (
{GAC}) - Behandeln des
<Reference Include="...">Werts als echter Dateiname ({RawFileName}) - Das Ausgabeverzeichnis (
$(OutDir))
Das .NET SDK legt einen kleineren Standardwert für AssemblySearchPaths fest (ohne standardmäßige Durchsuchung von GAC, Registrierung und Ausgabeverzeichnis).
{CandidateAssemblyFiles}{HintPathFromItem}{TargetFrameworkDirectory}{RawFileName}
Um den effektiven Wert für Ihren Build zu sehen, inspizieren Sie die protokollierte Eingabe von SearchPaths durch ResolveAssemblyReference (z. B. im MSBuild Structured Log Viewer), oder verarbeiten Sie das Projekt mit msbuild /pp vor.
Jeder Eintrag kann deaktiviert werden, indem die entsprechende Kennzeichnung auf false gesetzt wird.
- Das Durchsuchen von Dateien aus dem aktuellen Projekt ist deaktiviert, indem die
AssemblySearchPath_UseCandidateAssemblyFilesEigenschaft auf "false" festgelegt wird. - Das Durchsuchen der Verweispfadeigenschaft (aus einer
.userDatei) ist deaktiviert, indem man dieAssemblySearchPath_UseReferencePathEigenschaft auf "false" festlegt. - Die Verwendung des Hinweispfads aus dem Element ist deaktiviert, indem die Eigenschaft
AssemblySearchPath_UseHintPathFromItemauf false festgelegt wird. - Die Verwendung des Verzeichnisses mit der Ziellaufzeit von MSBuild ist deaktiviert, indem die
AssemblySearchPath_UseTargetFrameworkDirectoryEigenschaft auf "false" festgelegt wird. - Das Durchsuchen von Assemblyordnern aus AssemblyFolders.config ist deaktiviert, indem die
AssemblySearchPath_UseAssemblyFoldersConfigFileSearchPathEigenschaft auf "false" festgelegt wird. - Die Suche in der Registrierung ist deaktiviert, indem die
AssemblySearchPath_UseRegistryEigenschaft auf "false" festgelegt wird. - Das Durchsuchen von älteren registrierten Assemblyordnern ist deaktiviert, indem die
AssemblySearchPath_UseAssemblyFoldersEigenschaft auf "false" festgelegt wird. - Die Suche im GAC ist deaktiviert, indem die
AssemblySearchPath_UseGACEigenschaft auf "false" festgelegt wird. - Die Behandlung des "Include"-Elements eines Verweises als echter Dateiname wird deaktiviert, indem die
AssemblySearchPath_UseRawFileName-Eigenschaft auf "false" gesetzt wird. - Das Überprüfen des Ausgabeordners der Anwendung ist deaktiviert, indem die
AssemblySearchPath_UseOutDirEigenschaft auf "false" festgelegt wird.
Es gab einen Konflikt
Eine häufige Situation ist, dass MSBuild eine Warnung ausgibt, weil verschiedene Verweise unterschiedliche Versionen derselben Assembly verwenden. Die Lösung umfasst häufig das Hinzufügen einer Bindungsumleitung zur app.config Datei.
Eine nützliche Möglichkeit, diese Konflikte zu untersuchen, besteht darin, in DER MSBuild Structured Log Viewer nach "Es gab einen Konflikt" zu suchen. Es zeigt Ihnen detaillierte Informationen darüber, welche Verweise benötigt werden, welche Versionen der betreffenden Assembly erforderlich sind.