La DLL dipendente non viene copiata nella cartella di output della generazione in Visual Studio


188

Ho una soluzione di Visual Studio. Ho molti progetti nella soluzione. C'è un progetto principale che funge da start up e utilizza altri progetti. C'è un progetto che dice "ProjectX". Il suo riferimento viene aggiunto al progetto principale. ProjectX fa riferimento a un'altra DLL .NET (ad esempio abc.dll) che non fa parte della soluzione.

Ora questo abc.dll dovrebbe essere copiato nella cartella bin / debug del progetto principale, ma non viene copiato lì. Perché non viene copiato, qualche motivo noto?


se non riesci a capirlo, copialo nel tuo pre-build.
Dilshod,

come usi il tuo 'ProjectX' nel progetto principale - qual è il tipo di progetto, target ecc.
NSGaga - per lo più inattivo

Ho avuto lo stesso problema e questa risposta ha risolto il mio problema: stackoverflow.com/a/8213977/174469
Gordon Tucker,


c'è una RestoreProjectStyle soluzione disponibile . L'idea è di impostare <RestoreProjectStyle>PackageReference</RestoreProjectStyle>per ogni progetto .Net Framework nella soluzione.
oleksa,

Risposte:


105

Ho scoperto che se ProjectX fa riferimento ad abc.dll ma non utilizza direttamente nessuno dei tipi DEFINED in abc.dll, abc.dll NON verrebbe copiato nella cartella di output principale. (Sarebbe copiato nella cartella di output di ProjectX, per renderlo più confuso.)

Quindi, se non stai usando esplicitamente nessuno dei tipi di abc.dll in nessun punto di ProjectX, metti una dichiarazione fittizia da qualche parte in uno dei file in ProjectX.

AbcDll.AnyClass dummy006; // this will be enough to cause the DLL to be copied

Non è necessario eseguire questa operazione per ogni classe: una sola volta sarà sufficiente per far copiare la DLL e tutto funzionerà come previsto.

Addendum: si noti che potrebbe funzionare per la modalità debug, ma NON per il rilascio. Vedi la risposta di @nvirth per i dettagli.


7
Questo sembra un trucco. L'aggiunta del riferimento al progetto principale sembra essere sufficiente.
Mike K

3
È un trucco, ma come ci hanno insegnato le notizie di CodeProject di oggi, anche i compilatori possono sbagliarsi!
Overlord Zurg

4
Come possono essere cose folli. @OverlordZurg la tua soluzione ha funzionato poiché avevo un riferimento alla DLL dipendente nel mio XAML (WPF) e non ha copiato la DLL nel progetto principale fino a quando non ho aggiunto un semplice riferimento fittizio come hai detto ... Grazie comunque
Mohsen Afshin

5
@MohsenAfshin Ho avuto lo stesso problema --- Stavo facendo riferimento a una DLL dipendente in XAML. Invece di dichiarare una variabile fittizia, tuttavia, ho semplicemente chiamato il componente che stavo usando in XAML, e questo è stato sufficiente per far sì che il suo assembly venisse copiato.
redcurry

5
@MikeK L'aggiunta al progetto principale (che in realtà non dipende direttamente da esso) è un hack ancora più grande, imo. Quindi devi gestirlo in due posizioni ("gestisci" come in aggiornamento o rimozione). Con questo trucco, almeno ricevi un bel errore di compilazione che ti ricorda di rimuovere questo trucco quando rimuovi la dipendenza e devi ancora aggiornarlo in un solo posto.
jpmc26,

71

Solo un sidenote alla risposta di Overlord Zurg.

Ho aggiunto il riferimento fittizio in questo modo e ha funzionato in modalità Debug:

public class DummyClass
{
    private static void Dummy()
    {
        var dummy = typeof(AbcDll.AnyClass);
    }
}

Ma in modalità Release, la DLL dipendente non è stata ancora copiata.
Questo ha funzionato comunque:

public class DummyClass
{
    private static void Dummy()
    {
        Action<Type> noop = _ => {};
        var dummy = typeof(AbcDll.AnyClass);
        noop(dummy);
    }
}

Questa informazione in realtà mi è costata ore per capire, quindi ho pensato di condividerla.


7
in modalità di rilascio, l'ottimizzatore presuppone che "dummy" non sia utilizzato, pertanto questa riga non è necessaria e deve essere rimossa. ma quando si utilizza "fittizio" nel codice, l'ottimizzatore non ritiene che non sia necessario.
Yucel,

1
questo non funziona per me.AbcDll.AnyClass non viene ancora copiato in un altro progetto
Matthew Lock

3
Assicurati che AbcDll.AnyClassvenga utilizzato come campo pubblico o proprietà su una classe pubblica, quindi funzionerà. Se lo usi in un metodo come questo, il compilatore non lo vede . Ritarderà il caricamento di questo assembly, non ciò che si desidera che accada.
John Leidegren,

52

Sì, dovrai impostare Copy Localsu true. Tuttavia, sono abbastanza sicuro avrete anche bisogno di riferimento che il montaggio dal progetto principale e insieme Copy Locala truecosì - non solo ottenere copiato da un assembly dipendente.

È possibile accedere alla Copy Localproprietà facendo clic sull'assieme in Referencese premendo F4.


2
@Brij, l'assembly fa riferimento al progetto principale in cui lo desideri? Come ho detto, sono abbastanza sicuro che anche tu debba fare riferimento a quel progetto - gli assiemi dipendenti non vengono copiati in questo modo. In tal caso, non sarà necessario aggiungere gli assiemi a tutti i progetti pertinenti quando si utilizza NuGet.
Mike Perrenoud,

1
qual è stata la conclusione qui? Mi sembra che tu abbia ragione - i riferimenti dipendenti non vengono copiati anche se CopyLocal è impostato su true - qual è la logica alla base di ciò?
mcmillab,

29
@mcmillab, in breve Visual Studio non deduce dipendenze da altri progetti dipendenti. Se il progetto A fa riferimento al progetto B, il progetto A dovrà avere tutti i riferimenti del progetto B. Funziona bene quando tutto il progetto B ha bisogno di assembly .NET, ma se si tratta di un assembly di terze parti è necessario aggiungere il riferimento a entrambi i progetti.
Mike Perrenoud,

12
@MichaelPerrenoud Non penso sia vero. Se guardi un output dettagliato di MSBuild vedrai le chiamate a ResolveAssemblyReference che afferma che "include dipendenze del secondo e dell'ennesimo ordine". Ciò concorda anche con ciò che vedo nelle mie cartelle bin (le dipendenze n-esime vengono copiate). Il problema è che ci sono alcuni avvertimenti su ciò che viene copiato, principalmente attorno a GAC ​​e riferimenti indiretti (Aggiungi riferimento a volte non è abbastanza)
Jack Ukleja,

2
La mia attuale esperienza è che questo funzionerà ad eccezione delle dipendenze "copiate": il progetto A.net fa riferimento a DLL C ++ esterne come file che sono "copia sempre". Riferimenti a Project B.net Progetto A. Alla compilazione, B / Debug include le DLL C ++. Tuttavia, quando creo l'Applicazione X, che fa riferimento al Progetto B, le DLL C ++ a volte vengono copiate (sembra essere solo se faccio una ricostruzione).
Benjol,

34

Sembra liscio quando lo rendi un attributo assembly

[AttributeUsage(AttributeTargets.Assembly)]
public class ForceAssemblyReference: Attribute
{        
    public ForceAssemblyReference(Type forcedType)
    {
        //not sure if these two lines are required since 
        //the type is passed to constructor as parameter, 
        //thus effectively being used
        Action<Type> noop = _ => { };
        noop(forcedType);
    }
}

L'utilizzo sarà:

[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]

Grazie, ma per me questo fa qualcosa solo quando aggiungo l'attributo assembly alla dipendenza (Progetto X), che fa già riferimento a AbcDll.AnyClass. E poi, non fa più del normale, dove copia AbcDll nella directory di output della dipendenza. Non lo copia ancora nell'output del progetto dipendente principale. E non posso aggiungere l'attributo all'assembly dipendente a meno che non aggiunga anche un riferimento a AbcDll. Quando lo faccio, AbcDll viene già copiato senza l'attributo.
JS

25

Ho affrontato questo stesso problema. Informazioni di base: prima della costruzione, avevo aggiunto un nuovo progetto X alla soluzione. Il progetto Y dipendeva dal progetto X e il progetto A, B, C dipendeva dal progetto Y.

Gli errori di compilazione sono stati che non è stato possibile trovare le DLL Progetto A, B, C, Y e X.

La causa principale era che il progetto X di nuova creazione era destinato a .NET 4.5, mentre il resto dei progetti di soluzione era destinato a .NET 4.5.1. Il progetto X non è stato creato impedendo la costruzione del resto dei progetti.

Assicurarsi che qualsiasi progetto appena aggiunto abbia come target la stessa versione .NET del resto della soluzione.


1
I progetti referenziati potrebbero essere una versione precedente di .NET. Sono in grado di fare riferimento a un progetto creato per .NET 4 da un progetto creato per .NET 4.5.
redcurry

18

Non sono sicuro se questo aiuta, ma per me, molte volte faccio riferimento a una DLL (che ovviamente la aggiunge automaticamente alla cartella bin). Tuttavia, quella DLL potrebbe richiedere DLL aggiuntive (a seconda delle funzioni che sto usando). NON voglio fare riferimento a quelli nel mio progetto perché devono semplicemente finire nella stessa cartella della DLL che sto effettivamente utilizzando.

Realizzo questo in Visual Studio "aggiungendo un file esistente". Dovresti essere in grado di aggiungerlo ovunque tranne la cartella Add_data. personalmente l'ho appena aggiunto alla radice.

Quindi modificare le proprietà di quel file in ...

Build Action = None (se impostato su qualcosa come Content, in realtà copia la versione "root" nella radice, più una copia nel Cestino).

Copia nella cartella di output = Copia se più recente (in pratica lo inserisce nella cartella BIN solo se manca, ma non lo fa dopo)

Quando pubblico .. la mia DLL aggiunta esiste solo nella cartella BIN e in nessun altro luogo nella posizione Pubblica (che è quello che voglio).


10

Puoi anche verificare che le DLL che stai cercando non siano incluse nel GAC. Credo che Visual Studio sia intelligente nel non copiare quei file se esiste già nel GAC sulla macchina di compilazione.

Di recente mi sono imbattuto in questa situazione in cui avevo testato un pacchetto SSIS che aveva bisogno di assiemi nel GAC. Da allora l'avevo dimenticato e mi chiedevo perché quelle DLL non uscissero durante una build.

Per controllare cosa c'è nel GAC (da un prompt dei comandi per sviluppatori di Visual Studio):

gacutil -l

O l'output in un file per facilitare la lettura:

gacutil -l > output.txt
notepad.exe output.txt

Per rimuovere un assieme:

gacutil -u MyProjectAssemblyName

Dovrei anche notare che una volta rimossi i file dal GAC, sono stati correttamente emessi nella directory \ bin dopo una compilazione (anche per gli assembly a cui non era stato fatto direttamente riferimento nel progetto root). Questo era su Visual Studio 2013 Update 5.


Grazie, hai ragione, MSBuild non copia la dll nella cartella di output se le trova nel GAC.
John-Philip,

3

Nel mio caso, è stata la cosa più stupida, causata da un comportamento predefinito di TFS / VS con cui non sono d'accordo.

Poiché l'aggiunta della dll come riferimento al progetto principale non ha funzionato, ho deciso di aggiungerla come "elemento esistente", con Copia locale = Sempre. Anche allora il file non c'era.

Si scopre che, anche se il file è presente sulla soluzione VS e tutto compilato sia localmente che sul server, VS / TFS non ha aggiunto effettivamente il file al controllo del codice sorgente. Non è stato incluso nei "Modifiche in sospeso". Ho dovuto andare manualmente a Explorer controllo sorgente e fare esplicito clic sull'icona "Aggiungi elementi alla cartella".

Stupido perché ho sviluppato per 15 anni in VS. Mi sono già imbattuto in questo, non me lo ricordavo e in qualche modo mi mancava perché tutto era ancora compilato perché il file era un riferimento regolare, ma il file aggiunto come elemento esistente non veniva copiato perché non esisteva su il server di controllo del codice sorgente.

Spero che questo salvi qualcuno un po 'di tempo, dal momento che ho perso 2 giorni della mia vita per questo.


1
Non posso ringraziarti abbastanza ... mi hai risparmiato così tanto tempo. Questa è stata la soluzione per me. Ha anche esposto il problema alla radice, la DLL che ho aggiunto come riferimento corrispondeva a un gitignoremodello, quindi quando si aggiungeva come riferimento non si aggiungeva al progetto. DEVI aggiungere manualmente il file al controllo del codice sorgente !!!
Mattkwish,

2

Questa è una leggera modifica dell'esempio di nvirth

internal class DummyClass
{
    private static void Dummy()
    {
        Noop(typeof(AbcDll.AnyClass));
    }
    private static void Noop(Type _) { }
}

2

Lo aggiungerei agli eventi di Postbuild per copiare le librerie necessarie nelle directory di output. Qualcosa come XCopy pathtolibraries targetdirectory

Puoi trovarli nelle proprietà del progetto -> Crea eventi.


Questo ha funzionato per me e penso che questa sia la risposta migliore. La soluzione di riferimento fittizia funziona, ma è un trucco, mentre una regola post-build è un modo chiaro per ottenere lo stesso risultato.
Kevin Fichter

2

Problema:

Si è verificato un problema simile per una DLL del pacchetto NuGet (Newtonsoft.json.dll) in cui l'output di generazione non include la DLL di riferimento. Ma la compilation va bene.

fix:

Esamina i tuoi progetti in un editor di testo e cerca riferimenti con tag in essi contenuti. Come vero o falso. "Privato" è sinonimo di "Copia locale". Da qualche parte nelle azioni, MSBuild sta prendendo per individuare le dipendenze, sta trovando la tua dipendenza da qualche altra parte e sta decidendo di non copiarla.

Quindi, esamina ogni file .csproj / .vbproj e rimuovi i tag manualmente. Ricostruisci e tutto funziona in Visual Studio e MSBuild. Una volta che hai funzionato, puoi tornare indietro e aggiornare il dove pensi che debbano essere.

Riferimento:

https://www.paraesthesia.com/archive/2008/02/13/what-to-do-if-copy-local-works-in-vs-but.aspx/


1

NESSUN BISOGNO DEL MANICHINO IN CODICE
Solo:

aggiungere un riferimento al progetto eseguibile

o / e assicurarsi che il riferimento nel progetto eseguibile sia "Copy Local"impostato su TRUE(che era il mio " errore ") sembra che questo "sovrascritto" l'impostazione nel progetto libreria di riferimento di base ...


1

Se fai clic con il pulsante destro del mouse sull'assieme di riferimento, vedrai una proprietà chiamata Copia locale . Se Copia locale è impostato su true, l'assembly deve essere incluso nel cestino. Tuttavia , sembra che ci sia un problema con Visual Studio, che a volte non include la dll di riferimento nella cartella bin ... questa è la soluzione che ha funzionato per me:

inserisci qui la descrizione dell'immagine


1
Copia Loal è stato disattivato, questo ha aiutato stackoverflow.com/questions/15526491/...
CodeMirror

1

TLDR; Visual Studio 2019 potrebbe richiedere semplicemente un riavvio.

Ho riscontrato questa situazione utilizzando progetti basati sul progetto Microsoft.NET.Sdk.

<Project Sdk="Microsoft.NET.Sdk">

In particolare:

  • Project1: obiettivi .netstandard2.1
    • riferimenti Microsoft.Extensions.Logging.Consolevia Nuget
  • Project2: obiettivi .netstandard2.1
    • riferimenti Project1tramite un riferimento al progetto
  • Project2Tests: obiettivi .netcoreapp3.1
    • riferimenti Project2tramite un riferimento al progetto

Durante l'esecuzione del test, ho ricevuto il messaggio di errore che indicava che Microsoft.Extensions.Logging.Consolenon è stato possibile trovare e che in effetti non si trovava nella directory di output.

Ho deciso di aggirare il problema aggiungendo Microsoft.Extensions.Logging.Consolea Project2, solo per scoprire che Nuget Manager di Visual Studio non era elencato Microsoft.Extensions.Logging.Consolecome installato Project1, nonostante sia presente nel Project1.csprojfile.

Un semplice arresto e riavvio di Visual Studio hanno risolto il problema senza la necessità di aggiungere un riferimento aggiuntivo. Forse questo farà risparmiare a qualcuno 45 minuti di perdita di produttività :-)


In realtà ho riavviato l'intero PC sul mio modo di testare le cose, ma ha funzionato per me
Noman_1

0

È possibile impostare sia il progetto principale che il percorso di output della build di ProjectX sulla stessa cartella, quindi è possibile ottenere tutte le DLL necessarie in quella cartella.


0

Assicurarsi che la DLL dipendente utilizzata dall'utente non abbia un framework .net di destinazione superiore al framework .net di destinazione dell'applicazione del progetto.

Puoi verificarlo selezionando il tuo progetto, quindi premi ALT + INVIO, quindi seleziona Applicazione dal lato sinistro e quindi seleziona Target Framework del tuo progetto.

Supponiamo, dll Target Framework = 4.0 dipendente e Application dll Target Framework = 3.5, quindi cambialo in 4.0

Grazie!


0

Oltre a quelli comuni sopra, avevo una soluzione multi-progetto da pubblicare. Apparentemente alcuni file hanno come target diversi framework.

Quindi la mia soluzione: Proprietà> Versione specifica (Falso)


0

Aggiungi la DLL come elemento esistente a uno dei progetti e dovrebbe essere ordinata


0

VS2019 V16.6.3

Per me il problema era in qualche modo il file .proj principale finito con una voce come questa per il progetto la cui DLL non veniva copiata nella cartella bin del progetto principale:

<ProjectReference Include="Project B.csproj">
  <Project>{blah blah}</Project>
  <Name>Project B</Name>
  <Private>True</Private>
</ProjectReference>

Ho eliminato manualmente la riga <Private>True</Private>e la DLL è stata quindi copiata nella cartella principale del progetto su ogni build del progetto principale.

Se vai al riferimento del progetto problema nella cartella riferimenti del progetto principale, fai clic su di esso e visualizza le proprietà c'è un'impostazione "Copia locale". Il tag privato equivale a questa impostazione, ma per me per qualche motivo la modifica della copia locale non ha avuto alcun effetto sul tag privato nel file .proj.

In modo fastidioso non ho cambiato il valore locale della copia per il riferimento, non ho idea di come sia stato impostato in quel modo e un altro giorno ho sprecato a rintracciare uno stupido problema con VS.

Grazie a tutte le altre risposte che mi hanno aiutato a individuare la causa.

HTH

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.