如何在VS2017及MSBuild脚本中引用NuGet包形式的自制构建工具
Great question! Since you've migrated to PackageReference (a solid choice for maintainability), referencing your internal NuGet-hosted tools in VS2017's BeforeBuild/AfterBuild targets is straightforward and eliminates brittle hardcoded paths. Here's a step-by-step breakdown:
1. First, Confirm the PackageReference is in Place
Make sure your project includes a PackageReference for MyTool. If you haven't added it yet, insert this into your .csproj or .vbproj file (inside an <ItemGroup> section):
<PackageReference Include="MyTool" Version="X.Y.Z" />
When using PackageReference, MSBuild automatically generates a special property that points directly to the package's installation directory—this is your best friend for avoiding hardcoded paths.
2. Use the Auto-Generated MSBuild Property to Locate the Tool
MSBuild creates a property named $(PkgMyTool) (the naming pattern is Pkg[PackageName]; if your package name had spaces or dots, they'd be replaced with underscores) that resolves to the full root path of your installed MyTool package (exactly the C:\Users\Me\.nuget\packages\MyTool\X.Y.Z path you mentioned).
For example, if your tool executable lives in tools/MyTool.exe inside the NuGet package, you can call it in your BeforeBuild or AfterBuild targets like this:
<Target Name="BeforeBuild"> <!-- Use quotes around the path to handle any spaces in directories --> <Exec Command=""$(PkgMyTool)\tools\MyTool.exe" --input "$(ProjectDir)src" --output "$(IntermediateOutputPath)"" /> </Target> <Target Name="AfterBuild"> <Exec Command=""$(PkgMyTool)\tools\PostBuildValidator.exe" --target "$(OutputPath)\$(AssemblyName).dll"" /> </Target>
3. Fallback: Manual Path Construction (If Needed)
If you prefer to control the version via a shared property (for easier updates across projects), you can build the path using $(NuGetPackageRoot) (which defaults to the user's .nuget/packages folder) and a defined version variable:
<PropertyGroup> <!-- Define the version once for easy reuse --> <MyToolVersion>X.Y.Z</MyToolVersion> </PropertyGroup> <Target Name="BeforeBuild"> <Exec Command=""$(NuGetPackageRoot)MyTool\$(MyToolVersion)\tools\MyTool.exe" --arg1 value1" /> </Target>
This works with VS2017 since it uses MSBuild 15+, which supports the $(NuGetPackageRoot) property natively.
4. Compatibility Checks
- VS2017: Both methods work seamlessly in VS2017, as it uses MSBuild 15 which fully supports PackageReference and these auto-generated properties.
- MSBuild Command Line: Running
msbuild.exedirectly will resolve these properties correctly, as long as the PackageReference is present in the project file—perfect for CI/CD pipelines.
Pro Tips
- Avoid Hardcoded Paths: Never use absolute paths like
C:\Users\Me\.nuget\packages\MyTool\X.Y.Z—this breaks on other developers' machines or build servers with different user profiles. - Tool Package Setup: If your NuGet package is marked as a tool package (via the
<Tool>element in its.nuspec), some NuGet versions might add it to the system PATH, but relying on the MSBuild properties is far more reliable for build scripts.
内容的提问来源于stack exchange,提问作者TheRoadrunner

