新 ( "sdk-style" ) 与旧项目格式的 MsBuild 条件



我想编写一个msbuild"include"(.props(文件,该文件将导入到新的("sdk风格"(项目和旧项目中。

有没有办法找出 .props 文件导入到哪种类型的项目中,以便我可以在某个条件下使用它?例如

<PropertyGroup Condition="'$(ProjectType)'=='sdk'">
<SomeProperty>SomeValue</SomeProperty>
</PropertyGroup>

我在项目中遇到了同样的需求。 起初我选择了解决方案@wexman,但我发现该变量不可靠。 我考虑过打开 csproj 文件并使用正则表达式查找 SDK 属性的方法,但对我来说感觉太脆弱了 - 特别是考虑到 SDK 可以在元素或属性中指定。 最后,我创建了一个打开二进制日志记录的构建(选项/bl(,并搜索在构建 SDK 样式项目时导入的各种文件。

我发现了属性UsingMicrosoftNETSdk

,该属性设置为在props 文件中设置为true,当您使用 SDK 样式的项目时,该文件会自动导入Microsoft.Common.props。 这种自动导入(导致 Directory.Build.props 的自动导入(似乎是 SDK 样式项目最重要的定义特征之一,并且属性的名称使其看起来更有可能保留下来。

所以最后我的解决方案是:

Condition="'$(UsingMicrosoftNETSdk)' == 'true'"

(或相反(作为确定正在使用哪种类型的项目的可靠方法。

我似乎已经找到了一个可行的解决方案。我正在检查 Microsoft.NET.Sdk.Props 中声明的属性 $(_PlatformWithoutConfigurationInference(。如果它不为空,我将处理一个 sdk 风格的项目,如果它是空的,它是一个遗留项目:

<Project>
<PropertyGroup>
<ProjectStyle Condition="'$(_PlatformWithoutConfigurationInference)'!=''">sdk</ProjectStyle>
<ProjectStyle Condition="'$(_PlatformWithoutConfigurationInference)'==''">legacy</ProjectStyle>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Message Importance="High" Text="$(MsBuildProjectName) is a $(ProjectStyle) style project" />
</Target>
</Project>

虽然测试属性值(或缺少属性值(是 MSBuild 中几乎所有操作完成的方式,但有时还有其他方法。

如何知道当前的 MSBuild 项目是否为 SDK 项目?

换句话说:

  • 给定一个 XML 文件...
  • 其完整路径在MSBuildProjectFullPath知名物业中...
  • 谁的第一个标签是Project...
  • 所述标签是否具有Sdk属性?

借助 MSBuild 的属性函数,您可以执行以下操作:

  • 使用[System.IO.File]::ReadAllText以字符串形式读取项目文件的内容;
  • 然后使用[System.Text.RegularExpressions.Regex]::IsMatch测试具有Sdk属性的Project标记。

<_ProjectContents>$([System.IO.File]::ReadAllText('$(MSBuildProjectFullPath('((
<_SdkRegex>(?s-i((^|\s|>(<项目\s(([^>]*?)\s(?Sdk(\s*?(=(\s*?
<_IsSdkProject>$([System.Text.RegularExpressions.Regex]::IsMatch('$(_ProjectContents(', '$(_SdkRegex('((

或者,如果您更喜欢单行:

<PropertyGroup>
<_IsSdkProject>$([System.Text.RegularExpressions.Regex]::IsMatch(`$([System.IO.File]::ReadAllText(`$(MSBuildProjectFullPath)`))`, `(?s-i)(^|s|&gt;)&lt;Projects(([^&gt;]*?)s)?Sdk(s*?)=(s*?)"`))</_IsSdkProject>
</PropertyGroup>

然后你可以在一个Condition中使用_IsSdkProject的值,它将是TrueORFalse,如下所示:

<PropertyGroup Condition="'$(_IsSdkProject)'=='True'">
<SomeProperty>SomeValue</SomeProperty>
</PropertyGroup>

正则表达式解释

在上面的正则表达式中,<>字符已替换为 XML 实体(分别为&lt;&gt;(。原始正则表达式如下:

(?s-i)(^|s|>)<Projects(([^>]*?)s)?Sdk(s*?)=(s*?)"

这意味着:

  • 在单行、区分大小写的模式下...
  • 要么在文件的开头,要么在空格字符后面,要么在>字符后面......
  • 查找文字字符串<Project...
  • 然后是一个空格字符...
  • 然后,可以选择除>之外的任何字符的任意数量,以及另一个空格字符...
  • 然后文字字符串Sdk...
  • 然后,可以选择任意数量的空格字符...
  • 那么角色=...
  • 然后,可以选择任意数量的空格字符...
  • 然后角色"

更好的解释,以及在线测试器,您可以在其中插入项目文件的内容并实时测试,regex101.com。该网站是为Javascript正则表达式制作的,它的行为与.NET中的行为不完全相同,但无论如何它都很有用。

("SDK 样式"(与旧项目格式的 MsBuild 条件

这个问题没有直接的解决方案。因为在MSBuild/Visual Studio中没有这样的属性ProjectType

我想在这里提供一个解决方法,您可以检查它是否适合您。我们知道,在旧的项目格式中,通常会有一个文件AssemblyInfo.cs,这在新的"sdk样式"项目格式中是不存在的。因此,我们可以使用该Condition="Exists('$(ProjectDir)PropertiesAssemblyInfo.cs')"来找出.props文件导入到哪种类型的项目中:

我的测试.props文件的内容:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="Exists('$(ProjectDir)PropertiesAssemblyInfo.cs')">
<SomeProperty>SomeValue1</SomeProperty>
</PropertyGroup>
<PropertyGroup Condition="!Exists('$(ProjectDir)PropertiesAssemblyInfo.cs')">
<SomeProperty>SomeValue2</SomeProperty>
</PropertyGroup>
<Target Name="Test" AfterTargets="AfterBuild">
<Message Text="$(SomeProperty)"></Message>
</Target>
</Project>

希望这有帮助。

最新更新