dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.68k stars 1.06k forks source link

AssemblyName can not use condition in multiple target frameworks project #22469

Open ahdung opened 2 years ago

ahdung commented 2 years ago

Version Used: VS2019 16.11.5

Steps to Reproduce:

  1. Save follow content to asdf.csproj
    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFrameworks>net48;net5.0</TargetFrameworks>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
        <AssemblyName Condition="'$(TargetFramework)'=='net48'">A.Net48</AssemblyName>
        <AssemblyName Condition="'$(TargetFramework)'=='net5.0'">A.Net50</AssemblyName>
      </PropertyGroup>
    </Project>
  2. Open this project with VS2019
  3. Build it, you'll got error:
    已启动生成…
    1>------ 已启动生成: 项目: asdf, 配置: Debug Any CPU ------
    未能还原 C:\Users\Administrator\Desktop\新建文件夹\asdf.csproj (用时 5 ms)。
    NuGet 包还原失败。请查看“错误列表”窗口了解详细警告和错误。
    1>C:\Program Files\dotnet\sdk\5.0.402\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(241,5): error NETSDK1005: 资产文件“C:\Users\Administrator\Desktop\新建文件夹\obj\project.assets.json”没有“net48”的目标。确保已运行还原,且“net48”已包含在项目的 TargetFrameworks 中。
    1>已完成生成项目“asdf.csproj”的操作 - 失败。
    1>C:\Program Files\dotnet\sdk\5.0.402\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(241,5): error NETSDK1005: 资产文件“C:\Users\Administrator\Desktop\新建文件夹\obj\project.assets.json”没有“net5.0”的目标。确保已运行还原,且“net5.0”已包含在项目的 TargetFrameworks 中。
    1>已完成生成项目“asdf.csproj”的操作 - 失败。
    ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

Expected Behavior: Build success and the condition of AssemblyName work.

Actual Behavior: Build failed.

dotnet-issue-labeler[bot] commented 2 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

HeinziAT commented 1 year ago

I can confirm that this issue still exists with VS2022.

Here are the relevant parts of my csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net48;net7.0-windows</TargetFrameworks>
    <LangVersion>latest</LangVersion>
    ...
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)' == 'net48'">
    <AssemblyName>SomeFileName</AssemblyName>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
    <AssemblyName>SomeOtherFileName</AssemblyName>
  </PropertyGroup>
  ...
</Project>

And here are the exact error messages in English:

1>C:\Program Files\dotnet\sdk\7.0.102\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): error NETSDK1005: Assets file 'C:\Users\[path redacted]\obj\project.assets.json' doesn't have a target for 'net48'. Ensure that restore has run and that you have included 'net48' in the TargetFrameworks for your project.
1>Done building project "[project name redacted].csproj" -- FAILED.
1>C:\Program Files\dotnet\sdk\7.0.102\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): error NETSDK1005: Assets file 'C:\Users\[path redacted]\obj\project.assets.json' doesn't have a target for 'net7.0-windows'. Ensure that restore has run and that you have included 'net7.0-windows' in the TargetFrameworks for your project.
1>Done building project "[project name redacted].csproj" -- FAILED.
bradwilson commented 1 year ago

Another confirmation that this is still broken in VS2022 (17.7.4), but only sometimes. (Yay? 😁)

Working: https://github.com/xunit/xunit/blob/9ab4ecef596b9677bcc53bdb3b5e1117b0a83bf4/src/xunit.execution/xunit.execution.csproj#L4-L5

Broken: https://github.com/xunit/visualstudio.xunit/blob/85864c89881560adb668f59b137e06f3dc544554/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj#L5-L6

For the broken project, command line dotnet restore and dotnet build work as expected. Visual Studio fails to restore, and references in Solution Explorer appear broken until the command line dotnet restore is run; trying to build from within Visual Studio will re-break the restore (and also the build, obviously).

I don't know why one works and one doesn't, but hopefully having both will help track down the issue.

My dotnet --info:

.NET SDK:
 Version:   7.0.401
 Commit:    eb26aacfec

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22621
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\7.0.401\

Host:
  Version:      7.0.11
  Architecture: x64
  Commit:       ecb34f85ec

.NET SDKs installed:
  7.0.401 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found
jeepinpugs commented 10 months ago

I too was having this issue. The issue is with the NuGet restore command through Visual Studio. NuGet appears to use the AssemblyName as part of the Package ID that it generates when doing a restore. The problem comes in when you try to change the AssemlyName conditionally. If you specify your own explicit Package ID then it will fix this problem. Add this property to your property group and set the Package ID to some unique string: <PackageId>SolutionName.ProjectName</PackageId>

bradwilson commented 10 months ago

Thanks you @jeepinpugs! This has saved a tiny part of my sanity! 😄

ahdung commented 10 months ago

@jeepinpugs You're genius, man.

ViktorHofer commented 9 months ago

I too was having this issue. The issue is with the NuGet restore command through Visual Studio. NuGet appears to use the AssemblyName as part of the Package ID that it generates when doing a restore. The problem comes in when you try to change the AssemlyName conditionally.

cc @dotnet/nuget-team

zivkan commented 9 months ago

This is a known issue, and @jeepinpugs has already described the mitigation, which is to explicitly set the package id.

However I strongly recommend against using this pattern. It will cause assembly load failures when 3 or more projects/packages are used:

.NET 8 console app reference .NET Standard ClassLib1, which itself references multi-targeting (.NET 8 and .NET Standard) ClassLib2.

ClassLib2 will have a compile time reference to ClassLib2.netstandard, but the console app will have ClassLib2.net8.dll in the bin directory. As soon as the console app calls a ClassLib1 API that calls a ClassLib2 API, the runtime will fail with a FileNotFoundException, looking for ClassLib2.netstandard.dll

This runtime failure will happen no matter if ClassLib1 and ClassLib2 are packages or project references. The solution to this runtime failure is to keep the assembly name the same for all target frameworks.

also see: https://learn.microsoft.com/en-us/dotnet/standard/library-guidance/cross-platform-targeting

AVOID changing the assembly name or using different assembly names for each TFM your library compiles. Due to dependencies between libraries, multi-targeting with different assembly names per TFM can break package consumers. An assembly should have the same name across all TFMs.

HeinziAT commented 9 months ago

In addition to the points raised by zivkan, we encountered another problem with having different assembly names for different targets: WPF.

(a) XAML requires the name of the assembly when importing namespaces from other assemblies (e.g. xmlns:lib="clr-namespace:Foo.Library;assembly=FooLibrary), and (b) XAML does not have an good solution for "conditional compilation". This creates a problem if you have a multi-targeting WPF application, because you'd need different XAML for both targets.

Thus, while jeepinpugs' solution works (and the issue mentioned by zivkan's does not apply in our case since we have the mutually incompatible targets .NET 7 and .NET Framework 4.8), we had to go back to using the same assembly name for all targets for our library.

HeinziAT commented 9 months ago

@zivkan

This is a known issue

In that case, I hereby submit the feature request of getting a more helpful error message. :-)

zivkan commented 9 months ago

Someone outside the NuGet team (but still a Microsoft employee) contributed a fix recently:

It'll be improved in VS2022 17.9 preview 3