-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
On a ProjectReference, setting ReferenceOutputAssembly=false and Private=true does not copy the reference to the output without referencing it #1916
Comments
Refer to this article from Kirill Osenkov for a work around. |
On a related note, in Visual Studio, you'll need to set the |
Oops, I went ahead and approved your comments. Turns out I had 41 comments waiting for moderation :( Software didn't let me know or I turned all notifications off... sorry about that. |
Found this and it's exactly my issue. The workaround is not a solution as it doesn't copy the referenced projects dependencies. I'm using VS2019 (Version 16.4.2) and am using another workaround but it bloats the output folder so it's not ideal. So as I see it, we need the ability for Project A to reference Project B (where project B has nuget dependencies) in order to get it included in Project A's build output folder (including nuget dependencies) but for Project B to not be available to the compiler so Project A can't new up objects incorrectly. If implemented correctly, Project A's output folder should be exactly the same as a build with Project B referenced with ReferenceOutputAssembly=true. Perhaps there's a way to accomplish this that I've been unable to find? |
This issue is still open, so I assume it isn't fixed. I'm trying to build a project where the core module loads all other modules by reflection. So basically I want them to be built and published (copied) together, but I don't want a real dependency. @KirillOsenkov 's blog linked above is an interesting take on this problem, but it only copies the DLL (possibly PDB) from referenced project. If the referenced project itself has some unique dependencies, we need to copy them as well for the application to run properly --> that doesn't work with the technique described in the blog post. As of 2023 has anything changed? What would be the best way to do this with .net 7? |
I'm doing it like this. I'm not sure if there's a better way though.
A.csproj
|
@parched Here's what I ended up doing, it's a little simpler and works with many dependencies: <!--
Start by adding "weak" references as normal ones.
Unfortunate side-effect is that in IDE code from those can be referenced,
but then full build would fail because of next step below.
You can add individual ProjectReference as usual, or even grab many projects with a glob as shown here.
The key is to tag "weak" projects that must be compiled and deployed together,
but not be a direct reference, with a custom property "IsWeakReference".
-->
<ProjectReference Include="../Modules/**/*.csproj">
<IsWeakReference>true</IsWeakReference>
</ProjectReference>
<!--
The timing of this target is key to make this solution work. Goal is:
1. Automatically compile the "weak" references with main project, **without introducing a real reference.**
This preserves architecture layering and also avoids interference with things like Microsoft.NET.Sdk.Web SDK
that has a target that automatically adds ApplicationPartAttribute for each reference that itself references MVC.
2. Have the weak referenced compilation output copied in main project output (during build or publish).
A challenge here is to also include transitive references to nuget packages.
The solution has 3 parts:
1. Use MSBuild flag ReferenceOutputAssembly=false.
With this flag, MSBuild builds the weak references first,
but doesn't add them as actual references to the main project.
2. Use combination OutputItemType=Content and CopyToOutputDirectory to copy built projects output.
Unfortunately this does NOT copy transitive dependencies :(
3. To work-around that limitation, we first include the references as regular ones,
*without* ReferenceOutputAssembly=false.
During target AssignProjectConfiguration, .net SDK flattens transitive references,
so $(ProjectReferenceWithConfiguration) now contains both direct project references
and their transitive dependencies. This is key to getting all dlls copied in output.
At this step, before C# compilation is invoked, the configuration of modules references is modified
so that they're not referenced by compilation anymore (set ReferenceOutputAssembly=false)
and still copied to output (OutputItemType + CopyToOutputDirectory).
-->
<Target Name="SetModuleReferencesAsPrivate"
AfterTargets="AssignProjectConfiguration"
BeforeTargets="ResolveProjectReferences">
<ItemGroup>
<ProjectReferenceWithConfiguration
Condition="%(ProjectReferenceWithConfiguration.IsWeakReference) == 'true'">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ProjectReferenceWithConfiguration>
</ItemGroup>
</Target> That's some deep MS Build / .NET SDK trickery, but it has been working well for us. |
Might also be worth mentioning here that some extra tinkering is required for C/C++ dependencies: |
As far as I can see, the problem is that if
ReferenceOutputAssembly
is set tofalse
, then the project will not be added to_ResolvedProjectReferencePaths
, which is what gets passed to RAR, so RAR never even has the reference to consider.I would expect ReferenceOutputAssembly to prevent the compiler from seeing the reference, but not prevent copying as a dependency (say, for reflection purposes).
The text was updated successfully, but these errors were encountered: