使用 Directory.Build 来消除项目文件中的重复配置
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 Directory.Build 来消除项目文件中的重复配置相关的知识,希望对你有一定的参考价值。
使用 Directory.Build 来消除项目文件中的重复配置
Intro
如果解决方案里的项目比较多的话,往往会有很多重复的项目属性,通常我们可以使用独立的 props
属性文件来配置公用的属性,而一般的属性文件都需要手动的 Import
到项目文件中,而 MSBuild 支持自动导入我们要介绍的 Directory.Build.props
中的配置,所以通常我们可以使用 Directory.Build.props
来减少项目中重复的属性
DirectoryBuild
什么是 Directory.Build
呢?
Directory.Build
文件是放在某一个目录下,其中的配置针对这个目录下所有的项目都生效,并且 MSBuild 运行的时候会自动引入,不需要显式地在项目文件中引入,主要分成 Directory.Build.props
和 Directory.Build.targets
两类,在很多开源项目包括微软的开源项目都有用到这个来简化项目配置,.props
文件是属性文件,通常定义公用的属性,导入时机较早,项目中的定义可以覆盖掉其中的配置,.targets
是目标文件,通常定义一些自定义的 MSBuild Task,导入时间稍后,可以用来覆盖项目文件中的定义
通常我只是用到 Directory.Build.props
来配置公用的属性
下面是一个项目文件中的一部分:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
上面 TargetFramwork
/Nullable
/ImplicitUsings
是一个 MSBuild 属性,需要声明在 PropertyGroup
内
如果一个解决方案中有很多个项目,那么这些可能就都是重复项了,这时候使用 Directory.Build.props
就会比较方便,比如说 ImplicitUsing
这一属性,这个属性是用来启用 .NET 6 里的隐式命名空间引用的,但是从 .NET 6 RC1 默认是禁用的,需要显式声明 <ImplicitUsings>enable</ImplicitUsings>
来启用,如果项目里的项目都是需要启用的,那就可以直接声明在 Directory.Build.props
中,放在项目根目录下,如下所示:
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
除了 PropertyGroup
之外,我们也可以定义 <ItemGroup>
,下面就是一个示例:
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Using Include="WeihanLi.Common"/>
<Using Include="WeihanLi.Common.Helpers"/>
<Using Include="WeihanLi.Extensions"/>
</ItemGroup>
</Project>
这样我们可以把公用的命名空间定义在 Directory.Build.props
上, MSBuild 会按目录结构依次寻找上层的 Directory.Build.props
,找到第一个之后就会停止再往上寻找,下面是一个示例
c:\\users\\username\\code\\test\\case1
c:\\users\\username\\code\\test
c:\\users\\username\\code
c:\\users\\username
c:\\users
c:\\
如果项目较多可以使用多层 Directory.Build.props
,下面是一个示例:
\\
MySolution.sln
Directory.Build.props (1)
\\src
Directory.Build.props (2-src)
\\Project1
\\Project2
\\test
Directory.Build.props (2-test)
\\Project1Tests
\\Project2Tests
所有项目 (1) 的通用属性、src 项目 (2-src) 的通用属性,以及 test 项目 (2-test) 的通用属性
前面我们提到过,MSBuild 对于指定项目找到第一个 Directory.Build.props
就会停止再向上寻找 Directory.Build.props
如果要同时使用多级 Directory.Build.props
则需要显式导入上层的 Directory.Build.props
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
Sample
下面我们来看一些使用示例吧
Sample1
在稍微复杂一些项目,往往会引用很多的 Nuget 包,而一些项目的版本可能是有关系的,有些包的版本是一致的,此时我们可以考虑定义一个属性,而在包版本的地方则引用这个属性
项目根目录下 Directory.Build.props
内容
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<EFVersion>6.0.0-rc.1.*</EFVersion>
</PropertyGroup>
项目文件中内容:
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(EFVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(EFVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(EFVersion)" />
</ItemGroup>
这样我们如果需要更新 EF 的版本,我们只需要更新 Directory.Build.props
文件中的 EFVersion
这个属性就可以了,详细配置可以参考:https://github.com/WeihanLi/WeihanLi.EntityFramework
Sample2
我们再来看一个多个层级使用的示例,项目结构如下所示:
Directory.Build.props
--src
--tests
--Directory.Build.props
----UnitTest
----IntegrationTest
项目根目录下 Directory.Build.props
,主要定义 package 相同的属性配置以及启用可控引用类型,隐式命名空间和公用的命名空间
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PackageIcon>icon.png</PackageIcon>
<PackageTags>HTTPie http https curl rest</PackageTags>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/WeihanLi/dotnet-httpie</RepositoryUrl>
<PackageProjectUrl>https://github.com/WeihanLi/dotnet-httpie</PackageProjectUrl>
<Product>dotnet-HTTPie</Product>
<Authors>WeihanLi</Authors>
<PackageReleaseNotes>https://github.com/WeihanLi/dotnet-httpie/tree/main/docs/ReleaseNotes.md</PackageReleaseNotes>
<Copyright>Copyright 2021 (c) WeihanLi</Copyright>
</PropertyGroup>
<ItemGroup>
<Using Include="WeihanLi.Common"/>
<Using Include="WeihanLi.Common.Helpers"/>
<Using Include="WeihanLi.Extensions"/>
</ItemGroup>
</Project>
tests
目录下 Directory.Build.props
,定义了测试项目公用的命名空间,并引入了上一层 Directory.Build.props
中的属性
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
<ItemGroup>
<Using Include="FluentAssertions"/>
<Using Include="Xunit"/>
</ItemGroup>
</Project>
IntegrationTest
项目文件,引入自己需要的命名空间引用
<ItemGroup>
<Using Include="HTTPie"/>
<Using Include="HTTPie.Implement"/>
<Using Include="HTTPie.Middleware"/>
<Using Include="HTTPie.Models"/>
<Using Include="HTTPie.Utilities"/>
</ItemGroup>
具体配置可以参考:https://github.com/WeihanLi/dotnet-httpie
More
使用好 Directory.Build.props
可以简化项目配置,使得项目更容易维护,如果还没用起来的可以尝试一下哈
References
https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?WT.mc_id=DT-MVP-5004222&view=vs-2019
https://github.com/WeihanLi/SparkTodo/blob/master/Directory.Build.props
https://github.com/WeihanLi/SamplesInPractice/tree/master/net6sample
https://github.com/WeihanLi/WeihanLi.EntityFramework/blob/dev/Directory.Build.props
https://github.com/WeihanLi/dotnet-httpie/blob/dev/Directory.Build.props
https://github.com/WeihanLi/dotnet-httpie/blob/dev/tests/Directory.Build.props
以上是关于使用 Directory.Build 来消除项目文件中的重复配置的主要内容,如果未能解决你的问题,请参考以下文章
当解决方案包含框架和核心项目时,Directory.Build.props 不起作用