1

I'm using Visual Studio 2022 to create a simple C# class library targeting .NET6 and .NET Framework 4.8.... and I've been tearing my hair out on this one all day.

I want to name my assembly differently depending on the framework. Specifically, I want to append ".Core" to my assembly name if it's a .NET build.

But it seems I can't utilize the $(TargetFramework) macro within a .csproj file to change the value of the AssemblyName property.

For example, this works when using the $(Configuration) macro:

<PropertyGroup>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
           ...
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <AssemblyName>$(MSBuildProjectName).Debug</AssemblyName>
</PropertyGroup>

But this doesn't:

<PropertyGroup>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
         ....
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'">
    <AssemblyName>$(MSBuildProjectName).Core</AssemblyName>
</PropertyGroup>

I've been reading similar questions, specifically this one but I'm not sure it applies to CSPROJ files. Moreover the answer doesn't provide an example; it's unclear to me how it could be implemented in a CSPROJ.

Can AssemblyName be overridden by placing a condition on the target framework?

The errors I'm receiving are:

NuGet package restore failed. Please see Error List window for detailed warnings and errors.

Failed to restore D:\src2\csharp\dummy1\dummy1.csproj (in 0.6 ms).
1>C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): error NETSDK1005: Assets file 'D:\src2\csharp\dummy1\obj\project.assets.json' doesn't have a target for 'net6.0'. Ensure that restore has run and that you have included 'net6.0' in the TargetFrameworks for your project.

1>Done building project "dummy1.csproj" -- FAILED.

1>C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): error NETSDK1005: Assets file 'D:\src2\csharp\dummy1\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 "dummy1.csproj" -- FAILED.

using command line tools "dotnet build" and "msbuild", the project succeeds (thanks @Jimmy!). It's only in Visual Studio that it doesn't work. I'm starting to suspect my problem isn't renaming the assembly name, but something else in Visual Studio that needs to be done.

enter image description here

With @Jimmy pointing me to the build tool, I'm suspecting that this really is a Nuget problem, and NOT an assembly renaming issue, though the error only appears when trying to rename the assembly...

Ketchup201
  • 129
  • 1
  • 9
  • Would you consider updating that XML and then running the build? I would be able to suggest a solution using xmlstarlet to do so. I run into a simular problem building my nugget packages and getting the project source updated to use the new package version. – Felipe Esteves Dec 20 '22 at 23:19
  • check this out: https://pastebin.pl/view/fcba4528. In this case I'm replacing the Version attribute of the XML. – Felipe Esteves Dec 20 '22 at 23:21
  • 1
    I created a dummy project with no code and a simple project file; I'm happy to try anything! – Ketchup201 Dec 20 '22 at 23:57
  • 1
    Filipe - link is broken, but I tried the AssemblyVersion attribute and it worked just fine. , I'm specifically trying to change the AssemblyName attribute and it won't work. – Ketchup201 Dec 21 '22 at 00:01

3 Answers3

1

The easiest (and dumbest) way to solve that would be running a few commands to update the .csproject with those values depending on the compilation need. For instance:

given the file project.csproj:

<PropertyGroup>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
           ...
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <AssemblyName>$(MSBuildProjectName).Debug</AssemblyName>
</PropertyGroup>

I would run run:

sed -i.backup 's/(Configuration)\x27 == \x27Debug\x27/\(TargetFramework\)\x27 == \x27net6.0\x27/' project.csproj

and then run:

sed -i.backup 's/(MSBuildProjectName).Debug/(MSBuildProjectName).Core/' project.csproj

that would transform the project.csproj on:

<PropertyGroup>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
           ...
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'">
    <AssemblyName>$(MSBuildProjectName).Core</AssemblyName>
</PropertyGroup>

I know that isn't the coolest thing (transforming files like that in devops time) but that would definitely do the trick.

You could also wrap that script into a shell (.sh) or bat (.bat) and run that when building.

PS: \x27is a scape for the single quote. sed command would mix the single quotes with the strings you are replacing.

You can find more about sed here: https://www.geeksforgeeks.org/sed-command-in-linux-unix-with-examples/

With a few shell commands you can use environment variables to do that in a script.

Hope that helps!

Felipe Esteves
  • 363
  • 1
  • 10
  • @Ketchup201 once you test that it would be great if you flag the answer. Thx! – Felipe Esteves Dec 21 '22 at 21:20
  • Thanks! I couldn't implement it exactly as you said since that requires modifying the project file while the project file is already in use, or to modify it outside of Visual Studio, which is exactly what I'm trying not to do.. It would be do-able on our build system, but developers would have my head on a plate if I didn't give them the ability to compile from within VStudio.. I have an idea how to get around this without too much 'working outside of VStudio'.. I'll give it a try next week and will update my post with the results. – Ketchup201 Dec 22 '22 at 22:57
  • Would you consider using a "pre-build" command to do that replacement? That would fix that issue before building with Visual Studio. Visual Studio has the "pre-build" solution command and you can add something like that there. – Felipe Esteves Dec 23 '22 at 13:42
1

This works fine for me. Here's my test project file in its entirety:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(TargetFramework)'=='net6.0'">
    <AssemblyName>$(MSBuildProjectName).Core</AssemblyName>
  </PropertyGroup>
</Project>

I built with dotnet build -bl and then looked at the msbuild.binlog files using https://msbuildlog.com/. I see the top-level build kicking off two inner builds, one with each target framework:

Screenshot from the binlog viewer showing the build for DynamicAssemblyName.csproj.  The target DispatchToInnerBuilds is expanded, and inside that the task MSBuild is expanded, showing two inner builds.  The second inner build is expanded to show that TargetFramework has been set to net6.0

If I look up higher in the viewer, I can see the evaluation for the inner build (id 109 as shown in the screenshot above) showing that the value was updated during evaluation:

The Evaluation node is expanded and the node for id 109 is expanded.  A line of output is highlighted showing that the property value for $(AssemblyName) was reassigned.

If I were you, I'd get a binlog and see if the property is being reassigned again back to the default, perhaps by another .targets file later on.

Jimmy
  • 27,142
  • 5
  • 87
  • 100
  • Fascinating, @jimmy, thanks. I've never seen that tool before. So I ran the build via command line using donet build, and my sample compiled without error. I then tried using msbuild /t:Rebuilid, and THAT worked. This makes me wonder why Visual Studio is complaining. Maybe Visual Studio is complaining about something else, that's only slightly related? Can you compile your sample in VS without error? I'm updating my OP with the error I'm receiving, which I should have done in the first place. – Ketchup201 Dec 27 '22 at 16:37
  • 1
    @Ketchup201 you're right, I also can't build this in VS, with the same failure at ResolvePackageAssets. I know VS does run the build with some differences, but I don't know what they are or why they would break this. Might be worth reporting through VS Feedback so the product team can look, this seems like a reasonable scenario that should work. – Jimmy Dec 28 '22 at 18:46
1

So I determined that even if I got the assembly renamed the way Jimmy was able to show, it could still cause issues when I do this with our full solution (that has a ton of dependencies) -- I'm not confident Visual Studio will be able to find my renamed Core assemblies when resolving the dependencies (since they're project dependencies).

So here's what I did..

  1. I created 4 build configurations: DebugFramework, DebugNET, ReleaseFramework, and ReleaseNET.

  2. I removed the TargetFramework from the PropertyGroup.

  3. I added this to each project file:

     <Choose>    
         <When Condition="'$(Configuration)' == 'DebugNET' OR '$(Configuration)' == 'ReleaseNET'">
             <PropertyGroup>
                 <TargetFramework>net6.0-windows</TargetFramework>
                 <AssemblyName>$(MSBuildProjectName).Core</AssemblyName>
             </PropertyGroup>
         </When>
         <Otherwise>
             <PropertyGroup>
                 <TargetFramework>net48</TargetFramework>
                 <AssemblyName>$(MSBuildProjectName)</AssemblyName>
             </PropertyGroup>
         </Otherwise>
     </Choose>
    

Now, when I build, the AssemblyName is known at the start of the build and doesn't change in the middle.

While I'd rather have both .NET and .FRAMEWORK builds performed at the same time, this workaround is good enough, and is probably more like the way Microsoft intended us to do it in the first place.

Hope this helps someone else. Thanks for everyone's input!

Ketchup201
  • 129
  • 1
  • 9