templating
templating copied to clipboard
The conditions of the Target tag in the csproj are removed if a template's condition is true
Product
dotnet CLI & Visual Studio
Describe The Bug
I'm creating a template which modify a .csproj file.
In my template.json, I added a boolean like following :
"symbols": {
"GenerateClient": {
"type": "parameter",
"description": "Automatically adds the Client generation",
"datatype": "bool",
"defaultValue": "true"
},
},
In the code, it's as easy as following to modify it if the GenerateClient is true :
#if (GenerateClient)
Console.WriteLine("Client generated.");
#endif
But in the .csproj it's different. I can't (or at least, I didn't find how to) add a bunch of lines in a GenerateClient condition.
So instead of that, I'm adding a condition to each line of my .csproj, like following :
<PackageReference Condition="'$(GenerateClient)' == 'True'" Include="NSwag.AspNetCore" Version="13.20.0" />
If the condition is false, the line is removed, and if it's true, the Condition parameter is removed. It's exactly what I want.
<PackageReference Include="NSwag.AspNetCore" Version="13.20.0" />
But unfortunately, if your tag already has a Condition parameter and you add the '$(GenerateClient)' == 'True' in it, the whole Condition is getting removed.
For example, I have a Target tag with the following Condition parameter :
<Target Name="NSwag" BeforeTargets="AfterBuild" Condition="'$(TF_BUILD)'!='True' And '$(Configuration)' != 'Debug'">
I want that the Target tag is getting added only if the GenerateClient bool is true. So I modified the Condition parameter as following :
<Target Name="NSwag" BeforeTargets="AfterBuild" Condition="'$(GenerateClient)' == 'True' And '$(TF_BUILD)'!='True' And '$(Configuration)' != 'Debug'">
If the GenerateClient bool is false, it works. The whole Target tag is getting removed. But if the GenerateClient is true, the Target tag is being added, but the Condition parameter is totally removed, like the following :
<Target Name="NSwag" BeforeTargets="AfterBuild">
I tried some workarounds, for example I added a Label : Label="The label will be replaced in order to readd Conditions", then I added a symbol to the template.json :
"TargetCondition": {
"type": "parameter",
"defaultValue": "Condition=\"'$(TF_BUILD)'!='True' And '$(Configuration)' != 'Debug'\"",
"replaces":"Label=\"The label will be replaced in order to readd Conditions\""
}
But the problem is now any user of my template can modify the TargetCondition string, and possibly abuse this vulnerability.
I also tried to surround the Target tag with an ItemGroup which has the GenerateClient condition like that :
<ItemGroup Condition="'$(GenerateClient)' == 'True'">
<Target Name="NSwag" BeforeTargets="AfterBuild" Condition="'$(TF_BUILD)'!='True' And '$(Configuration)' != 'Debug'">
...
</Target>
</ItemGroup>
But the Target tag should be at the root of the Project tag, and cannot be surrounded by any tag. So if I do this, the .csproj isn't valid anymore.
Would it be possible for the Condition parameter to not being totally removed ? Maybe I'm missing a point.
Thanks for your help and your work !
To Reproduce
Steps:
- Create a template with a
template.json. - Add a boolean
symbol, for example "GenerateClient". - Add a
Targettag to any.csproj, with aConditionparameter. - Add the boolean
symbolpreviously created to theConditionparameter (Condition="'$(GenerateClient)' == 'True'"). - Generate a new project using this project, with the "GenerateClient" condition to
true. - The newly created
.csprojshould have aTargettag without anyConditionparameter.
dotnet Info
output
SDK .NET : Version: 7.0.403 Commit: 142776d834Environnement d'exécution : OS Name: Windows OS Version: 10.0.22621 OS Platform: Windows RID: win10-arm64 Base Path: C:\Program Files\dotnet\sdk\7.0.403\
Host: Version: 7.0.13 Architecture: arm64 Commit: 3f73a2f186
.NET SDKs installed: 7.0.403 [C:\Program Files\dotnet\sdk]
.NET runtimes installed: Microsoft.AspNetCore.App 6.0.24 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.24 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 6.0.24 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 7.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Other architectures found: x64 [C:\Program Files\dotnet\x64] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x64\InstallLocation] x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables: Not set
global.json file: Not found
Learn more: https://aka.ms/dotnet/info
Download .NET: https://aka.ms/dotnet/download
Visual Studio Version
2022
Additional context
No response
Hello,
So I updated my workaround using the constantgenerator I found during my researches :
"TargetCondition": {
"type": "generated",
"generator": "constant",
"parameters": {
"value":"Condition=\"'$(TF_BUILD)'!='True' And '$(Configuration)' != 'Debug'\""
},
"replaces":"Label=\"The label will be replaced in order to readd Conditions\""
}
Now it works and there isn't a vulnerability in the template.
Unfortunately, I didn't find any cleaner solution to my problem for the moment.
This is documented and can easily be fixed in two ways. See: https://github.com/dotnet/templating/blob/v7.0.308/docs/Conditional-processing-and-comment-syntax.md#ignore-conditions-expressions-in-msbuild-files