Zależna biblioteka DLL nie jest kopiowana do folderu wyjściowego kompilacji w programie Visual Studio

188

Mam rozwiązanie do studia wizualnego. W rozwiązaniu mam wiele projektów. Jest jeden główny projekt, który działa jako start-up i wykorzystuje inne projekty. Jest jeden projekt o nazwie „ProjectX”. Jego odniesienie zostało dodane do głównego projektu. ProjectX odwołuje się do innej biblioteki DLL .NET (powiedz abc.dll), która nie jest częścią rozwiązania.

Teraz ten plik abc.dll powinien zostać skopiowany do folderu bin / debugowania głównego projektu, ale nie jest tam kopiowany. Dlaczego nie można go skopiować, z jakichkolwiek znanych przyczyn?

Brij
źródło
jeśli nie możesz tego rozgryźć, skopiuj go do swojego prebuild.
Dilshod
jak używasz swojego „ProjectX” w głównym projekcie - jaki jest typ projektu, cel itp.
NSGaga-głównie-nieaktywny
Miałem ten sam problem i ta odpowiedź rozwiązała mój problem: stackoverflow.com/a/8213977/174469
Gordon Tucker
jest RestoreProjectStyle dostępne rozwiązanie . Chodzi o to, aby ustawić <RestoreProjectStyle>PackageReference</RestoreProjectStyle>dla każdego projektu .Net Framework w rozwiązaniu.
oleksa

Odpowiedzi:

105

Odkryłem, że jeśli ProjectX odwoływał się do pliku abc.dll, ale nie używał bezpośrednio żadnego z typów DEFINED w abc.dll, to plik abc.dll NIE zostałby skopiowany do głównego folderu wyjściowego. (Zostałby skopiowany do folderu wyjściowego ProjectX, aby był bardzo mylący.)

Jeśli więc nie używasz żadnego z typów abc.dll w żadnym miejscu w ProjectX, umieść fałszywą deklarację gdzieś w jednym z plików w ProjectX.

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

Nie musisz tego robić dla każdej klasy - wystarczy jeden raz, aby skopiować plik DLL i wszystko działało zgodnie z oczekiwaniami.

Dodatek: Należy pamiętać, że może to działać w trybie debugowania, ale NIE w przypadku wydania. Szczegółowe informacje można znaleźć w odpowiedzi @ nvirth.

Overlord Zurg
źródło
7
To wygląda na włamanie. Wydaje się, że wystarczy dodać odniesienie do głównego projektu.
Mike K
3
To jest włamanie, ale jak nauczyły nas dzisiejsze wiadomości CodeProject, nawet kompilatory mogą się mylić!
Overlord Zurg
4
Jak szalone mogą być rzeczy. @OverlordZurg twoje rozwiązanie działało, ponieważ miałem odniesienie do zależnej biblioteki DLL w moim XAML (WPF) i nie skopiowało biblioteki DLL do głównego projektu, dopóki nie dodałem prostego odniesienia, jak powiedziałeś ... W każdym razie dzięki
Mohsen Afshin
5
@MohsenAfshin Miałem ten sam problem --- odwoływałem się do zależnej biblioteki DLL w XAML. Zamiast zadeklarować zmienną fikcyjną, po prostu nazwałem komponent, którego używałem w XAML, i to wystarczyło, aby skopiować jego zestaw.
redcurry
5
@MikeK Dodanie go do głównego projektu (który tak naprawdę nie zależy bezpośrednio od niego) to jeszcze większy hack, imo. Następnie musisz zarządzać dwoma miejscami („zarządzaj” jak przy aktualizacji lub usuwaniu). Dzięki temu hackowi przynajmniej dostaniesz ładny błąd czasu kompilacji przypominający o usunięciu tego hacka po usunięciu zależności i nadal musisz go zaktualizować tylko w jednym miejscu.
jpmc26,
71

To tylko sidena na odpowiedź Overlorda Zurga.

W ten sposób dodałem referencyjne atrapę, która działała w trybie debugowania:

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

Ale w trybie Release zależna biblioteka DLL nadal nie została skopiowana.
Działa to jednak:

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

Ta informacja faktycznie kosztowała mnie wiele godzin, więc pomyślałem, że ją podzielę.

nvirth
źródło
7
w trybie zwolnienia optymalizator zakłada, że ​​„fikcyjny” nie jest używany, więc ten wiersz jest niepotrzebny i należy go usunąć. ale kiedy użyjesz „manekina” w kodzie, optymalizator nie zakłada, że ​​jest to niepotrzebne.
Yucel
1
to nie działa dla mnie.AbcDll.AnyClass nadal nie jest kopiowany do innego projektu
Matthew Lock
3
Upewnij się, że AbcDll.AnyClassjest używany jako pole publiczne lub właściwość w klasie publicznej, wtedy będzie działać. Jeśli użyjesz go w treści metody takiej jak ta, kompilator go nie zobaczy . Opóźni to ładowanie tego zestawu, a nie tego, co chcesz się wydarzyć.
John Leidegren
52

Tak, musisz ustawić Copy Localna true. Jednak jestem całkiem pewny, będzie trzeba także odsyłającego wynika, że zespół od głównego projektu oraz zestaw Copy Localdo truejak dobrze - to nie tylko kopiowane z zestawu zależnego.

Możesz dostać się do Copy Localnieruchomości klikając na zespół pod Referencesi naciskając F4.

Mike Perrenoud
źródło
2
@Brij, czy do zestawu odwołuje się główny projekt, w którym chcesz? Jak już wspomniałem, jestem prawie pewien, że musisz odwoływać się do tego projektu, a zestawy zależne nie są kopiowane w ten sposób. W takim przypadku nie trzeba dodawać zestawów do wszystkich odpowiednich projektów podczas korzystania z NuGet.
Mike Perrenoud
1
jaki był tutaj wniosek? Wydaje mi się, że masz rację - referencje zależne nie są kopiowane, nawet jeśli CopyLocal ma wartość true - jaka jest logika tego?
mcmillab
29
@mcmillab, w skrócie Visual Studio nie wywnioskować zależności od innych projektów zależnych. Jeśli projekt A odwołuje się do projektu B, projekt A będzie musiał posiadać wszystkie odniesienia do projektu B. Działa ładnie, gdy cały projekt B potrzebuje zestawów .NET, ale jeśli jest to zestaw zewnętrzny, musisz dodać odwołanie do obu projektów.
Mike Perrenoud
12
@MichaelPerrenoud Nie sądzę, że to prawda. Jeśli spojrzysz na szczegółowe dane wyjściowe MSBuild, zobaczysz wywołania ResolveAssemblyReference, które stwierdzają, że „zawiera zależności drugiego i n-tego rzędu”. To również zgadza się z tym, co widzę w folderach bin (n-te zależności są kopiowane). Problem polega na tym, że istnieją pewne zastrzeżenia dotyczące tego, co jest kopiowane, głównie wokół GAC i referencji pośrednich (Add Reference to czasem za mało)
Jack Ukleja
2
Z mojego obecnego doświadczenia wynika, że ​​będzie to działać z wyjątkiem zależności „skopiowanych”: projekt A.net odwołuje się do zewnętrznych bibliotek dll C ++ jako plików, które są „zawsze kopiuj”. Odniesienia do projektu B.net Projekt A. Po kompilacji B / Debug zawiera biblioteki dll C ++. Jednak podczas tworzenia aplikacji X, która odwołuje się do projektu B, biblioteki dll C ++ czasami są kopiowane (wydaje się, że dzieje się tak tylko wtedy, gdy dokonam przebudowy).
Benjol,
34

Wygląda gładko, gdy stajesz się atrybutem zestawu

[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);
    }
}

Wykorzystanie będzie:

[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]
Aryéh Radlé
źródło
Dziękuję, ale dla mnie działa to tylko wtedy, gdy dodam atrybut assemblacji do zależności (Project X), która już odwołuje się do AbcDll.AnyClass. A potem nie robi więcej niż normalnie, gdzie kopiuje AbcDll do katalogu wyjściowego zależności. Nadal nie kopiuje go do wyniku głównego projektu zależnego. Nie mogę dodać atrybutu do zależnego zestawu, chyba że dodam również odwołanie do AbcDll. Kiedy to robię, AbcDll jest już kopiowane bez atrybutu.
JS
25

Wpadłem na ten sam problem. Informacje podstawowe: przed budowaniem dodałem nowy projekt X do rozwiązania. Projekt Y zależał od Projektu X, a Projekt A, B, C zależał od Projektu Y.

Błędy kompilacji polegały na tym, że nie można było znaleźć bibliotek DLL projektu A, B, C, Y i X.

Główną przyczyną było to, że nowo utworzony Projekt X był ukierunkowany na .NET 4.5, podczas gdy pozostałe projekty rozwiązań były ukierunkowane na .NET 4.5.1. Projekt X nie został skompilowany, co spowodowało, że reszta Projektów również się nie zbudowała.

Upewnij się, że wszystkie nowo dodane projekty są kierowane na tę samą wersję .NET, co reszta rozwiązania.

Darren Alfonso
źródło
1
Referencyjne projekty mogą być starszymi wersjami platformy .NET. Jestem w stanie odwołać się do projektu zbudowanego dla .NET 4 przez projekt zbudowany dla .NET 4.5.
redcurry
18

Nie jestem pewien, czy to pomaga, ale dla mnie wiele razy odwołuje się do biblioteki DLL (która automatycznie dodaje ją do folderu bin). Jednak ta biblioteka DLL może wymagać dodatkowych bibliotek DLL (w zależności od używanych funkcji). NIE chcę odwoływać się do tych w moim projekcie, ponieważ muszą po prostu znaleźć się w tym samym folderze, co biblioteka DLL, której faktycznie używam.

Osiągam to w Visual Studio poprzez „Dodawanie istniejącego pliku”. Powinieneś być w stanie dodać go w dowolnym miejscu oprócz folderu Add_data. osobiście po prostu dodaję to do katalogu głównego.

Następnie zmień właściwości tego pliku na ...

Kompilacja działania = Brak (ustawienie tego na coś takiego jak Treść faktycznie kopiuje wersję „root” do katalogu głównego oraz kopię w Koszu).

Kopiuj do folderu wyjściowego = Kopiuj, jeśli nowszy (Zasadniczo umieszcza go w folderze BIN tylko wtedy, gdy go brakuje, ale nie robi tego później)

Kiedy publikuję ... moje dodane biblioteki DLL istnieją tylko w folderze BIN i nigdzie indziej w lokalizacji Publikuj (to jest to, czego chcę).

da_jokker
źródło
10

Możesz również sprawdzić, czy biblioteki DLL, których szukasz, nie są uwzględnione w GAC. Wierzę, że Visual Studio jest mądry, jeśli chodzi o nie kopiowanie tych plików, jeśli już istnieją w GAC na komputerze kompilacji.

Niedawno uruchomiłem się w tej sytuacji, w której testowałem pakiet SSIS, który potrzebował zespołów w GAC. Odtąd zapomniałem o tym i zastanawiałem się, dlaczego te biblioteki DLL nie wychodziły podczas kompilacji.

Aby sprawdzić, co jest w GAC (z wiersza polecenia Visual Studio Developer Developer):

gacutil -l

Lub wyślij do pliku, aby ułatwić czytanie:

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

Aby usunąć zespół:

gacutil -u MyProjectAssemblyName

Powinienem również zauważyć, że po usunięciu plików z GAC były one poprawnie wyprowadzane do katalogu \ bin po kompilacji (nawet dla zestawów, które nie były bezpośrednio przywoływane w projekcie głównym). Było to w Visual Studio 2013 Update 5.

Brett
źródło
Dzięki, masz rację, MSBuild nie skopiuje dll do folderu wyjściowego, jeśli znalazł je w GAC.
John-Philip
3

W moim przypadku była to najgłupsza rzecz, spowodowana domyślnym zachowaniem TFS / VS, z którym się nie zgadzam.

Ponieważ dodanie dll jako odwołania do głównego projektu nie zadziałało, postanowiłem dodać go jako „istniejący element”, z opcją Kopiuj lokalnie = Zawsze. Nawet wtedy pliku nie było.

Okazuje się, że pomimo tego, że plik jest obecny w VS Solution i wszystko skompilowane zarówno lokalnie, jak i na serwerze, VS / TFS nie dodał tak naprawdę dodania pliku do kontroli źródła. W ogóle nie został uwzględniony w „Oczekujących zmianach”. Musiałem ręcznie przejść do Eksploratora kontroli źródła i wyraźnie kliknąć ikonę „Dodaj elementy do folderu”.

Głupie, bo rozwijam się od 15 lat w VS. Natknąłem się na to wcześniej, po prostu nie pamiętałem i jakoś tęskniłem, ponieważ wszystko wciąż się kompilowało, ponieważ plik jest regularnym odniesieniem, ale plik, który został dodany jako istniejący element, nie był kopiowany, ponieważ nie istniał serwer kontroli źródła.

Mam nadzieję, że zaoszczędzi to komuś trochę czasu, ponieważ straciłem na to 2 dni życia.

GR7
źródło
1
Nie mogę ci wystarczająco podziękować ... tyle zaoszczędziłeś mi czasu. To było dla mnie rozwiązanie. Wystawił również na problem root, biblioteka DLL, którą dodałem jako odniesienie, pasowała do gitignorewzorca, więc podczas dodawania jako odniesienia nie dodała do projektu. MUSISZ ręcznie dodać plik do kontroli źródła !!!
Mattkwish,
2

Jest to drobna poprawka na przykładzie nvirth

internal class DummyClass
{
    private static void Dummy()
    {
        Noop(typeof(AbcDll.AnyClass));
    }
    private static void Noop(Type _) { }
}
maca134
źródło
2

Dodałbym to do zdarzeń Postbuild, aby skopiować niezbędne biblioteki do katalogów wyjściowych. Coś takiego jak katalog ścieżek XCopy

Możesz je znaleźć we właściwościach projektu -> Kompiluj zdarzenia.

Chethan Jain
źródło
To działało dla mnie i myślę, że to lepsza odpowiedź. Sztuczne rozwiązanie odniesienia działa, ale jest to hack, podczas gdy reguła po kompilacji jest czystym sposobem na osiągnięcie tego samego wyniku.
Kevin Fichter
2

Kwestia:

Wystąpił podobny problem z biblioteką DLL pakietu NuGet (Newtonsoft.json.dll), w której dane wyjściowe kompilacji nie zawierają wspomnianej biblioteki DLL. Ale kompilacja idzie dobrze.

Naprawić:

Przejrzyj swoje projekty w edytorze tekstu i poszukaj odniesień z tagami. Jak prawda czy fałsz. „Prywatny” jest synonimem „Kopiuj lokalnie”. Gdzieś w akcjach MSBuild podejmuje się zlokalizowania zależności, znajduje swoją zależność gdzieś indziej i decyduje się jej nie kopiować.

Przejrzyj każdy plik .csproj / .vbproj i usuń tagi ręcznie. Przebuduj, a wszystko działa zarówno w Visual Studio, jak i MSBuild. Gdy już zaczniesz działać, możesz wrócić i zaktualizować miejsce, w którym Twoim zdaniem powinno być.

Odniesienie:

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

Nkl Kumar
źródło
1

NIE JEST POTRZEBNA NA MANEKIN W KODIE
Po prostu:

dodaj odniesienie do projektu wykonywalnego

lub / i upewnij się, że odniesienie w wykonywalnym projekcie zostało "Copy Local"ustawione na TRUE(co było moją „ winą ”), wydaje się, że to „nadpisało” ustawienie w referencyjnym projekcie biblioteki ...

Cadburry
źródło
1

Jeśli klikniesz prawym przyciskiem myszy odnośny zespół, zobaczysz właściwość o nazwie Kopiuj lokalnie . Jeśli opcja Kopiuj lokalnie ma wartość true, zespół powinien zostać dołączony do kosza. Jednak istnieją problemy ze Visual Studio, że czasami nie zawiera odnośnika dll w folderze bin ... jest to obejście, które działało dla mnie:

wprowadź opis zdjęcia tutaj

Hooman Bahreini
źródło
1
Kopiowanie Loal zostało wyłączone, co pomogło stackoverflow.com/questions/15526491/…
codemirror
1

TLDR; Visual Studio 2019 może po prostu wymagać ponownego uruchomienia.

Sytuację tę spotkałem przy użyciu projektów opartych na projekcie Microsoft.NET.Sdk.

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

Konkretnie:

  • Project1: cele .netstandard2.1
    • referencje Microsoft.Extensions.Logging.Consoleza pośrednictwem Nuget
  • Project2: cele .netstandard2.1
    • referencje Project1poprzez referencje projektu
  • Project2Tests: cele .netcoreapp3.1
    • referencje Project2poprzez referencje projektu

Podczas wykonywania testu otrzymałem komunikat o błędzie wskazujący, że Microsoft.Extensions.Logging.Consolenie można go znaleźć, a tak naprawdę nie było w katalogu wyjściowym.

Postanowiłem obejść ten problem, dodając Microsoft.Extensions.Logging.Consoledo Project2, tylko po to , aby odkryć, że Nuget Manager programu Visual Studio nie wyświetlał się Microsoft.Extensions.Logging.Consolejako zainstalowany Project1, pomimo jego obecności w Project1.csprojpliku.

Proste zamknięcie i ponowne uruchomienie Visual Studio rozwiązało problem bez potrzeby dodawania dodatkowego odwołania. Być może pozwoli to zaoszczędzić komuś 45 minut utraconej produktywności :-)

Eric Patrick
źródło
Właściwie zrestartowałem cały komputer w trakcie testowania, ale zadziałało to dla mnie
Noman_1,
0

Możesz ustawić zarówno główny projekt, jak i ścieżkę wyjściową kompilacji ProjectX do tego samego folderu, a następnie możesz pobrać wszystkie potrzebne biblioteki dll w tym folderze.

YantingChen
źródło
0

Upewnij się, że używana przez Ciebie zależna biblioteka DLL nie ma docelowej struktury .net wyższej niż docelowa struktura .net aplikacji twojego projektu.

Możesz to sprawdzić, wybierając projekt, a następnie naciśnij klawisze ALT + ENTER, następnie wybierz opcję Aplikacja z lewej strony, a następnie wybierz opcję Struktura docelowa projektu.

Załóżmy, że zależny dll Target Framework = 4.0 i Application dll Target Framework = 3.5, a następnie zmień to na 4.0

Dziękuję Ci!

Manish Jain
źródło
0

Oprócz powyższych, miałem do opublikowania rozwiązanie obejmujące wiele projektów. Najwyraźniej niektóre pliki są ukierunkowane na różne frameworki.

Więc moje rozwiązanie: Właściwości> Określona wersja (Fałsz)

RicL
źródło
0

Dodaj bibliotekę DLL jako istniejący element do jednego z projektów i powinna zostać posortowana

abhijithkarkal
źródło
0

VS2019 V16.6.3

Dla mnie problem polegał na tym, że główny plik .proj zakończył się takim wpisem dla projektu, którego biblioteka DLL nie była kopiowana do nadrzędnego folderu bin projektu:

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

Ręcznie usunąłem wiersz, <Private>True</Private>a następnie biblioteka DLL została skopiowana do głównego folderu bin projektu przy każdej kompilacji projektu głównego.

Jeśli przejdziesz do odniesienia do projektu powodującego problem w folderze odniesienia głównego projektu, kliknij go i wyświetl właściwości, które zawierają ustawienie „Kopiuj lokalnie”. Znacznik prywatny odpowiada temu ustawieniu, ale dla mnie z jakiegoś powodu zmiana kopiowania lokalnego nie miała wpływu na prywatny znacznik w pliku .proj.

Irytujące nie zmieniłem lokalnej wartości kopii dla odniesienia, nie mam pojęcia, jak to się ustawiło, a kolejny dzień zmarnował śledzenie głupiego problemu z VS.

Dzięki wszystkim pozostałym odpowiedziom, które pomogły mi ustalić przyczynę.

HTH

Richard Moore
źródło