Çözümde proje bağımlılıkları kullanılıyorsa MSBuild referansları (DLL dosyaları) kopyalamaz


273

Visual Studio çözümümde dört proje var (.NET 3.5'i hedefleyen herkes) - sorunum için sadece bu ikisi önemlidir:

  1. MyBaseProject <- bu sınıf kütüphanesi üçüncü taraf DLL dosyasına başvuruyor (elmah.dll)
  2. MyWebProject1 <- bu web uygulaması projesi MyBaseProject için bir referans var

Ben elmah.dll başvuru eklendi MyBaseProject tıklayarak Görsel stüdyoda 2008'de "başvuru ekleyin ..." → "Gözat" sekmesi → "elmah.dll" seçerek.

Elmah Referansının Özellikleri aşağıdaki gibidir:

  • Takma adlar - global
  • Yerel kopyala - doğru
  • Kültür -
  • Açıklama - ASP.NET için Hata Günlüğü Modülleri ve İşleyicileri (ELMAH)
  • Dosya Türü - Montaj
  • Yol - D: \ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
  • Çözüldü - Doğru
  • Çalışma zamanı sürümü - v2.0.50727
  • Belirtilen sürüm - yanlış
  • Kesin Ad - yanlış
  • Sürüm - 1.0.11211.0

In MyWebProject1 I tarafından Proje MyBaseProject başvurusunu ekledi: "MyBaseProject" seçerek → "Projeler" sekmesi → "referansı ... Ekle". Bu başvurunun özellikleri, aşağıdaki üyeler dışında aynıdır:

  • Açıklama -
  • Yol - D: \ webs \ CMS \ MyBaseProject \ bin \ Debug \ MyBaseProject.dll
  • Sürüm - 1.0.0.0

Visual Studio'da yapıyı çalıştırırsam elmah.dll dosyası MyBaseProject.dll ile birlikte MyWebProject1'in bin dizinine kopyalanır !

Ancak , çözüm için MSBuild'i temizleyip çalıştırırsam (D: \ webs \ CMS> C: \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ MSBuild.exe / t: ReBuild / p: Configuration = MyProject.sln hatalarını ayıkla ) elmah.dll MyWebProject1 bin dizininde eksik - her ne kadar yapının kendisi hiçbir uyarı veya hata içermiyor!

Zaten MyBaseProject .csproj "true" ( "Visual Studio'da " kopya yerel " için bir takma ad olmalıdır) değeri ile özel öğe içerdiğinden emin oldum :

<Reference Include="Elmah, Version=1.0.11211.0, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\mypath\__tools\elmah\Elmah.dll</HintPath>
    **<Private>true</Private>**
</Reference>

(Özel etiket varsayılan olarak .csproj'un xml dosyasında görünmüyordu, ancak Visual Studio "yerel kopyala" doğru dedi. "Yerel kopyala" yı yanlış - kaydedilmiş - olarak değiştirdim ve tekrar doğru değerine ayarladım - kaydet!)

MSBuild ile ilgili sorun nedir? (Elmah.dll) referansının MyWebProject1'in bin kutusuna kopyalanmasını nasıl sağlayabilirim?

Her projenin postbuild komutuna bir postbuild kopya eylemi eklemek istemiyorum! (MyBaseProject'e bağlı birçok projem olacağını hayal edin!)


11
Bunun neden olduğu konusunda daha net bir cevap almak isterim.
David Faivre


1
bu konuda çalışan tam kaynak kodu örneği ile herhangi bir son çözüm?
Kiquenet

2
Cevap Bkz stackoverflow.com/a/21055664/21579 @deadlydog aşağıda. Mükemmel açıklama ve benim için sorunu çözdü ... en çok oy verilen cevap VS2012 için doğru değil.
Jeff Widmer

Yanıtlar:


153

Visual Studio ve MsBuild arasında oluştururken neden farklı olduğundan emin değilim, ama burada MsBuild ve Visual Studio'da bu sorunla karşılaştığımda bulduğum şey.

açıklama

Örnek bir senaryo için, proje X, montaj A ve montaj B'ye sahip olduğumuzu varsayalım. Montaj A, montaj B'ye başvurur, bu nedenle proje X, hem A hem de B'ye bir referans içerir. Ayrıca, proje X, montaj A'ya (örn. bir_işlev ()). Şimdi, X projesine referansta bulunan yeni bir Y projesi oluşturursunuz.

Böylece bağımlılık zinciri şöyle görünür: Y => X => A => B

Visual Studio / MSBuild akıllı olmaya çalışır ve yalnızca X projesinin gerektirdiğini algıladığı Y projesine referanslar getirir; Y projesinde referans kirliliğini önlemek için bunu yapar. Sorun, X projesi aslında B derlemesini açıkça kullanan herhangi bir kod içermediğinden (örn. B.SomeFunction ()), VS / MSBuild B'nin gerekli olduğunu algılamaz. ve böylece Y projesinin bin dizinine kopyalamaz; yalnızca X ve A montajlarını kopyalar.

Çözüm

Bu sorunu çözmek için iki seçeneğiniz vardır, her ikisi de B derlemesinin Y projesinin bin dizinine kopyalanmasına neden olur:

  1. Y projesinde B montajına bir referans ekleyin.
  2. X projesinde B derlemesini kullanan bir dosyaya sahte kod ekleyin.

Şahsen ben birkaç nedenden dolayı 2. seçeneği tercih ediyorum.

  1. Gelecekte X projesine başvuran başka bir proje eklerseniz, B montajına da bir referans eklemeyi hatırlamanız gerekmeyecektir (1. seçenekle yapmanız gerektiği gibi).
  2. Sahte kodun neden orada olması gerektiğini ve onu kaldırmamak gerektiğini söyleyen açık yorumlarınız olabilir. Birisi kodu yanlışlıkla silerse (örneğin, kullanılmayan kodu arayan bir refactor aracıyla), kodun gerekli olduğunu ve geri yükleyebildiğini kaynak kontrolünden kolayca görebilirsiniz. 1. seçeneği kullanırsanız ve biri kullanılmayan referansları temizlemek için bir yeniden düzenleme aracı kullanırsa, yorumunuz yoktur; bir başvurunun .csproj dosyasından kaldırıldığını göreceksiniz.

İşte bu durumla karşılaştığımda tipik olarak eklediğim "kukla kod" örneğidir.

    // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
    private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
    {
        // Assembly A is used by this file, and that assembly depends on assembly B,
        // but this project does not have any code that explicitly references assembly B. Therefore, when another project references
        // this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
        // assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
        // gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
        var dummyType = typeof(B.SomeClass);
        Console.WriteLine(dummyType.FullName);
    }

4
Burada tartışılmayan şey, bir web projesinin / binindeki yapı ürünlerinin kopyalanması ile hedef çıktı dizinine (örneğin / bin / x86 / Debug) rutin kopyalanması arasında bir fark olmasıdır. Birincisi, oluşturulduğunda başvurulan proje tarafından yapılır ve ikincisi bağımlı web projesi tarafından yapılır. Microsoft.Common.targets incelemesi bunu anlamaya yardımcı olur. Web / bin'e kopyalar hiç yerel kopyayı kopyalamaya bağlı değildir - kopyadaki yerel etkileri Debug ile çalışan Cassini tarafından başvurulan yapının bir parçası olmayan çıktı hedef dizinine kopyalayın.
user1164178

6
neden bu "kukla kodu" eklemeden VS ile çalıştı ama msbuild ile açıklayabilir misiniz?
toebens

3
Bir işlevi çağırmaktan daha az invaziv olsa da, derlemede bulunan bir sınıfın türünü sahte bir değişkene atayabilirsiniz. Type dummyType = typeof(AssemblyA.AnyClass);
Arithmomaniac

14
Visual Studio'da 'Kodu En İyi Duruma Getir' ayarını işaretlemediyseniz, yukarıda gösterilen 2. Çözüm çözüm çalışacaktır. Bu durumda, yine de dll'yi hariç tutacaktır. "Optimizasyonunu" geçersiz kılmak için bir satır daha ekledim. Console.WriteLine(dummyType.FullName);
JasonG

3
Çözüm 2 Visual Studio 2017'de benim için işe yaramadı. İlk olarak bunun X meclisinde sadece enumB'den kullandığımı ve enumun satır içinde olduğunu varsaydığımı düşündüm. Doğrudan B bir tür kullanmak için kod ekledi ve bu yardımcı olmadı. Aynı zamanda her zaman X'in A'daki alt sınıfları B'deki alt sınıfları kullandığı durumdaydı, bu yüzden derleyicinin B'nin X tarafından gerekli olmadığını ve göz ardı edilebileceğini nasıl düşündüğünü anlayamıyorum. Bu çılgınlık.
Xharlie

170

Sadece bununla başa çıkıyorum. Referansınızın özelliklerine gidin ve bunu yapın:

Set "Copy local = false"
Save
Set "Copy local = true"
Save

ve bu kadar.

Visual Studio 2010 başlangıçta şunu eklemez: <private>True</private> referans etiketine ve "yerel kopyala" seçeneğini yanlış olarak ayarlamak etiketin oluşturulmasına neden olur. Daha sonra buna göre doğru ve yanlış olarak ayarlanır.


10
Bu bir nimettir. Bunun için teşekkür ederim!
Rebecca

22
MSBuild 4 / VS2012 ile benim için çalışmadı. Yani, referansları güncelleyebildim <Private>true</Private>ama MSBuild üzerinde hiçbir etkisi yok gibi görünüyordu. Sonunda, alt düzey projelere NuGet referanslarını ekledim.
Michael Teper

2
Benim için çalışmadı. Hala System.Net.Http.Formatting dosyasını bin klasörüne kopyalamaz.
Akira Yamamoto

4
Bu eşdeğerdir Have you tried turning it off and on again?ve işe yaradı!
guanome

6
Görünüşe göre VS2015 hala aynı davranıyor: 'Yerel kopyala' ayarı 'False' olarak ayarlandıktan sonra başvurulan .dll dosyalarında 'True' ayarına geri dönüyor.
çevirme

38

Derleme doğrudan kodda kullanmıyorsanız, yardımcı olmaya çalışırken Visual Studio kullanılmadığını algılar ve çıktıya dahil etmez. Visual Studio ve MSBuild arasında neden farklı davranışlar gördüğünüzden emin değilim. Her ikisi için derleme çıktısını diyagnostik olarak ayarlamayı deneyebilir ve sonuçları karşılaştırarak nerede ayrıldığını görebilirsiniz.

Elmah.dll referansınıza gelince, doğrudan kodda başvurmuyorsanız, projenize bir öğe olarak ekleyebilir ve Eylem Oluşturma Contentve Çıktı Dizine Kopyala olarak ayarlayabilirsiniz Always.


3
Çıktı Dizini'ne yaptığınız kopya için +1, Elmah kodda kullanılmıyorsa içerik olarak kopyalamak mantıklıdır.
Kit Roed

4
Aslında kullanılmayan montajları yok sayar, ancak XAML kaynak sözlüklerinde montaj kullanan VS 2010'dan itibaren VS tarafından assmebly kullanıldığı düşünülmez, bu yüzden kopyalamaz.
Alex Burtsev


Bu dll ihtiyacım bir Birim Testi projesi için daha iyidir. Ana proje sadece testleri çalıştırmak için gerekli değildir bir dll eklemek istemiyorum!
Lukos

14

Şuna baksana:

Bu MSBuild forum iş parçacığını başlattım

Geçici çözümümü / geçici çözümü burada bulacaksınız!

(MyBaseProject, elmah.dll dosyasının MyWebProject1'in kutusuna kopyalanması için elmah.dll dosyasından bazı sınıflara (her ne olursa olsun) başvuran bazı kodlara ihtiyaç duyar!)


1
Lanet olsun - bu benim de geldiğim tek çözüm - bunu yapmanın daha iyi bir yolu olabileceğini umuyordum!
nickspoon

2
Daha az hacky bir çözüm için
Andrew'un yanıtına bakın

1
Şimdi buna bakanlar için , MSDN'deki toebens'in cevabı , birkaç yıl sonra sağlanan ölümcül cevap ile aynıdır .
jpaugh

8

Ben de aynı problemi yaşadım.

Projenizin çerçeve sürümünün başvurduğunuz dll'nin çerçeve sürümüyle aynı olup olmadığını kontrol edin.

Benim durumumda, istemcim "Framework 4 Client" kullanılarak derlendi ve DLL "Framework 4" idi.


6

Karşılaştığım sorun kütüphane projesine bağlı bir projem olmasıydı. Oluşturmak için şu adımları izliyordum:

msbuild.exe myproject.vbproj /T:Rebuild
msbuild.exe myproject.vbproj /T:Package

Tabii ki ben bin ve en önemlisi paket zip dosyasında benim kütüphanenin dll dosyaları eksik demekti. Bunun mükemmel çalıştığını gördüm:

msbuild.exe myproject.vbproj /T:Rebuild;Package

Neden bu işe ya da neden işe yaramadığına dair hiçbir fikrim yok. Ama umarım bu yardımcı olur.


Aynı sorunu / t: BuildCity'den bir adım sonra sonraki / t: Paket WebAPI projesinde kullanarak tüm çözümü oluştururken de aynı sorunu yaşadım. Herhangi bir proje referansı tarafından başvurulan herhangi bir dll dahil edilmemiştir. Bu yukarıdaki - / T: Rebuild; WebAPI üzerindeki paket daha sonra bu dll'leri kullanarak düzeltildi.
Andy Hoyle

5

Aynı problemi yaşadım ve aynı çözümdeki 2 projenin 3. taraf kütüphanesinin farklı bir versiyonuna atıfta bulunmasından kaynaklandı.

Tüm referansları düzelttikten sonra her şey mükemmel çalıştı.


4

Alex Burtsev'in bir yorumda bahsettiği gibi, sadece bir XAML kaynak sözlüğünde kullanılan herhangi bir şey veya benim durumumda, yalnızca XAML'de kullanılan ve arkasında kod olmayan herhangi bir şey, MSBuild tarafından 'kullanımda' olarak kabul edilmez.

Bu nedenle, sadece bir kodda derlemede bir sınıf / bileşene kukla bir başvuru yapmak MSBuild'i derlemenin gerçekten kullanımda olduğuna ikna etmek için yeterliydi.


Bu benim sorunum ve işe yarayan çözümdü. Bunu anlamaya çalışırken çok uzun zaman geçirdim. Teşekkürler Scott & @Alex Burstev
karol

İyi keder, bu beni deli ediyordu. Evet , FontAwesome.WPF kullanıyordum ve sadece XAML içinden (bariz nedenlerle). Sahte bir yöntem eklemek yardımcı oldu. Teşekkürler! Ve evet, VS 2017 15.6 hala etkileniyor, bu yüzden bir hata bildirdim
Sören Kuklau

3

Hedef çerçevesini değiştirme .NET Framework 4 İstemci Profili için .NET Framework 4 benim için bu sorunu düzeltildi.

Örneğinizde: MyWebProject1'deki hedef çerçeveyi .NET Framework 4 olarak ayarlayın


3

Deadlydog'un şemasını kullanarak,

Y => X => A => B ,

benim sorunum Y'yi inşa ettiğimde, X'in derlemeleri (A ve B, hepsi 15) Y'nin bin klasöründe görünmüyordu.

Ben referans X'i Y'den kaldırarak, kaydettikten, derledikten sonra X referansını (bir proje referansı) yeniden ekleyerek çözdüm ve kaydet, inşa et ve A ve B Y'nin bin klasöründe görünmeye başladı.


Diğer çözümlerin birçoğunu araştırıp denedikten sonra, bu benim için çalıştı.
Suncat2000

2

Aynı sorunu vardı ve dll dinamik olarak yüklenen bir referans oldu. Sorunu çözmek için dll ad alanı ile bir "kullanma" ekledim. Şimdi dll çıktı klasörüne kopyalanır.


2

Bunun için bir .targets için projenize dosya dosyayı projenin içerilenler bölümünde içerecek şekilde ayarlamanız gerekir.

Prosedür için cevabımı buraya bakın .


2

Derleme sırasında kullanılmayan referans düzenekleri doğru uygulama değildir. Ek dosyanızı kopyalaması için derleme dosyanızı artırmalısınız. Bir post-build olayı kullanarak veya özellik grubunu güncelleyerek.

Bazı örnekler diğer yazılarda bulunabilir


2

Bunun ortaya çıktığı başka bir senaryo, Visual Studio'da eski "Web Sitesi" proje türünü kullanıyorsanız. Bu proje türü için, kendi dizin yapısının (geçerli klasör ve aşağı) dışındaki .dll'lere başvuruda bulunamaz. Yukarıdaki yanıtta, dizin yapınızın şöyle göründüğünü varsayalım:

resim açıklamasını buraya girin

ProjectX ve ProjectY, üst / alt dizinler olduğunda ve ProjectX, A.dll'yi başvuruda bulunan A.dll'ye başvurur ve bu da B.dll ve B.dll'yi kök (Nugets) üzerindeki bir Nuget paketinde olduğu gibi dizin yapısının dışındadır. dll dahil edilecek, ancak B.dll olmayacak.


0

Bugün benzer bir sorunum vardı ve bu kesinlikle sorunuzun cevabı değil. Ama herkesi bilgilendirmek ve muhtemelen bir içgörü sağlamak istiyorum.

Bir ASP.NET uygulamam var. Derleme işlemi, temizlemeye ve sonra derlemeye ayarlanır.

İki Jenkins CI senaryom var. Biri üretim, diğeri sahneleme için. Başvurumu sahnelemeye yerleştirdim ve her şey yolunda gitti. Üretime dağıtıldı ve başvurulan bir DLL dosyası eksikti. Bu DLL dosyası sadece projenin kökündeydi. Hiçbir NuGet deposunda değil. DLL olarak ayarlandı do not copy.

CI betiği ve uygulama iki dağıtım arasında aynıydı. Yine de temizleme ve hazırlama ortamına konuşlandırıldıktan sonra DLL dosyası ASP.NET uygulamasının dağıtım konumunda değiştirildi (bin/ ) . Üretim ortamı için durum böyle değildi.

Bir test dalında bindizine bu DLL dosyasını kopyalamak için inşa sürecine bir adım ekledi ortaya çıkıyor . Şimdi anlaması biraz zaman alan kısım. CI süreci kendini temizlemiyordu. DLL çalışma dizininde bırakıldı ve yanlışlıkla ASP.NET .zip dosyasıyla paketleniyordu. Üretim dalı hiçbir zaman DLL dosyası aynı şekilde kopyalanmadı ve bunu yanlışlıkla dağıtmadı.

TLDR; Yapı sunucunuzun ne yaptığını kontrol edin ve emin olun.


0

Her iki projenin de aynı .net sürümünde olduğundan emin olun, ayrıca yerel kopyalamayı da kontrol edin, ancak bu truevarsayılan olarak olmalıdır


0

Ek parametre ekleyerek Visual Studio 2015 kullanma

/ Deployonbuild = yanlış

msbuild komut satırına sorun giderildi.


-1

Çok benzer bir sorunla karşılaştım. Visual Studio 2010 kullanarak derlerken, DLL dosyasıbin klasöre . Ancak, MSBuild kullanarak derlerken üçüncü taraf DLL dosyası dahil edilmedi.

Çok sinir bozucu. Çözdüğüm yol, doğrudan orada kullanmama rağmen NuGet referansını web projeme dahil etmekti .


Bu, en üstteki cevabın bir kopyasıdır.
Giles Roberts

-3

Başvurulan tüm DLL dosyalarını Web Sitesi projesine proje referanslarınızdan dahil etmek, özellikle bağımlılık enjeksiyonunu kullanırken her zaman iyi bir fikir değildir. : web projeniz herhangi bir somut uygulama DLL'si değil, arayüz DLL dosyasına / projesine bir referans eklemek istiyor dosya.

Bir uygulama DLL dosyasına / projesine doğrudan bir başvuru eklerseniz, geliştiricinizin arabirim yerine uygulama DLL dosyasının / projesinin somut sınıflarında "yeni" çağrılmasını engelleyemezsiniz. Uygulamayı kullanmak için web sitenizde bir "sabit kod" da belirtmişsinizdir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.