Search code examples
c#.netbuildmsbuild

C# Build Issue: Multiple Publish Output Files with Same Relative Path


  • Error Message:
Severity    Code    Description    Project    File    Line    Suppression State    Details
Error (active)    NETSDK1152    Found multiple publish output files with the same relative path:
D:\\source\\repos\\DesktopWidgets3\\Tools\\DevHome.Dashboard\\BuildAssets\\Microsoft.Windows.Widgets.winmd,
D:\\source\\repos\\DesktopWidgets3\\DesktopWidgets3\\obj\\x64\\Debug\\net8.0-windows10.0.22621.0\\MsixContent\\Microsoft.Windows.Widgets.winmd.  
DesktopWidgets3    C:\\Program Files\\dotnet\\sdk\\8.0.400\\Sdks\\Microsoft.NET.Sdk\\targets\\Microsoft.NET.ConflictResolution.targets    112
  • Project Structure
  1. DevHome.Dashboard (Tool project)
  2. DesktopWidgets3 (Main project that references DevHome.Dashboard)
  • Project csproj file

This is DevHome.Dashboard.csproj.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <RootNamespace>DevHome.Dashboard</RootNamespace>
    <UseWinUI>true</UseWinUI>
    <TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
    <!-- ... other properties ... -->
  </PropertyGroup>

  <ItemGroup>
    <Content Include=".\BuildAssets\Microsoft.Windows.Widgets.Internal.winmd" Link="Microsoft.Windows.Widgets.Internal.winmd" CopyToOutputDirectory="PreserveNewest" />
    <Content Include=".\BuildAssets\Microsoft.Windows.Widgets.winmd" Link="Microsoft.Windows.Widgets.winmd" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

  <ItemGroup>
  <Reference Include="Microsoft.Windows.Widgets.Hosts">
    <HintPath>.\BuildAssets\Microsoft.Windows.Widgets.winmd</HintPath>
    <IsWinMDFile>true</IsWinMDFile>
  </Reference>
</ItemGroup>

  <!-- ... other item groups and references ... -->
</Project>

This is DesktopWidgets3.csproj.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
    <!-- ... other properties ... -->
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Tools\DevHome.Dashboard\DevHome.Dashboard.csproj" />
    <!-- ... other project references ... -->
  </ItemGroup>

  <!-- ... other item groups and properties ... -->
</Project>
  • The Issue

The DevHome.Dashboard project needs the Microsoft.Windows.Widgets.winmd file, but it's causing a conflict when building DesktopWidgets3. But I don't add Microsoft.Windows.Widgets.winmd file in DesktopWidgets.

However, for Microsoft.Windows.Widgets.Internal.winmd which is not added to the reference. It works well.

  • Question

How can I prevent the Microsoft.Windows.Widgets.winmd file from being copied to the DesktopWidgets3 project while still allowing DevHome.Dashboard to use it?

I've tried modifying the ProjectReference in DesktopWidgets3.csproj like this:

<ProjectReference Include="..\Tools\DevHome.Dashboard\DevHome.Dashboard.csproj">
  <ExcludeAssets>ContentFiles</ExcludeAssets>
</ProjectReference>

But the error persists. Any suggestions?

I've tried modifying the ProjectReference in DesktopWidgets3.csproj like this:

<ProjectReference Include="..\Tools\DevHome.Dashboard\DevHome.Dashboard.csproj">
  <ExcludeAssets>ContentFiles</ExcludeAssets>
</ProjectReference>

But the error persists.


Solution

  • The underlying issue

    As you've ascertained in your comments, the underlying issue is indeed that you have:

    1. A Content file brought in by your ProjectReference
    2. A duplicated Reference in the head project

    ❌ How you've tried to fix it

    Your example with the following:

    <ProjectReference ...>
      <ExcludeAssets>ContentFiles</ExcludeAssets>
    </ProjectReference>
    

    Makes really good conceptual sense. But there's no such element as ExcludeAssets on a ProjectReference. These are exclusive to other types of reference like PackageReference.

    ✅ Removing the duplicate Content

    One method of fixing the underlying issue is to use CopyToPublishDirectory on the Content. This is what you've noted in your comments, you say to no avail. But I know this should work in your scenario. Is it possibly because you've put Update instead of Include?

    The following should work:

    <Content Include="..." CopyToPublishDirectory="Never" />
    

    I've just set up a hierarchy of published dependency projects precisely as you have; recreated your precise error code, then tested this fix successfully.

    ✅ Removing the duplicate copied reference

    Another way to fix the duplicate file is to stop the Reference from copying to the target directory, allowing the Content file through instead.

      <Reference Include="Microsoft.Windows.Widgets.Hosts">
        <Private>False</Private> 
        ...
      </Reference>
    

    NB Private might be better called "CopyLocal"; it determines whether the asset will be copied to the target directory; by derivation the publish directory.

    https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items?view=vs-2022#reference

    NB. I've just tested this method also fixes your precise error.

    ❌ An alternative (quick) fix

    For this specific error (NetSDK1152) directly relating to publishing, you can override it (read caveats before using this method):

    <PropertyGroup>
    <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
    </PropertyGroup>
    

    See: https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#erroronduplicatepublishoutputfiles

    Future readers note that OP tried this method and it resulted in the following:

    APPX1101 Payload contains two or more files with the same destination path

    From past experience this is a well known "quick fix"; however it looks like the underlying flag may simply not be usable any more:

    NB. on the documentation it says that fixes NetSDK1148. I'm quite confident that this is a typo in the Microsoft documentation. It has been commented that we get this fixed and yes that would be the best idea ordinarily. However it looks like the flag itself may be coming up for removal, if anything, given its current state of dysfunction.

    Further discussion

    I don't know the ins and outs of your specific project hierarchy and it obviously has a "rich history" given the WinMD files and post-net.50 windows.xxx target framework workarounds. However from what I've seen I'd question whether those Content references containing the WinMD files are required at all. It certainly raises a "smell" that it's causing you so many issues. Do these files need to be copied to the target directory (note target directory, publish directory) at all by this specific project?