AssemblyName can not use condition in multiple target frameworks project
ahdung opened this issue · 11 comments
Version Used:
VS2019 16.11.5
Steps to Reproduce:
- 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>
- Open this project with VS2019
- 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.
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.
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.
Another confirmation that this is still broken in VS2022 (17.7.4), but only sometimes. (Yay? 😁)
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
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>
Thanks you @jeepinpugs! This has saved a tiny part of my sanity! 😄
@jeepinpugs You're genius, man.
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
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.
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.
This is a known issue
In that case, I hereby submit the feature request of getting a more helpful error message. :-)
Someone outside the NuGet team (but still a Microsoft employee) contributed a fix recently:
It'll be improved in VS2022 17.9 preview 3