Condividi tramite


How to have a Project Reference without referencing the actual binary

Sometimes you want a project reference from project B to project A to indicate a build-time dependency, but you don’t actually want assembly B to reference assembly A (maybe because it’s a runtime-only dependency or loaded using reflection). Having a project reference is beneficial because you indicate to the build system that in order to have B fully built you also need to build (and possibly deploy) A as well. You could use Visual Studio Configuration Manager dialog to declare the dependency between projects in the .sln file, but don’t. Configuration Manager is a foreign concept in MSBuild, it’s a legacy feature that shouldn’t exist.

Instead, on your project reference in the .csproj file, set the ReferenceOutputAssembly metadata:

     <ProjectReference Include="..\ProjectA\ProjectA.csproj">
      <Project>{b402782f-de0a-41fa-b364-60612a786fb2}</Project>
      <Name>ProjectA</Name>
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
    </ProjectReference>

This will indicate a dependency between projects to MSBuild, but won’t pass the output assembly of ProjectA as a reference to the compiler when compiling ProjectB.

If you set ReferenceOutputAssembly to false you will notice that MSBuild stops copying the assembly A into the output directory for assembly B. If you would still like to copy assembly A to the output of assembly B (without referencing it), use this:

     <ProjectReference Include="..\ProjectA\ProjectA.csproj">
      <Project>{b402782f-de0a-41fa-b364-60612a786fb2}</Project>
      <Name>ProjectA</Name>
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
      <OutputItemType>Content</OutputItemType>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </ProjectReference>

This will produce an item of type Content in project B that includes the output assembly of project A, and the CopyToOutputDirectory metadata on that item will be set to Copy If Newer. This achieves copying a dependency without referencing it.

Update: many people have asked how to also copy the .pdb file in addition to the .exe/.dll. Turns out there is a trick, but it doesn’t work when building in VS. But it’s OK since you don’t really need the .pdb in VS anyway, since the debugger will find the .pdb at its original path anyway.

Add this line to the project reference to also copy the .pdb:

     <ProjectReference Include="..\ProjectA\ProjectA.csproj">
      <Project>{b402782f-de0a-41fa-b364-60612a786fb2}</Project>
      <Name>ProjectA</Name>
      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
      <OutputItemType>Content</OutputItemType>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <Targets>Build;DebugSymbolsProjectOutputGroup</Targets> 
    </ProjectReference>

Comments

  • Anonymous
    April 04, 2015
    Hello Kirill! Would you be so kind to tell us how to setup solution to build libraries with circular references? Say assembly A refers to B and B refers A at same time. Example : A - logging subsystem and it refers DAL to store logs, B is a DAL and of course it is using logging. In .Net framework class library there are some cases where such circular references exist, so Microsoft using it internally, but Visual Studio refuse to add reference in such case. I've heard it can be done with something called "temporary metadata only" assemblies. Please clarify and suggest. Thanks

  • Anonymous
    April 05, 2015
    Unfortunately I have never done this myself so I can only imagine how it can work. You need to compile your first assembly, put the dll in a References folder, then reference the dll from second project, compile that, put that dll also in the references folder, then open the first project again and add a reference to the second dll. But really, don't do that. Instead, split your logging assembly into two parts - definitions and implementation. Have both the DAL and the implementation reference the logging definition assembly. It should just have an interface (API) for DAL to call. By having three assemblies instead of two you avoid circularity.

  • Anonymous
    April 05, 2015
    Seems it will copy the .dll's (with CopyToOutputDirectory), but not the .pdb's, is there a way around that?

  • Anonymous
    April 06, 2015
    The comment has been removed

  • Anonymous
    April 08, 2015
    AFAIK, Microsoft uses a special build system in order to create such circular references. However, as part of the cleanup of .NET Core, there will be no more circular references. One way I can imagine this could be done is by having multiple assemblies (so it is non-circular), and then later IL-merging the assemblies.

  • Anonymous
    April 27, 2015
    Dan - updated to include a way to also copy the .pdb file.

  • Anonymous
    February 01, 2016
    My 2 cents on circular references: stackoverflow.com/.../151249 But I agree it's better simply not to do it.

  • Anonymous
    February 22, 2016
    I need to copy de .config file from de project A to bin's folder of project B (since B references A). By default de .config copied from A has taked from src's folder but i want to take it from bin's folder of A. Where do i can configurate de source of .config in A?

  • Anonymous
    April 25, 2016
    Kirill,Thank you for the post. It works great. It seems you are expert in this area. Could you see my question here: http://stackoverflow.com/questions/36842976/why-msbuild-task-does-not-build-a-project-dependencies

  • Anonymous
    June 23, 2016
    "This achieves copying a dependency without referencing it."I have a .csproj that references a .vcxproj. Thanks to I am able to declare that reference and I can see that a build of the .vcxproj is triggered.I added this too: And the @(ReferenceCopyLocalPaths) collection does not contain the name of the .dll either.But the .csproj's output directory does not contain the output of the .vcxproj.Built using VS 2013.

  • Anonymous
    July 01, 2016
    Hi Krill,Great post!I have a user control library (lets call it A) that references two other user control libraries (B and C) and I want to be able to reference Control A from an application and have the libraries from B and C copied to the application build destination as well as A.Do you know if there's a way to do this?

  • Anonymous
    May 24, 2017
    Hi Kirill,Is there any way to do something similar for nuget packages?

  • Anonymous
    August 21, 2017
    If ProjectA references another ProjectC whose API it also accesses, ProjectB won't copy the output of ProjectC to its output directory automatically. This seems to be a logical consequence of how the Project Reference from ProjectB to ProjectA is specified.Therefore, you need to specify a build-time dependency from ProjectB to ProjectC, too.

  • Anonymous
    October 23, 2017
    I'm facing an additional major issue with this approach. If I change a source file of project A, and build within Visual Studio, it won't rebuild project B, thus not deploying the library of project A to project B's output directory.On the other hand, deployment wasn't working with solution level dependencies either.

    • Anonymous
      November 03, 2017
      I managed to solve my issue by setting the DisableFastUpToDateCheck property to true in project B.
  • Anonymous
    December 01, 2017
    First: This is a brilliant article and I really wish I had seen it sooner!Second: I am trying to understand the mechanism for output files from a project and what gets copied.My issue is that I want a project reference to a project that generates 2 assemblies than need to be referenced and a dll that needs to be copied to 'bin' but not referenced.I can do this 'easily' by outputting the first project into a nuget package and importing that in to the second and that is all fine, but I want to manage the same via project reference...How do I make the second assembly and the dll appear in the project 'output' such that it is copied/referenced?

  • Anonymous
    January 07, 2018
    Кирилл, отличная статья!!

  • Anonymous
    February 07, 2018
    Hi Kirill,Your solution works perfect except copying the pdb for Asp.net Core 2.0 projects, DebugSymbolsProjectOutputGroup target does not work. What is required to copy the pdb file?

  • Anonymous
    April 18, 2018
    I found that this works for C++ project (vcxproj) also, for "not-Managed-C++" cases where you can't reference the project normally.However, Visual Studio doesn't copy the dependency to indirect references (like the managed library's unit test project).I found that this alternative seems to work correctly for me, both for direct and indirect references: {70AC46A2-605B-4E9A-8414-D510A479742C} RE2.Native false PreserveNewest The first part tells MSBuild and VS that there’s a project dependency, but it should not be referenced. This causes VS to build things in the right order. (If you use a Post-Build COPY command instead, it fails if RE2.Native.dll wasn’t built first).The second part tells MSBuild and VS to copy the dependency to the output folder. (If you add to the , the native library disappears on Rebuild for indirect dependencies, like when changing a test and building RE2.Managed.Test.dll. The same happens if you use instead of as the type above.)

  • Anonymous
    April 18, 2018
    Here's a sample of referencing a native binary:[code] <ItemGroup> <ProjectReference Include="..\RE2.Native\RE2.Native.vcxproj"> <Project>{70AC46A2-605B-4E9A-8414-D510A479742C}</Project> <Name>RE2.Native</Name> <ReferenceOutputAssembly>false</ReferenceOutputAssembly> </ProjectReference> <None Include="$(ProjectDir)..\RE2.Native\bin$(Platform)$(Configuration)\RE2.Native.dll"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>[/code]The first part tells MSBuild and VS that there’s a project dependency, but it should not be referenced. This causes VS to build things in the right order. (If you use a Post-Build COPY command instead, it fails if RE2.Native.dll wasn’t built first).The second part tells MSBuild and VS to copy the dependency to the output folder. (If you add to the , the native library disappears on Rebuild for indirect dependencies, like when changing a test and building RE2.Managed.Test.dll. The same happens if you use instead of as the type above.)

  • Anonymous
    November 09, 2018
    How to change above to copy it to the subfolder of output directory, for example, how to copy it to ProjectA subfolder?

  • Anonymous
    November 13, 2018
    Same question for .net core. Is there a way to make a reference to another project, only for the build process, and keep the referenced project unavailable for development against?

  • Anonymous
    January 10, 2019
    This is great - however I've come into this little conundrum:My main project (project A) is referencing a module (project B) using the above mechanism. Project B imports some NuGet packages, which are not included in the Project A bin directory... thus it blows up at runtime... Is there any way to have the project reference also scan the dependencies of Project B and include them in the output?

  • Anonymous
    March 20, 2019
    This does not appear to work for N-Order Project References which might be required by the Library; I am attempting to see if there is a work around.