16

I have a C# project X that references a C# project Y that references a C# project Z. So the dependency chain looks like this: X => Y => Z. There is no direct/explicit dependency X => Z. When I build a package for publication using msbuild command

msbuild DesignService.csproj /m /p:Configuration="Debug" /p:Platform="AnyCPU" /verbosity:quiet /t:Package /p:PackageLocation=X.zip /p:PackageAsSingleFile=True

I get a zip file that has DLLs for X and Y, but not Z. Then when the package is published (to an Azure App Service) I get runtime errors when a call is made to code in Z, saying the DLL can not be found. If I add Z as a direct/explicit reference in X, it works just fine. But I don't think I should have to do this.

How can I get DLLs for Z in my publish package from msbuild without adding an explicit reference in X?

Scotty H
  • 6,432
  • 6
  • 41
  • 94
  • I somewhat reproduced this locally. I used a Azure API app as my .csproj. Then I had a similar problem to yours when I packaged using msbuild. I was able to get past this by going to visual studio > right click project > Properties > Package/Publish Web > Items to deploy > change to "All files in this project". – P.Brian.Mackey Mar 28 '18 at 20:42
  • @P.Brian.Mackey Thanks, but I already have it set to "All files in this project folder", which is even broader in scope. – Scotty H Mar 28 '18 at 20:48
  • Does this help? https://github.com/Azure/service-fabric-issues/issues/257 – P.Brian.Mackey Mar 28 '18 at 20:57
  • @P.Brian.Mackey It seems related, but I'm not sure what actionable items I can take from it, especially since it's still open. – Scotty H Mar 29 '18 at 14:17
  • There are a few workarounds that may help you in the thread. If it is the same issue, it's good to know that the bug report already exists. – P.Brian.Mackey Mar 29 '18 at 14:19
  • This normally comes to a good end, but the question is too vague to have a shot at guessing at the cause. You need to show us. Add /verbosity:detailed so MSBuild starts generating a lot more info about what it does. Redirect output to a file and copy/paste its content to a public paste bin. – Hans Passant Jul 14 '18 at 18:21

2 Answers2

1

Why does this happen

X.csproj was invoked, and because it has a project reference to Y.csproj, it invokes Y.csproj — it “goes around the back”. Z.csproj hasn’t necessarily built yet, so the build breaks.

How to fix

Follow this principle: do not use dependencies expressed in the solution file at all.

You could put a project reference in the project instead. It would look like this – note the metadata element, and all this is inside an <ItemGroup> tag of course:

<ProjectReference Include=”… foo.csproj”> 
    <ReferenceOutputAssembly>false</ReferenceOutputAssembly> 
</ProjectReference>

Although it’s tiresome to have to edit your projects in this way to make the bug go away, it’s a best practice to use project references instead and consider the solution file merely a “view”.

You’ll end up with projects that if you want can be built without a solution file.

For more details about how to fix the problem, you could refer to this blog.

Joey Cai
  • 18,968
  • 1
  • 20
  • 30
  • In my question I am `msbuild`ing a csproj, not a solution, so is this relevant? Can you edit your answer to make it clear which csproj the proposed edit goes in? X.csproj right? – Scotty H Mar 29 '18 at 14:16
  • 1
    You are not supposed to use sln files to build packages. This answer is more about msbuild w/ a build target not a package target. It is not relevant. If anything, the OP should go the opposite direction and build each package independently. That is a workaround to the issue. – P.Brian.Mackey Mar 29 '18 at 14:37
1

There is no straightforward way to do this, even though this issue has been raised multiple times with msbuild. In terms of workarounds, the most popular ones are to make some use of the 'Z' project assembly (create a dummy instance of some class from the 'Z' project in the 'X' project) or to add a direct reference in the 'X' project to the 'Z' project.

The most clean workaround in my opinion is explained in this blog. Essentially, it involves creating a separate .targets file, which is nothing but instructions for msbuild to ensure that while it builds and packages the DLLs, it also includes all transitive dependencies. This .targets file then needs to be added to your X.csproj file so that on building it using msbuild, this targets file gets invoked.

ThePretendProgrammer
  • 1,449
  • 10
  • 16