La DLL dépendante n'est pas copiée dans le dossier de sortie de génération dans Visual Studio

188

J'ai une solution de studio visuel. J'ai de nombreux projets dans la solution. Il y a un projet principal qui sert de start-up et utilise d'autres projets. Il y a un projet dit "ProjectX". Sa référence est ajoutée au projet principal. ProjectX fait référence à une autre dll .NET (disons abc.dll) qui ne fait pas partie de la solution.

Maintenant, ce abc.dll doit être copié dans le dossier bin / debug du projet principal, mais il n'y est pas copié. Pourquoi n'est-il pas copié, pour des raisons connues?

Brij
la source
si vous ne pouvez pas le comprendre, copiez-le dans votre préconstruction.
Dilshod
comment utilisez-vous votre 'ProjectX' dans le projet principal - quel est le type de projet, la cible, etc.
NSGaga-most-inactive
J'ai eu le même problème et cette réponse a résolu mon problème: stackoverflow.com/a/8213977/174469
Gordon Tucker
il existe une RestoreProjectStyle solution disponible . L'idée est de définir <RestoreProjectStyle>PackageReference</RestoreProjectStyle>pour chaque projet .Net Framework de la solution.
oleksa

Réponses:

105

J'ai trouvé que si ProjectX faisait référence à l'abc.dll mais n'utilisait directement aucun des types DEFINIS dans abc.dll, alors abc.dll ne serait PAS copié dans le dossier de sortie principal. (Il serait copié dans le dossier de sortie de ProjectX, pour le rendre encore plus déroutant.)

Donc, si vous n'utilisez explicitement aucun des types de abc.dll n'importe où dans ProjectX, placez une déclaration factice quelque part dans l'un des fichiers de ProjectX.

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

Vous n'avez pas besoin de le faire pour chaque classe - une seule fois suffira pour que la copie DLL et tout fonctionne comme prévu.

Addendum: Notez que cela peut fonctionner pour le mode de débogage, mais PAS pour la version. Voir la réponse de @ nvirth pour plus de détails.

Overlord Zurg
la source
7
Cela ressemble à un hack. L'ajout de la référence au projet principal semble être suffisant.
Mike K
3
C'est un hack, mais comme les nouvelles de CodeProject nous l'ont appris, même les compilateurs peuvent se tromper!
Overlord Zurg
4
Comme les choses peuvent être folles. @OverlordZurg votre solution a fonctionné car j'avais une référence à la dll dépendante dans mon XAML (WPF) et elle n'a pas copié la DLL dans le projet principal jusqu'à ce que j'ajoute une simple référence factice comme vous l'avez dit ... Merci quand même
Mohsen Afshin
5
@MohsenAfshin J'ai eu le même problème --- je faisais référence à une DLL dépendante en XAML. Au lieu de déclarer une variable factice, cependant, j'ai simplement nommé le composant que j'utilisais en XAML, ce qui était suffisant pour que son assembly soit copié.
redcurry
5
@MikeK L'ajouter au projet principal (qui ne dépend pas directement de lui) est un hack encore plus grand, imo. Ensuite, vous devez le gérer à deux endroits («gérer» comme en mise à jour ou en retrait). Avec ce hack, au moins vous obtenez une belle erreur de compilation vous rappelant de supprimer ce hack lorsque vous supprimez la dépendance, et vous n'avez toujours besoin de le mettre à jour qu'à un seul endroit.
jpmc26
71

Juste un commentaire sur la réponse d'Overlord Zurg.

J'ai ajouté la référence factice de cette façon, et cela a fonctionné en mode débogage:

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

Mais en mode Release, la DLL dépendante n'a toujours pas été copiée.
Cela a fonctionné cependant:

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

Cette information m'a en fait coûté des heures à comprendre, alors j'ai pensé la partager.

nvirth
la source
7
en mode release, l'optimiseur suppose que "factice" n'est pas utilisé, donc cette ligne est inutile et doit être supprimée. mais lorsque vous utilisez "factice" dans le code, l'optimiseur ne suppose pas que ce soit inutile.
Yucel
1
cela ne fonctionne pas pour moi.AbcDll.AnyClass n'est toujours pas copié dans un autre projet
Matthew Lock
3
Assurez-vous qu'il AbcDll.AnyClassest utilisé comme un champ public ou une propriété sur une classe publique, alors cela fonctionnera. Si vous l'utilisez dans un corps de méthode comme celui-ci, le compilateur ne le voit pas . Cela retardera le chargement de cet assemblage, pas ce que vous voulez.
John Leidegren
52

Oui, vous devrez définir Copy Localsur true. Cependant, je suis à peu près sûr que vous devrez également référencer cet assemblage à partir du projet principal et définir Copy Localsurtrue aussi bien - il ne sont pas simplement copiés à partir d' un assemblage dépendant.

Vous pouvez accéder à la Copy Localpropriété en cliquant sur l'assemblage sous Referenceset en appuyant sur F4.

Mike Perrenoud
la source
2
@Brij, l'assembly est-il référencé à partir du projet principal dans lequel vous le souhaitez? Comme je l'ai dit, je suis à peu près sûr que vous devez également faire référence à ce projet - les assemblys dépendants ne sont pas copiés comme ça. Si tel était le cas, vous n'auriez pas besoin d'ajouter les assemblys à tous les projets pertinents lors de l'utilisation de NuGet.
Mike Perrenoud
1
quelle était la conclusion ici? Il me semble que vous avez raison - les références dépendantes ne sont pas copiées même si CopyLocal est défini sur true - quelle est la logique derrière cela?
mcmillab
29
@mcmillab, bref Visual Studio ne déduisent les dépendances d'autres projets dépendants. Si le projet A fait référence au projet B, le projet A devra avoir toutes les références du projet B. Cela fonctionne bien lorsque tous les besoins du projet B sont des assemblys .NET, mais s'il s'agit d'un assembly tiers, vous devez ajouter la référence aux deux projets.
Mike Perrenoud
12
@MichaelPerrenoud Je ne pense pas que ce soit vrai. Si vous regardez une sortie MSBuild détaillée, vous verrez des appels à ResolveAssemblyReference qui indique qu'il "inclut les dépendances de deuxième et de nième ordre". Cela concorde également avec ce que je vois dans mes dossiers bin (les n-ièmes dépendances sont copiées). Le problème est qu'il y a quelques mises en garde sur ce qui est copié, principalement autour du GAC et des références indirectes (ajouter une référence n'est parfois pas suffisant)
Jack Ukleja
2
Mon expérience actuelle est que cela fonctionnera sauf pour les dépendances «copiées»: le projet A.net fait référence aux DLL C ++ externes comme des fichiers qui sont «toujours copiés». Project B.net fait référence au projet A. Lors de la génération, B / Debug inclut les DLL C ++. Cependant, lorsque je construis l'application X, qui fait référence au projet B, les dll C ++ sont parfois copiées (cela semble être le cas uniquement si je fais une reconstruction).
Benjol
34

Il a l'air élégant lorsque vous en faites un attribut d'assemblage

[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'utilisation sera:

[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]
Aryéh Radlé
la source
Merci, mais pour moi, cela ne fait quelque chose que lorsque j'ajoute l'attribut assembly à la dépendance (Projet X), qui fait déjà référence à AbcDll.AnyClass. Et puis, il ne fait pas plus que normalement, où il copie l'AbcDll dans le répertoire de sortie de la dépendance. Il ne le copie toujours pas dans la sortie du projet dépendant principal. Et je ne peux pas ajouter l'attribut à l'assembly dépendant à moins que j'ajoute également une référence à AbcDll. Quand je fais cela, AbcDll est déjà copié sans l'attribut.
JS
25

Ran dans ce même problème. Informations de fond: avant de construire, j'avais ajouté un nouveau Project X à la solution. Le projet Y dépendait du projet X et le projet A, B, C dépendait du projet Y.

Les erreurs de construction étaient que les DLL du projet A, B, C, Y et X étaient introuvables.

La cause première était que le projet X nouvellement créé ciblait .NET 4.5 tandis que le reste des projets de solution ciblait .NET 4.5.1. Le projet X n'a ​​pas été construit, ce qui a empêché le reste des projets de se construire.

Assurez-vous que tous les projets nouvellement ajoutés ciblent la même version .NET que le reste de la solution.

Darren Alfonso
la source
1
Les projets référencés peuvent être une ancienne version de .NET. Je peux référencer un projet construit pour .NET 4 par un projet construit pour .NET 4.5.
redcurry
18

Je ne sais pas si cela aide, mais pour moi, je référence souvent une DLL (qui l'ajoute automatiquement au dossier bin bien sûr). Cependant, cette DLL peut avoir besoin de DLL supplémentaires (en fonction des fonctions que j'utilise). Je ne veux PAS faire référence à ceux-ci dans mon projet car ils doivent simplement se retrouver dans le même dossier que la DLL que j'utilise réellement.

J'accomplis cela dans Visual Studio en «ajoutant un fichier existant». Vous devriez pouvoir l'ajouter n'importe où sauf dans le dossier Add_data. personnellement, je l'ajoute simplement à la racine.

Puis changez les propriétés de ce fichier en ...

Build Action = None (avoir cette valeur à quelque chose comme Content copie en fait la version "root" à la racine, plus une copie dans le Bin).

Copier dans le dossier de sortie = Copier si plus récent (le met essentiellement dans le dossier BIN uniquement s'il manque, mais ne le fait pas après cela)

Quand je publie .. mes DLL ajoutées existent uniquement dans le dossier BIN et nulle part ailleurs dans l'emplacement de publication (ce que je veux).

da_jokker
la source
10

Vous pouvez également vérifier que les DLL que vous recherchez ne sont pas incluses dans le GAC. Je pense que Visual Studio est intelligent pour ne pas copier ces fichiers s'ils existent déjà dans le GAC sur la machine de génération.

J'ai récemment couru dans cette situation où j'avais testé un package SSIS qui avait besoin d'assemblys pour exister dans le GAC. J'avais oublié cela depuis et je me demandais pourquoi ces DLL ne sortaient pas pendant une construction.

Pour vérifier ce qu'il y a dans le GAC (à partir d'une invite de commande de développeur Visual Studio):

gacutil -l

Ou sortie dans un fichier pour en faciliter la lecture:

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

Pour supprimer un assemblage:

gacutil -u MyProjectAssemblyName

Je dois également noter qu'une fois que j'ai supprimé les fichiers du GAC, ils étaient correctement sortis dans le répertoire \ bin après une construction (même pour les assemblys qui n'étaient pas directement référencés dans le projet racine). C'était sur Visual Studio 2013 Update 5.

Brett
la source
Merci, vous avez raison, MSBuild ne copiera pas les dll dans le dossier de sortie s'il les trouve dans le GAC.
John-Philip
3

Dans mon cas, c'était la chose la plus stupide, causée par un comportement par défaut de TFS / VS avec lequel je ne suis pas d'accord.

Puisque l'ajout de la dll comme référence au projet principal n'a pas fonctionné, j'ai décidé de l'ajouter en tant qu '"élément existant", avec Copier local = Toujours. Même alors, le fichier n'était pas là.

Il s'avère que, même si le fichier est présent sur la solution VS et que tout est compilé à la fois localement et sur le serveur, VS / TFS n'a pas ajouté réellement le fichier au contrôle de code source. Il n'était pas du tout inclus dans les "Modifications en attente". J'ai dû accéder manuellement à l'explorateur de contrôle de source et cliquer explicitement sur l'icône «Ajouter des éléments au dossier».

Stupide car je développe depuis 15 ans en VS. J'ai déjà rencontré cela auparavant, je ne m'en souvenais tout simplement pas et je l'ai manqué parce que tout était encore compilé parce que le fichier était une référence régulière, mais le fichier qui a été ajouté en tant qu'élément existant n'était pas copié car il n'existait pas sur le serveur de contrôle de source.

J'espère que cela fera gagner du temps à quelqu'un, car j'ai perdu 2 jours de ma vie à cause de cela.

GR7
la source
1
Je ne saurais trop vous remercier ... vous m'avez fait gagner beaucoup de temps. C'était une solution pour moi. Il a également exposé le problème de racine, la DLL que j'ai ajoutée comme référence correspondait à un gitignoremodèle, donc lors de l'ajout comme référence, elle n'a pas été ajoutée au projet. Vous DEVEZ ajouter manuellement le fichier au contrôle de source !!!
Mattkwish
2

Ceci est une légère modification de l'exemple de nvirth

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

Je l'ajouterais aux événements Postbuild pour copier les bibliothèques nécessaires dans les répertoires de sortie. Quelque chose comme XCopy pathtolibraries targetdirectory

Vous pouvez les trouver sur les propriétés du projet -> Créer des événements.

chethan jain
la source
Cela a fonctionné pour moi, et je pense que c'est la meilleure réponse. La solution de référence factice fonctionne, mais c'est un hack, alors qu'une règle post-build est un moyen propre d'obtenir le même résultat.
Kevin Fichter
2

Problème:

Rencontré avec un problème similaire pour une DLL de package NuGet (Newtonsoft.json.dll) où la sortie de génération n'inclut pas la DLL référencée. Mais la compilation se déroule bien.

Réparer:

Parcourez vos projets dans un éditeur de texte et recherchez des références contenant des balises. Comme vrai ou faux. «Privé» est synonyme de «Copier local». Quelque part dans les actions, MSBuild prend pour localiser les dépendances, il trouve votre dépendance ailleurs et décide de ne pas la copier.

Alors, parcourez chaque fichier .csproj / .vbproj et supprimez les balises manuellement. Reconstruisez et tout fonctionne à la fois dans Visual Studio et MSBuild. Une fois que cela fonctionne, vous pouvez revenir et mettre à jour le où vous pensez qu'il doit être.

Référence:

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

Nkl Kumar
la source
1

PAS BESOIN DE DUMMY DANS LE CODE
Juste:

ajouter une référence au projet exécutable

ou / et assurez-vous que la référence dans le projet exécutable est "Copy Local"définie sur TRUE(ce qui était ma " faute ") semble que cela "écrase" le paramètre dans le projet de bibliothèque référencé de base ...

Cadburry
la source
1

Si vous cliquez avec le bouton droit sur l'assemblage référencé, vous verrez une propriété appelée Copier local . Si Copy Local est défini sur true, l'assembly doit être inclus dans le bac. Cependant , il semble y avoir un problème avec Visual studio, car parfois il n'inclut pas la dll référencée dans le dossier bin ... c'est la solution de contournement qui a fonctionné pour moi:

entrez la description de l'image ici

Hooman Bahreini
la source
1
La copie Loal a été désactivée, cela a aidé stackoverflow.com/questions/15526491/…
codemirror
1

TLDR; Visual Studio 2019 peut simplement avoir besoin d'un redémarrage.

J'ai rencontré cette situation en utilisant des projets basés sur le projet Microsoft.NET.Sdk.

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

Plus précisément:

  • Project1: cibles .netstandard2.1
    • références Microsoft.Extensions.Logging.Consolevia Nuget
  • Project2: cibles .netstandard2.1
    • références Project1via une référence de projet
  • Project2Tests: cibles .netcoreapp3.1
    • références Project2via une référence de projet

Lors de l'exécution du test, j'ai reçu le message d'erreur indiquant que Microsoft.Extensions.Logging.Consolecela ne pouvait pas être trouvé, et ce n'était en effet pas dans le répertoire de sortie.

J'ai décidé de contourner le problème en ajoutant Microsoft.Extensions.Logging.Consoleà Project2, uniquement pour découvrir que Nuget Manager de Visual Studio n'était pas répertorié Microsoft.Extensions.Logging.Consolecomme installé dans Project1, malgré sa présence dans le Project1.csprojfichier.

Un simple arrêt et redémarrage de Visual Studio a résolu le problème sans qu'il soit nécessaire d'ajouter une référence supplémentaire. Peut-être que cela permettra à quelqu'un d'économiser 45 minutes de perte de productivité :-)

Eric Patrick
la source
En fait, j'ai redémarré tout le PC pour tester les choses, mais cela a fonctionné pour moi
Noman_1
0

Vous pouvez définir à la fois le projet principal et le chemin de sortie de construction de ProjectX dans le même dossier, puis vous pouvez obtenir toutes les dll dont vous avez besoin dans ce dossier.

YantingChen
la source
0

Assurez-vous que la dll dépendante que vous utilisez n'a pas de framework .net cible supérieur au framework .net cible de l'application de votre projet.

Vous pouvez vérifier cela en sélectionnant votre projet, puis appuyez sur ALT + ENTRÉE, puis sélectionnez Application sur le côté gauche, puis sélectionnez Cadre cible de votre projet.

Supposons que le Framework cible de la DLL dépendante = 4.0 et le Framework cible de la DLL d'application = 3.5, changez-le en 4.0

Je vous remercie!

Manish Jain
la source
0

Outre les plus courantes ci-dessus, j'avais une solution multi-projets à publier. Apparemment, certains fichiers ciblent différents frameworks.

Donc ma solution: Propriétés> Version spécifique (Faux)

RicL
la source
0

Ajoutez la DLL en tant qu'élément existant à l'un des projets et elle doit être triée

abhijithkarkal
la source
0

VS2019 V16.6.3

Pour moi, le problème était que le fichier .proj principal se terminait par une entrée comme celle-ci pour le projet dont la DLL n'était pas copiée dans le dossier bin du projet parent:

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

J'ai supprimé manuellement la ligne <Private>True</Private> et la DLL a ensuite été copiée dans le dossier bin principal du projet sur chaque version du projet principal.

Si vous accédez à la référence du projet problématique dans le dossier des références du projet principal, cliquez dessus et affichez les propriétés, il existe un paramètre "Copier local". La balise privée équivaut à ce paramètre, mais pour moi, pour une raison quelconque, la modification de la copie locale n'a eu aucun effet sur la balise privée dans le fichier .proj.

Malheureusement, je n'ai pas changé la valeur locale de copie pour la référence, aucune idée de la façon dont elle a été définie de cette façon et une autre journée perdue à traquer un problème stupide avec VS.

Merci à toutes les autres réponses qui m'ont aidé à me concentrer sur la cause.

HTH

Richard Moore
la source