将 .NET Core 项目打一个最简单的 NuGet 源码包,安装此包就像直接把源码放进项目一样

将 .NET Core 项目打一个最简单的 NuGet 源码包,安装此包就像直接把源码放进项目一样

2018-06-20 01:22

NuGet 原本就提供了生成源码包的功能。不过,NuGet 原生的源码包仅用于调试时自带调试信息和调试源码。

本文将以最简单的方式制作一个源码引用包。安装 NuGet 包后,不会生成任何程序集引用,而是相当于将源码直接放入被安装的程序集中一样。


准备工作

我们需要一个可以用来打 NuGet 包的 .NET Core 项目,只需要在 Visual Studio 中新建一个即可。在本例中,我的项目名字是 Walterlv.Demo。

将源码加入 NuGet 包

项目文件中的已知 NuGet 属性(使用这些属性,创建 NuGet 包就可以不需要 nuspec 文件啦) 中,我说到了项目文件中的各种 NuGet 属性。在本文中,我们将使用到其中的一部分。

这些属性将设置到项目文件 Walterlv.Demo.csproj 中。

<!-- 将源码引入包中。 -->
<IncludeSource>true</IncludeSource>
<!-- 如果指定为 true,那么生成的 dll 将拷贝到 NuGet 包的 tools 目录下。 -->
<IsTool>true</IsTool>

为了避免将打出来的 NuGet 包作为 dll 被安装的程序集引用,我们需要设置 <IsTool>true</IsTool> 属性。这样,生成的 dll 将只会放入 tools 文件夹中,而不会被引用。

这时,项目的 csproj 文件像这样:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <IncludeSource>True</IncludeSource>
    <NoPackageAnalysis>true</NoPackageAnalysis>
    <IsTool>True</IsTool>
    <DevelopmentDependency>true</DevelopmentDependency>
  </PropertyGroup>
  
</Project>

设置后编译项目,我们将在输出目录得到 Walterlv.Demo.nupkg 和 Walterlv.Demo.1.0.0.symbols.nupkg 两个文件。

这种带后缀形式的包在只是 NuGet 的辅助包而已,不是主包。在 How to create NuGet symbol packages - Microsoft Docs 中说明这种 symbols 的包只是用于调试的。然而,我们需要的是将其作为直接引用的主包。这种情况下,Walterlv.Demo.nupkg 因为不能满足我们的目的,所以我们并不能使用它。所以,我们需要做的是,将 Walterlv.Demo.1.0.0.symbols.nupkg 变成主包。

于是,我们编写一个 <Target /> 将 symbols 包替换主包:

<Target Condition="$(IncludeSource) == 'True' Or $(IncludeSymbols) == 'True'" Name="UseSymbolsInsteadOfLib" AfterTargets="GenerateNuspec">
  <Delete Files="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).nupkg" />
  <Move SourceFiles="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).symbols.nupkg" DestinationFiles="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).nupkg" />
</Target>

这里使用到了 <Delete /><Move /> 两个自带的 Task,用于将功能不全的主包删除,然后将我们的源码包替换成为主包。我此前写过 如何编写基于 Microsoft.NET.Sdk 的跨平台的 MSBuild Target 介绍了一些自带的 Task。如果你想了解更多 <Target /> 编写相关的知识,也可以阅读这篇文章。

在增加了上面的一段 <Target /> 之后,最终我们将只会得到一个 NuGet 包,打开后能发现其中包含源码。

安装 NuGet 包时引入源码

为了让源码能随着包的安装加入到目标项目,我们需要 targets 文件来将源码引入。

在项目中新建 Assets 文件夹,这将用来放即将存入 NuGet 包中的文件。新建 Assets\build\Package.targets 文件,这个文件会被自动引入到被安装的项目中。

于是我们在 csproj 中额外添加一些代码将这个文件在打包时改名为正确的名称。

<ItemGroup>
  <None Include="Assets\build\*.targets" Pack="True" PackagePath="build\$(PackageId).targets" />
</ItemGroup>

于是,整个 csproj 文件看起来是这样:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <IncludeSource>True</IncludeSource>
    <NoPackageAnalysis>true</NoPackageAnalysis>
    <IsTool>True</IsTool>
    <DevelopmentDependency>true</DevelopmentDependency>
  </PropertyGroup>
  
  <ItemGroup>
    <None Include="Assets\build\*.targets" Pack="True" PackagePath="build\$(PackageId).targets" />
  </ItemGroup>

  <Target Condition="$(IncludeSource) == 'True'" Name="UseSymbolsInsteadOfLib" AfterTargets="GenerateNuspec">
    <Delete Files="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).nupkg" />
    <Move SourceFiles="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).symbols.nupkg" DestinationFiles="$(PackageOutputAbsolutePath)$(PackageId).$(PackageVersion).nupkg" />
  </Target>

</Project>

而至于我们刚刚新建的 Package.targets 文件中,我们也需要为目标项目填写一些内容:

<Project>

  <Target Name="WalterlvDemoIncludeSource" BeforeTargets="CoreCompile">
    <Message Text="$(MSBuildThisFileDirectory)..\src\Walterlv.Demo\**\*.cs" />
    <ItemGroup>
      <Compile Include="$(MSBuildThisFileDirectory)..\src\Walterlv.Demo\**\*.cs" />
    </ItemGroup>
  </Target>

</Project>

这样,一旦目标程序集安装了这个 NuGet 包,便会将所有的 cs 文件加入到目标项目的编译中。

本文会经常更新,请阅读原文: https://walterlv.com/post/the-simplest-way-to-pack-a-source-code-nuget-package.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

.NET Core RC2发布在即,我们试着用记事本编写一个ASP.NET Core RC2 MVC程序

在.NET Core 1.0.0 RC2即将正式发布之际,我也应应景,针对RC2 Preview版本编写一个史上最简单的MVC应用。由于VS 2015目前尚不支...

200100
来自专栏葡萄城控件技术团队

ASP.NET MVC 5 - 创建连接字符串(Connection String)并使用SQL Server LocalDB

您创建的MovieDBContext类负责处理连接到数据库,并将Movie对象映射到数据库记录的任务中。你可能会问一个问题,如何指定它将连接到数据库? 实际上,...

37080
来自专栏Flutter入门

Android adb无线调试脚本

使用adb的无线调试功能十分的方便。 但是实际工作中,总是要手动输入,十分麻烦。所以就把它写成脚本文件。

29220
来自专栏cnblogs

这样入门asp.net core 之 静态文件

本文章主要说明asp.net core中静态资源处理方案: 一、静态文件服务 首先明确contentRoot和webroot这两个概念 contentRoot:...

32950
来自专栏NetCore

Do you kown Asp.Net Core -- 配置Kestrel端口

Kestrel介绍 在Asp.Net Core中,我们的web application 其实是运行在Kestrel服务上,它是一个基于libuv开源的跨平台可运...

40980
来自专栏有困难要上,没有困难创造困难也要上!

Pyinstaller ERROR: Assembly amd64_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_none not found

48480
来自专栏GuZhenYin

SignalR系列续集[系列8:SignalR的性能监测与服务器的负载测试]

前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测...

26160
来自专栏along的开发之旅

win下xamarin和64位Android Studio共存

下了xamarin的installer.exe,打开后提示安装32位jdk1.7,(-。-;),没办法,32位就32位吧,装就装吧。。。。。。。。很长很长时间后...

9110
来自专栏walterlv - 吕毅的博客

如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包

发布于 2018-05-11 16:04 更新于 2018-09...

13710
来自专栏大内老A

.NET Core多平台开发体验[1]: Windows

微软在千禧年推出 .NET战略,并在两年后推出第一个版本的.NET Framework和IDE(Visual Studio.NET 2002,后来改名为Visu...

35460

扫码关注云+社区

领取腾讯云代金券