NuGet包卸载后如何自动执行静态文件清理自定义操作
实现方案
uninstall.ps1 被弃用后,NuGet 没有提供包卸载瞬间触发的官方钩子,但可以通过 MSBuild 机制实现卸载后首次构建自动清理残留,不需要依赖任何已废弃的脚本能力,目前有两种成熟的落地方式:
- 方案1:持久化清理目标实现自动删除
不需要把清理逻辑放在NuGet包自带的.targets文件里——毕竟包卸载后自带的targets就不会被项目加载了。可以在第一次执行复制静态文件的逻辑时,往项目的obj目录(也就是$(MSBuildProjectExtensionsPath)路径,这个目录下的.targets文件会被项目自动导入,和项目本身引用什么包无关)写入一个独立的清理目标文件,逻辑如下:- 每次构建时先判断当前项目是否还引用你的NuGet包
- 如果检测到包引用已经移除,自动删除之前复制到
MyDestination目录下的所有文件和目录本身 - 清理完成后自动删除这个清理目标文件本身,避免重复执行
对应修改后的target代码如下,把里面的MyPackageName替换成你实际的NuGet包ID即可:
<Target AfterTargets="Build" Name="CopyPackageStaticFiles"> <Copy SourceFiles="@(SourceModuleFiles)" DestinationFolder="$(MSBuildProjectDirectory)\MyDestination" SkipUnchangedFiles="true"/> <!-- 写入独立清理目标到obj目录 --> <WriteLinesToFile File="$(MSBuildProjectExtensionsPath)\MyPackage.Cleanup.targets" Overwrite="true" Lines='<Project> <Target Name="RunMyPackageCleanup" BeforeTargets="Build"> <PropertyGroup> <_HasPackageReference>@(PackageReference->WithMetadataValue("Identity", "MyPackageName")->Count())</_HasPackageReference> </PropertyGroup> <ItemGroup Condition="$(_HasPackageReference) == 0"> <_ResidualFiles Include="$(MSBuildProjectDirectory)\MyDestination\**\*"/> </ItemGroup> <Delete Files="@(_ResidualFiles)" Condition="$(_HasPackageReference) == 0"/> <RemoveDir Directories="$(MSBuildProjectDirectory)\MyDestination" Condition="$(_HasPackageReference) == 0 And Exists("$(MSBuildProjectDirectory)\MyDestination")"/> <Delete Files="$(MSBuildProjectExtensionsPath)\MyPackage.Cleanup.targets"/> </Target> </Project>'/> </Target>
这个方案兼容所有使用PackageReference格式的项目(VS2017及以上版本、所有.NET Core/.NET 5+项目、SDK风格的.NET Framework项目),用户卸载包之后只要执行一次构建,残留文件就会被自动清理,实际使用几乎感知不到和即时卸载的差异。
- 方案2:改用官方静态文件打包规则,从根源避免残留
如果不是强制要求静态文件出现在用户项目的源码目录树中,完全可以放弃自定义复制target的实现,直接用NuGet原生的contentFiles规则打包静态资源,配置构建/发布时自动输出到对应目录:
<ItemGroup> <None Include="你的静态文件路径\**\*" Pack="true" PackagePath="contentFiles\any\any\MyDestination" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" Flatten="false"/> </ItemGroup>
这种方式是NuGet官方推荐的静态资源处理方案,文件不会被复制到用户的源码目录,只会在构建、发布时输出到产物目录,包卸载后不会留下任何残留,连清理逻辑都不需要编写,兼容性远好于自定义复制target。
注意:以上方案针对目前主流的PackageReference引用格式生效,如果需要兼容已经淘汰的packages.config格式的老旧项目,没有太好的自动化清理方案,可以在包的说明文档中标注手动删除对应目录即可。
内容的提问来源于stack exchange,提问作者Monika
相关产品推荐
相关产品推荐

