MSBuild ne copie pas les références (fichiers DLL) si vous utilisez des dépendances de projet en solution

j'ai quatre projets dans ma solution de studio visuel (tout le monde cible .NET 3.5) - pour mon problème seulement ces deux sont importants:

  1. MyBaseProject <- cette classe de la bibliothèque de références d'un tiers d'un fichier DLL (elmah.dll)
  2. MyWebProject1 <- ce projet d'application web a une référence à MyBaseProject

j'ai ajouté l'elmah.dll référence à MyBaseProject dans Visual studio 2008 en cliquant sur" Ajouter une référence..."→Onglet "parcourir" → sélectionner le "elmah.DLL."

les propriétés de la référence Elmah sont les suivantes:

  • Alias-global
  • Copie locale - vrai
  • Culture -
  • Description - Modules d'enregistrement des Erreurs et des Gestionnaires (en apparence) pour ASP.NET
  • Type De Fichier - Assemblage
  • Chemin - D:websotherfolder_myPath__toolselmahElmah.dll
  • Résolu-Vrai
  • Exécution de la version v2.0.50727
  • version spécifiée-false
  • nom fort-faux
  • Version-1.0.11211.0

dans MyWebProject1 j'ai ajouté la référence au projet Mybaseprojet par: "Ajouter une référence..."→Onglet" Projets "→ sélectionner le"projet de Mybas". Les propriétés de cette référence sont les mêmes à l'exception des membres suivants:

  • Description -
  • Chemin - D:websCMSMyBaseProjectbinDebugMyBaseProject.dll
  • de la Version 1.0.0.0

Si je lance le construire en Visual Studio la elmah.le fichier dll est copié sur mon Le répertoire bin de MyWebProject1 , ainsi que le projet Mybas.dll!

cependant si je nettoie et exécute MSBuild pour la solution (via D:websCMS> C:WINDOWSMicrosoft.NETFrameworkv3.5MSBuild.exe / t: ReBuild / p:Configuration=Debug MyProject.la sln) l'elmah .dll est manquant dans le répertoire bin de MyWebProject1 - bien que la construction elle-même ne contient aucun avertissement ou des erreurs!

j'ai déjà fait en sorte que le .csproj de MyBaseProject contient le privé élément avec la valeur "true" (qui devrait être un alias pour " copie locale " dans Visual Studio):

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

(Le privé balise ne figure pas dans la .le xml de csproj par défaut, bien que Visual Studio ait dit" copier local " vrai. Je suis passé de "copie locale" faux - sauvé - et la définir à vrai nouveau - enregistrer!)

Qu'est-ce qui ne va pas avec MSBuild? Comment faire Je reçois le elmah.dll) référence copiée sur le bin de MyWebProject1?

Je ne veux pas ajouter une action de copie postbuild à la commande postbuild de chaque projet! (Imaginez que de nombreux projets dépendent de Mybaseprojet!)

247
demandé sur Peter Mortensen 2009-07-15 19:46:08

17 réponses

Je ne sais pas pourquoi C'est différent quand on construit entre Visual Studio et MsBuild, Mais voici ce que j'ai trouvé quand j'ai rencontré ce problème dans MsBuild et Visual Studio.

explication

pour un exemple de scénario, supposons que nous ayons le projet X, l'assemblage A et l'assemblage B. L'assemblage a fait référence à l'assemblage b, donc le projet X comprend une référence à la fois à A et à B. En outre, le projet X comprend un code qui fait référence à l'assemblage A (par exemple: A. SomeFunction ()). Maintenant, vous créez un nouveau projet Y qui fait référence au projet X.

ainsi la chaîne de dépendances ressemble à ceci: Y = > X => A => B

Visual Studio / MSBuild essaie d'être intelligent et de ne faire entrer dans le projet Y que les références qu'il détecte comme étant requises par le projet X; il le fait pour éviter la pollution de référence dans le projet Y. Le problème est que le projet X ne contient pas de code qui utilise explicitement assembly B (e.g. B. SomeFunction ()), VS/MSBuild ne détecte pas que B est requis par X, et ne le Copie donc pas dans le répertoire bin du projet Y; il ne copie que les assemblages X et A.

Solution

vous avez deux options pour résoudre ce problème, les deux qui aboutiront à l'assemblage B étant copié dans le répertoire bin du projet Y:

  1. ajouter une référence à l'assemblage B dans le projet Y.
  2. ajouter code fictif d'un fichier du projet X qui utilise l'assemblage B.

personnellement, je préfère l'option 2 pour deux raisons.

  1. si vous ajoutez à l'avenir un autre projet qui fait référence au Projet X, vous n'aurez pas à vous rappeler d'inclure également une référence à assembly B (comme vous auriez à faire avec l'option 1).
  2. vous pouvez avoir des commentaires explicites disant Pourquoi le code fictif doit être là et non pas l'enlever. Si si quelqu'un supprime le code par accident (par exemple avec un outil refactor qui recherche le code inutilisé), vous pouvez facilement voir du contrôle source que le code est nécessaire et de le restaurer. Si vous utilisez l'option 1 et que quelqu'un utilise un outil refactor pour nettoyer les références inutilisées, vous n'avez aucun commentaire; vous verrez juste qu'une référence a été retirée de la .fichier csproj.

voici un échantillon du "code fictif" que j'ajoute typiquement quand je rencontre ce situation.

    // 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);
    }
134
répondu deadlydog 2016-01-19 16:37:09

Je m'en occupe comme ça. Allez aux propriétés de votre référence et faites ceci:

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

et c'est tout.

Visual Studio 2010 ne met pas initialement: <private>True</private> dans la balise de référence et le paramètre" copier local " à false provoque la création de la balise. Ensuite, il le mettra à vrai et à faux en conséquence.

160
répondu andrew 2011-10-21 23:54:33

si vous n'utilisez pas L'assemblage directement en code, Visual Studio détecte qu'il n'est pas utilisé et ne l'inclut pas dans la sortie. Je ne sais pas pourquoi vous voyez un comportement différent entre Visual Studio et MSBuild. Vous pouvez essayer de définir la sortie de construction de diagnostic pour les deux et comparer les résultats voir où il diverge.

quant à votre elmah.dll référence si vous n'êtes pas référence directement dans le code, vous pourriez l'ajouter comme élément de votre projet et définir L'action de construction à Content et la copie dans le répertoire de sortie à Always .

38
répondu John Hunter 2017-01-20 17:58:18

regardez:

ce fil MSBuild forum j'ai commencé

vous trouverez ma solution temporaire / contourner là!

(MyBaseProject besoins du code qui fait référence à certaines classes (quoi que) le elmah.dll pour elmah.dll étant copié à la bin de MyWebProject1!)

14
répondu toebens 2017-01-20 17:57:19

j'ai eu le même problème.

vérifiez si la version framework de votre projet est la même que la version framework de la dll que vous mettez en référence.

dans mon cas, mon client a été compilé en utilisant" Framework 4 Client "et la DLL était dans"Framework 4".

8
répondu Andre Avelar 2012-06-25 08:22:42

la question à laquelle je faisais face était que j'ai un projet qui dépend d'un projet de bibliothèque. Pour construire, j'ai suivi ces étapes:

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

cela signifiait bien sûr que je manquais les fichiers dll de ma bibliothèque dans bin et surtout dans le fichier zip du paquet. J'ai trouvé cela fonctionne parfaitement:

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

Je n'ai aucune idée pourquoi cela fonctionne ou pourquoi il n'a pas en premier lieu. Mais l'espoir qui aide.

6
répondu vangorra 2012-07-18 22:49:52

comme Alex Burtsev a mentionné dans un commentaire Tout ce qui est seulement utilisé dans un dictionnaire de ressources XAML, ou dans mon cas, tout ce qui est seulement utilisé dans XAML et pas dans le code derrière, n'est pas considéré comme étant "en usage" par MSBuild.

donc simplement Nouveau-ing une référence factice à une classe/composant dans l'assemblage dans un certain code derrière était assez convaincre MSBuild que l'assemblage était effectivement en usage.

4
répondu Scott 2017-01-20 18:01:56

changer le cadre cible de . cadre de réseau 4 Profil du Client à . cadre de réseau 4 a corrigé ce problème pour moi.

ainsi dans votre exemple: définissez le cadre cible sur MyWebProject1 à . cadre net 4

3
répondu Fuyu Persimmon 2013-08-02 19:20:50

je viens d'avoir le même problème et il s'est avéré être causé par le fait que 2 projets dans la même solution référençaient une version différente de la bibliothèque de tierce partie.

une fois que j'ai corrigé toutes les références, tout a parfaitement fonctionné.

3
répondu Steven Engels 2014-02-12 15:24:53

j'ai eu le même problème et la dll était une référence chargée dynamiquement. Pour résoudre le problème, j'ai ajouté un "utiliser" avec l'Espace-nom de la dll. Maintenant la dll est copiée dans le dossier de sortie.

2
répondu Spamme 2012-06-27 09:39:57

cela nécessite d'ajouter un fichier .targets à votre projet et de le configurer pour qu'il soit inclus dans la section includes du projet.

Voir ma réponse ici pour la procédure.

2
répondu Alex Essilfie 2017-05-23 11:54:44
Les ensembles de référence

qui ne sont pas utilisés pendant la construction ne sont pas la bonne pratique. Vous devez augmenter votre fichier de construction pour qu'il copie les fichiers supplémentaires. Soit en utilisant un événement post build, soit en mettant à jour le groupe de propriétés.

Quelques exemples peuvent être trouvés dans d'autres post

2
répondu verbedr 2017-05-23 12:10:36

à l'Aide de deadlydog du régime,

Y = > X => A => B ,

mon problème était que lorsque j'ai construit Y, les assemblages (A et B, Tous les 15 d'entre eux) de X n'étaient pas présents dans le dossier de la corbeille de Y.

j'ai résolu le problème en retirant la référence X de Y, enregistrer, construire, puis ajouter de nouveau la référence X (une référence de projet), et enregistrer, construire, et A et B ont commencé à apparaître dans le dossier bin de Y.

2
répondu J Z 2016-12-08 20:39:56

un autre scénario où cela apparaît est si vous utilisez l'ancien type de projet" Site web " dans Visual Studio. Pour ce type de projet, il est incapable de référence .dlls qui sont en dehors de sa propre structure de répertoire (répertoire courant et en bas). Ainsi, dans la réponse ci-dessus, disons que la structure de votre répertoire ressemble à ceci:

enter image description here

où ProjectX et ProjectY sont des répertoires parent / enfant, références des projets A.dll qui à son tour fait référence B.dll, et B.dll est en dehors de la structure du répertoire, comme dans un paquet Nuget sur la racine (paquets), puis A.dll sera inclus, mais B.dll Non.

2
répondu Focker 2017-03-20 18:19:29

je viens de rencontrer un problème très similaire. Lors de la compilation en utilisant Visual Studio 2010, le fichier DLL a été inclus dans le dossier bin . Mais lors de la compilation en utilisant MSBuild le fichier DLL tiers n'a pas été inclus.

très frustrant. La façon dont je l'ai résolu était d'inclure la NuGet référence au paquet dans mon projet web même si Je ne l'utilise pas directement là.

0
répondu Gary Brunton 2017-01-20 18:00:51

j'ai eu un problème similaire aujourd'hui, et ce n'est certainement pas la réponse à votre question. Mais j'aimerais informer tout le monde, et peut-être fournir une étincelle de perspicacité.

j'ai un ASP.NET application. Le processus de construction est réglé pour nettoyer puis construire.

j'ai deux Jenkins CI scripts. Une pour la production et une pour la mise en scène. J'ai déployé ma demande de mise en scène et tout a fonctionné fin. Déployé à la production et manquait un fichier DLL qui a été référencé. Ce fichier DLL était juste à la racine du projet. Pas dans un dépôt NuGet. La DLL a été fixée à do not copy .

le script CI et l'application étaient les mêmes entre les deux déploiements. Toujours après le nettoyage et le déploiement dans l'environnement de mise en scène le fichier DLL a été remplacé dans le lieu de déploiement de la ASP.NET application ( bin/ ). Ce n'était pas le cas pour la production environnement.

il s'avère dans une branche de test que j'avais ajouté une étape au processus de construction pour copier ce fichier DLL dans le répertoire bin . Maintenant, la partie qui a pris un peu de temps à comprendre. Le processus D'assurance-récolte ne se nettoyait pas tout seul. La DLL a été laissée dans le répertoire de travail et était emballée accidentellement avec le ASP.NET .fichier zip. La branche de production n'a jamais eu le fichier DLL copié de la même façon et n'a jamais accidentellement déployé ceci.

TLDR; Vérifiez et assurez-vous de savoir ce que fait votre serveur de compilation.

0
répondu Jason Portnoy 2017-01-20 18:06:05

, y Compris toutes référencées fichiers DLL à partir de votre projectreferences dans le projet de Site web n'est pas toujours une bonne idée, surtout lorsque vous êtes à l'aide de l'injection de dépendance : votre projet web voulez juste ajouter une référence à la DLL d'interface fichier/projet, et non la mise en œuvre concrète de fichier DLL.

parce que si vous ajoutez une référence directement à un fichier/projet DLL de mise en œuvre, vous ne pouvez pas empêcher votre développeur d'appeler un "nouveau" sur des classes concrètes de L'implémentation DLL fichier/projet au lieu de via l'interface. C'est aussi vous avez indiqué un "hardcode" dans votre site web pour utiliser l'implémentation.

-3
répondu Hung Nguyen 2017-01-20 18:03:31