Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Salah satu tugas terpenting dalam MSBuild dan proses build .NET adalah menyelesaikan referensi perakitan, yang terjadi dalam ResolveAssemblyReference
tugas. Artikel ini menjelaskan beberapa detail cara ResolveAssemblyReference
kerjanya, dan cara memecahkan masalah kegagalan build yang dapat terjadi ketika ResolveAssemblyReference
tidak dapat menyelesaikan referensi. Untuk menyelidiki kegagalan referensi perakitan, Anda mungkin ingin menginstal Penampil Log Terstruktur untuk melihat log MSBuild. Cuplikan layar dalam artikel ini diambil dari Penampil Log Terstruktur.
Tujuannya ResolveAssemblyReference
adalah untuk mengambil semua referensi yang ditentukan dalam .csproj
file (atau di tempat lain) melalui <Reference>
item dan memetakannya ke jalur ke file rakitan di sistem file.
Pengkompilasi hanya dapat menerima .dll
jalur pada sistem file sebagai referensi, jadi ResolveAssemblyReference
mengonversi string seperti mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
yang muncul dalam file proyek ke jalur seperti C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll
, yang kemudian diteruskan ke pengkompilasi melalui sakelar /r
.
ResolveAssemblyReference
Selain itu menentukan set lengkap (sebenarnya penutupan transitif dalam istilah teori grafik) dari semua .dll
dan .exe
referensi secara rekursif, dan untuk masing-masing menentukan apakah itu harus disalin ke direktori output build atau tidak. Ini tidak melakukan penyalinan aktual (yang ditangani nanti, setelah langkah kompilasi aktual), tetapi menyiapkan daftar item file untuk disalin.
ResolveAssemblyReference
dipanggil dari ResolveAssemblyReferences
target:
Jika Anda melihat pemesanan, ResolveAssemblyReferences
terjadi sebelum Compile
, dan tentu saja, CopyFilesToOutputDirectory
terjadi setelah Compile
.
Catatan
ResolveAssemblyReference
tugas dipanggil dalam file Microsoft.Common.CurrentVersion.targets
standar .targets
di folder penginstalan MSBuild. Anda juga dapat menelusuri target .NET SDK MSBuild secara online di https://github.com/dotnet/msbuild/blob/a936b97e30679dcea4d99c362efa6f732c9d3587/src/Tasks/Microsoft.Common.CurrentVersion.targets#L1991-L2140. Tautan ini memperlihatkan dengan tepat di mana ResolveAssemblyReference
tugas dipanggil dalam .targets
file.
Input ResolveAssemblyReference
ResolveAssemblyReference
komprehensif tentang pengelogan inputnya:
Simpul Parameters
adalah standar untuk semua tugas, tetapi juga ResolveAssemblyReference
mencatat sekumpulan informasinya sendiri di bawah Input (yang pada dasarnya sama seperti di bawah Parameters
, tetapi disusun secara berbeda).
Input yang paling penting adalah Assemblies
dan AssemblyFiles
:
<ResolveAssemblyReference
Assemblies="@(Reference)"
AssemblyFiles="@(_ResolvedProjectReferencePaths);@(_ExplicitReference)"
Assemblies
menggunakan konten Reference
item MSBuild saat ini ketika ResolveAssemblyReference
dipanggil untuk proyek. Semua referensi metadata dan rakitan, termasuk referensi NuGet Anda, harus dimuat dalam item ini. Setiap referensi memiliki sekumpulan metadata yang kaya yang melekat padanya:
AssemblyFiles
berasal dari ResolveProjectReference
item output target yang disebut _ResolvedProjectReferencePaths
. ResolveProjectReference
berjalan sebelum ResolveAssemblyReference
dan mengonversi <ProjectReference>
item ke jalur rakitan bawaan pada disk. AssemblyFiles
Jadi akan berisi rakitan yang dibangun oleh semua proyek yang dirujuk dari proyek saat ini:
Input lain yang berguna adalah parameter boolean FindDependencies
, yang mengambil nilainya dari _FindDependencies
properti:
FindDependencies="$(_FindDependencies)"
Anda dapat mengatur properti ini ke false
dalam build Anda untuk menonaktifkan analisis rakitan dependensi transitif.
Algoritma ResolveAssemblyReference
Algoritma yang disederhanakan ResolveAssemblyReference
untuk tugas adalah sebagai berikut:
- Input log.
MSBUILDLOGVERBOSERARSEARCHRESULTS
Periksa variabel lingkungan. Atur variabel ini ke nilai apa pun untuk mendapatkan log yang lebih rinci.- Menginisialisasi objek tabel referensi.
- Baca file cache dari
obj
direktori (jika ada). - Menghitung penutupan dependensi.
- Buat tabel output.
- Tulis file cache ke
obj
direktori. - Catat hasilnya.
Algoritma mengambil daftar input rakitan (baik dari metadata maupun referensi proyek), mengambil daftar referensi untuk setiap rakitan yang diproses (dengan membaca metadata) dan membangun set lengkap (penutupan transitif) dari semua rakitan yang direferensikan, dan menyelesaikannya dari berbagai lokasi (termasuk GAC, AssemblyFoldersEx, dan sebagainya).
Rakitan yang dirujuk ditambahkan ke daftar secara berulang sampai tidak ada lagi referensi baru yang ditambahkan. Kemudian algoritma berhenti.
Referensi langsung yang Anda berikan ke tugas disebut Referensi utama. Rakitan tidak langsung yang ditambahkan ke set karena referensi transitif disebut Dependensi. Catatan untuk setiap rakitan tidak langsung melacak semua item utama ("root") yang menyebabkan penyertaannya dan metadata yang sesuai.
Hasil tugas ResolveAssemblyReference
ResolveAssemblyReference
menyediakan pengelogan terperinci dari hasil:
Rakitan yang diselesaikan dibagi menjadi dua kategori: Referensi utama dan Dependensi. Referensi utama ditentukan secara eksplisit sebagai referensi proyek yang sedang dibangun. Dependensi disimpulkan dari referensi referensi secara transitif.
Penting
ResolveAssemblyReference
membaca metadata rakitan untuk menentukan referensi rakitan tertentu. Ketika pengkompilasi C# memancarkan rakitan, itu hanya menambahkan referensi ke rakitan yang benar-benar diperlukan. Jadi, mungkin terjadi bahwa ketika Anda mengkompilasi proyek tertentu, proyek dapat menentukan referensi yang tidak diperlukan yang tidak akan dipanggang ke dalam rakitan. Tidak apa-apa untuk menambahkan referensi ke proyek yang tidak diperlukan; mereka diabaikan.
Metadata item CopyLocal
Referensi juga dapat memiliki CopyLocal
metadata atau tidak. Jika referensi memiliki CopyLocal = true
, referensi tersebut nantinya akan disalin ke direktori output oleh CopyFilesToOutputDirectory
target. Dalam contoh ini, DataFlow
telah CopyLocal
diatur ke true, sementara Immutable
tidak:
CopyLocal
Jika metadata hilang sepenuhnya, metadata diasumsikan benar secara default. Jadi ResolveAssemblyReference
secara default mencoba menyalin dependensi ke output kecuali menemukan alasan untuk tidak. ResolveAssemblyReference
mencatat alasan mengapa ia memilih referensi tertentu menjadi CopyLocal
atau tidak.
Semua kemungkinan alasan keputusan CopyLocal
dijumlahkan dalam tabel berikut. Sangat berguna untuk mengetahui string ini untuk dapat mencarinya di log build.
Status CopyLocal | Deskripsi |
---|---|
Undecided |
Status lokal salinan tidak terdeteksi sekarang. |
YesBecauseOfHeuristic |
Referensi harus memiliki CopyLocal='true' karena itu bukan 'tidak' karena alasan apa pun. |
YesBecauseReferenceItemHadMetadata |
Referensi harus memiliki CopyLocal='true' karena item sumbernya memiliki Private='true' |
NoBecauseFrameworkFile |
Referensi harus memiliki CopyLocal='false' karena ini adalah file kerangka kerja. |
NoBecausePrerequisite |
Referensi harus memiliki CopyLocal='false' karena ini adalah file prasyarat. |
NoBecauseReferenceItemHadMetadata |
Referensi harus memiliki CopyLocal='false' karena Private atribut diatur ke 'false' dalam proyek. |
NoBecauseReferenceResolvedFromGAC |
Referensi harus memiliki CopyLocal='false' karena diselesaikan dari GAC. |
NoBecauseReferenceFoundInGAC |
Perilaku warisan, CopyLocal='false' ketika rakitan ditemukan di GAC (bahkan ketika diselesaikan di tempat lain). |
NoBecauseConflictVictim |
Referensi harus memiliki CopyLocal='false' karena kehilangan konflik antara file rakitan bernama yang sama. |
NoBecauseUnresolved |
Referensi belum terselesaikan. Ini tidak dapat disalin ke direktori bin karena tidak ditemukan. |
NoBecauseEmbedded |
Referensi disematkan. Ini tidak boleh disalin ke direktori bin karena tidak akan dimuat saat runtime. |
NoBecauseParentReferencesFoundInGAC |
Properti copyLocalDependenciesWhenParentReferenceInGac diatur ke false dan semua item sumber induk ditemukan di GAC. |
NoBecauseBadImage |
File rakitan yang disediakan tidak boleh disalin karena merupakan gambar yang buruk, mungkin tidak dikelola, mungkin bukan rakitan sama sekali. |
Metadata item privat
Bagian penting dari penentuan CopyLocal
adalah Private
metadata pada semua referensi utama. Setiap referensi (utama atau dependensi) memiliki daftar semua referensi utama (item sumber) yang telah berkontribusi pada referensi tersebut yang ditambahkan ke penutupan.
- Jika tidak ada item sumber yang menentukan
Private
metadata,CopyLocal
diatur keTrue
(atau tidak diatur, yang defaultnya )True
- Jika salah satu item sumber menentukan
Private=true
,CopyLocal
diatur keTrue
- Jika tidak ada rakitan sumber yang menentukan
Private=true
dan setidaknya satu menentukanPrivate=false
,CopyLocal
diatur keFalse
Referensi mana yang mengatur Privat ke false?
Poin terakhir adalah alasan yang sering digunakan untuk CopyLocal
diatur ke false: 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 tidak memberi tahu kami referensi mana yang telah diatur Private
ke false, tetapi penampil log terstruktur menambahkan Private
metadata ke item yang ditentukan di atas:
Ini menyederhanakan penyelidikan dan memberi tahu Anda referensi mana yang menyebabkan dependensi yang bersangkutan diatur dengan CopyLocal=false
.
Singgahan Perakitan Global
Global Assembly Cache (GAC) memainkan peran penting dalam menentukan apakah akan menyalin referensi ke output. Ini sangat disayangkan karena konten GAC khusus mesin dan ini mengakibatkan masalah untuk build yang dapat direproduksi (di mana perilaku berbeda pada komputer yang berbeda tergantung pada status komputer, seperti GAC).
Ada perbaikan terbaru yang dibuat untuk ResolveAssemblyReference
meringankan situasi. Anda dapat mengontrol perilaku dengan dua input baru ini ke ResolveAssemblyReference
:
CopyLocalDependenciesWhenParentReferenceInGac="$(CopyLocalDependenciesWhenParentReferenceInGac)"
DoNotCopyLocalIfInGac="$(DoNotCopyLocalIfInGac)"
AssemblySearchPaths
Ada dua cara untuk mengkustomisasi ResolveAssemblyReference
daftar pencarian jalur dalam mencoba menemukan rakitan. Untuk sepenuhnya menyesuaikan daftar, properti AssemblySearchPaths
dapat diatur sebelumnya. Pesanan penting; jika rakitan berada di dua lokasi, ResolveAssemblyReference
berhenti setelah menemukannya di lokasi pertama.
Secara default, ada sepuluh pencarian lokasi ResolveAssemblyReference
(empat jika Anda menggunakan .NET SDK), dan masing-masing dapat dinonaktifkan dengan mengatur bendera yang relevan ke false:
- Mencari file dari proyek saat ini dinonaktifkan dengan mengatur properti ke
AssemblySearchPath_UseCandidateAssemblyFiles
false. - Mencari properti jalur referensi (dari
.user
file) dinonaktifkan dengan mengatur properti keAssemblySearchPath_UseReferencePath
false. - Menggunakan jalur petunjuk dari item dinonaktifkan dengan mengatur properti ke
AssemblySearchPath_UseHintPathFromItem
false. - Menggunakan direktori dengan runtime target MSBuild dinonaktifkan dengan mengatur
AssemblySearchPath_UseTargetFrameworkDirectory
properti ke false. - Mencari folder rakitan dari AssemblyFolders.config dinonaktifkan dengan mengatur
AssemblySearchPath_UseAssemblyFoldersConfigFileSearchPath
properti ke false. - Mencari registri dinonaktifkan dengan mengatur properti ke
AssemblySearchPath_UseRegistry
false. - Mencari folder rakitan terdaftar warisan dinonaktifkan dengan mengatur
AssemblySearchPath_UseAssemblyFolders
properti ke false. - Mencari di GAC dinonaktifkan dengan mengatur properti ke
AssemblySearchPath_UseGAC
false. - Memperlakukan Include referensi sebagai nama file nyata dinonaktifkan dengan mengatur
AssemblySearchPath_UseRawFileName
properti ke false. - Memeriksa folder output aplikasi dinonaktifkan dengan mengatur properti ke
AssemblySearchPath_UseOutDir
false.
Terjadi konflik
Situasi umum adalah MSBuild memberikan peringatan tentang versi yang berbeda dari rakitan yang sama yang digunakan oleh referensi yang berbeda. Solusi ini sering melibatkan penambahan pengalihan pengikatan ke file app.config.
Cara yang berguna untuk menyelidiki konflik ini adalah dengan mencari di MSBuild Structured Log Viewer untuk "Ada konflik". Ini menunjukkan kepada Anda informasi terperinci tentang referensi mana yang diperlukan versi rakitan mana yang dimaksud.