建设证件查询官方网站,wordpress设计素材主题,网站做任务给钱的,做网站是咋收费的序言在大前年#xff0c;为了说服框架组采用Nuget包的形式分发框架类库#xff0c;我费了老鼻子的劲也没有取得成功#xff0c;其中最致命的一个问题是#xff0c;nuget包不能获得源码调试级的支持#xff0c;在分发和包的管理形式上其比其他方案都优秀。最后折中的选择是… 序言在大前年为了说服框架组采用Nuget包的形式分发框架类库我费了老鼻子的劲也没有取得成功其中最致命的一个问题是nuget包不能获得源码调试级的支持在分发和包的管理形式上其比其他方案都优秀。最后折中的选择是采用源码直接引用项目的方式这种方案对框架类库的新分支的开发不是很有利在源码的保护上更是完全没有了保障不过在当时场景下也算是可以接受的方案之一了。而经过这几年的发展微软在这些方面都有了长足的发展那跟着我来看看能否解决各位心中的疑惑1. 历史悠久的PDB当看到一个人光鲜亮丽光彩照人的时候我们都有着一股探究其老底的冲动。是啊凭啥他就能行而我们就不行呢我们起起底探究下他的小秘密说不定从他身上能发掘出不为人知的一面为我们的崛起提供一些参考的方向这不香吗扯得有点远了我们回归正题。1.1 PDB 和符号文件PDB全称Program Database由微软开发的一种调试符号文件存储格式在windows系统中为了调试dll或者exe文件需要有一个符号文件(Symbols file)来支撑调试。符号文件保存多个数据这些数据在运行二进制文件时实际上并不需要但在调试过程中可能非常有用。通常符号文件可能包含全局变量局部变量函数名称和其入口点的地址帧指针省略 (FPO) 记录源行号调试时必须确保调试器能够访问与正在调试的目标关联的符号文件。实时调试和调试崩溃转储文件都需要符号。你必须获取要调试的代码的正确符号并将这些符号加载到调试器中。而PDB文件就是windows保留符号的文件格式。熟悉C的朋友应该对这个文件非常熟悉它伴随着Visual Studio 和WinDbg而产生可谓是历史悠久的文件格式之一。什么想看看PDB文件保存的是啥玩意好吧本尊就满足你的好奇心,在windows的调试工具有个dbh小工具可以查看pdb的文件内容。mysymbols [1000000]: symopt -2Symbol Options: 0x14c13
Symbol Options: 0x14c11mysymbols [1000000]: addr 102cb4e_MyFunction14name : _InterlockedIncrement4addr : 102cb4esize : 0flags : 0type : 0
modbase : 1000000value : 0reg : 0scope : SymTagNull (0)tag : SymTagPublicSymbol (a)index : 2ab当然了符号文件本身也有很多格式例如大名鼎鼎的COFF是Unix下常用的调试符号文件格式。1.2 PDB的变种-便携式PDB为了能适应跨平台的需求微软提出了便携式PDB(Portable PDB )标准以便和长期使用的Windows PDB相区别。其主要支持.NET中的托管代码。从历史上看Windows PDB用于存储本机代码和托管代码的调试信息其用于读取和写入这些PDB的工具仅在Windows平台上得到支持。便携式PDB旨在以平台无关的格式有效地存储托管的调试信息其在多个平台上的有着丰富的支持工具其以可移植格式存储托管的调试信息并会生成更小的PDB这在考虑分发大小时也是重要的优势。2 使用符号调试2.1 想要调试三方库或.net 框架让我们来看一个例子。有时您想进入框架以查看发生了什么特别是如果发生了意外的事情。假设您如同下面所示设置了断点。那么在按F11想进入框架内部的时候代码直接往下面执行了这就是您所看到的。默认情况下Visual Studio在调试应用程序时仅逐步执行代码。这是一个非常有用的功能因为您通常希望理解和研究自己所编写代码的逻辑。关注自己是人生在牙牙学语阶段就开始逐渐不断增长的意识因此始于人性才是最好的Feature启用这种体验的功能被恰当地称为仅我的代码(“ Just my Code”)。在某天您想调试第三方组件或平台本身的逻辑在这之前进行调试非常困难。主要是两个方面的困难缺少第三方组件或平台二进制文件的符号缺少第三方组件或平台二进制文件匹配的符号相关联的源文件。相比而言JavaScript具有与.NET几乎相反的问题。JavaScript社区包括浏览器和node.js变体都使用SourceMap其提供了调试第三方精简代码的良好体验。但是JavaScript编辑器无法提供“仅我的代码”的体验。对于.NET Core 开发人员我们希望能够轻松自然地在默认的“ 仅我的代码”体验以及带有第三方组件和平台源调试之间进行自由切换这一切并不是梦2.2 调试.net core 平台代码那我们怎么能够调试三方库或.net 框架呢Visual Studio 2017版中已经支持了符号调试在VS 的 工具菜单下选择选项/调试/常规页签配置如下参数:禁用 “启用仅我的代码”启用源链接选择选项/调试/符号页签配置如下参数:选择 Microsoft符号服务器选择 NuGet.org 符号服务器如果调试的是nuget库在缓存符号目录中设定一个目录避免多次下载符号库。如果使用的是VS Code可以为每个项目配置调试器设置launch.jsonjustMyCode: false,
symbolOptions: {searchMicrosoftSymbolServer: true,searchNuGetOrgSymbolServer: true
},
suppressJITOptimizations: true,
env: {COMPlus_ZapDisable: 1,COMPlus_ReadyToRun: 0
}注意并非nuget.org上的每个库都会为其.pdb文件建立索引。如果发现调试器找不到正在使用的开源库的PDB文件请鼓励作者上载其PDB只有Microsoft提供的库才会在Microsoft符号服务器上拥有其.pdb文件因此如果您只对三方库感兴趣可以禁用该选项。启动调试发现VS开始下载符号文件下载完毕后进入断点。当我们按F11后弹出如下界面3. SourceLinkSource Link是开发人员的一项生产力功能它允许在编译过程中将有关程序集原始源代码的唯一信息嵌入到PDB中的一组软件包和规范 通过SourceLink添加到PDB文件中的元数据和本地源代码文件、仓库内的代码文件建立了一个映射关系。因此Visual Studio调试时可以在需要时下载文件, 并为用户提供源代码调试, Microsoft库例如.NET Core和Roslyn都已启用Source Link。3.1 为什么使用SourceLink呢大多数调试是针对开发人员计算机上本地构建的源代码完成的。在这种情况下将二进制文件与源代码匹配并不困难。但是在许多调试方案中原始源代码没法立即就可用。这方面的两个很好的例子是调试崩溃转储或第三方库。在这些情况下对于开发人员来说要获取为生成正在调试的二进制文件而构建的确切源代码可能非常困难可能是特定的版本。Source Link通过在PDB中嵌入有关源代码的唯一信息例如git commit hash来解决此问题。诊断工具例如调试器可以使用此独特信息从托管服务例如GitHub中检索原始源代码。sourcelink 最初的版本是 ctaggart 实现的目前已归档 现在已经加入了 .Net 团队微软人员和ctaggart 一起做了现在的版本。官网地址: https://github.com/dotnet/sourcelink3.2 SourceLink的文件规范SourceLink 是一个Json配置的文件其内容格式如下{$schema: http://json-schema.org/draft-04/schema#,title: SourceLink,description: A mapping of source file paths to URLs,type: object,properties: {documents: {type: object,minProperties: 1,additionalProperties: {type: string},description: Each document is defined by a file path and a URL. Original source file paths are compared case-insensitively to documents and the resulting URL is used to download source. The document may contain an asterisk to represent a wildcard in order to match anything in the asterisks location. The rules for the asterisk are as follows:1. The only acceptable wildcard is one and only one *, which if present will be replaced by a relative path.2. If the file path does not contain a *, the URL cannot contain a * and if the file path contains a * the URL must contain a *.3. If the file path contains a *, it must be the final character.4. If the URL contains a *, it may be anywhere in the URL.}},required: [documents]
}为了减轻生成该json的工作量微软提供了一系列的软件包自动生成Source Link 文件。3.3 自动生成SourceLink在.net core项目内在.csproj文件内增加如下配置Project SdkMicrosoft.NET.SdkPropertyGroupTargetFrameworknetcoreapp2.1/TargetFramework!-- Optional: Publish the repository URL in the built .nupkg (in the NuSpec Repository element) --PublishRepositoryUrltrue/PublishRepositoryUrl!-- Optional: Embed source files that are not tracked by the source control manager in the PDB --EmbedUntrackedSourcestrue/EmbedUntrackedSources!-- Optional: Build symbol package (.snupkg) to distribute the PDB containing Source Link --IncludeSymbolstrue/IncludeSymbolsSymbolPackageFormatsnupkg/SymbolPackageFormat/PropertyGroupItemGroup!-- Add PackageReference specific for your source control provider (see below) -- /ItemGroup
/Project按照需要引用下面的软件包注意这里设置为 PrivateAssets以避免发布为nuget包后引用该包的项目下载sourcelink 包。github.com and GitHub EnterpriseItemGroupPackageReference IncludeMicrosoft.SourceLink.GitHub Version1.0.0 PrivateAssetsAll/
/ItemGroupAzure Repos (former Visual Studio Team Services)ItemGroupPackageReference IncludeMicrosoft.SourceLink.AzureRepos.Git Version1.0.0 PrivateAssetsAll/
/ItemGroupAzure DevOps Server (former Team Foundation Server)ItemGroupPackageReference IncludeMicrosoft.SourceLink.AzureDevOpsServer.Git Version1.0.0 PrivateAssetsAll/
/ItemGroup如果您的服务器配置有非空的IIS虚拟目录请在SourceLinkAzureDevOpsServerGitHost项目中指定此目录如下所示ItemGroupSourceLinkAzureDevOpsServerGitHost Includeserver-name VirtualDirectorytfs/
/ItemGroup该Include属性指定域以及服务器的端口例如server-name或server-name:8080。GitLabItemGroupPackageReference IncludeMicrosoft.SourceLink.GitLab Version1.0.0 PrivateAssetsAll/
/ItemGroupBitbucketItemGroupPackageReference IncludeMicrosoft.SourceLink.Bitbucket.Git Version1.0.0 PrivateAssetsAll/
/ItemGroup如果您的项目是由版本4.7之前的Bitbucket Server或Bitbucket Data Center托管的SourceLinkBitbucketGitHost则除了软件包参考之外还必须指定项目组ItemGroupSourceLinkBitbucketGitHost Includebitbucket.yourdomain.com Version4.5/
/ItemGroup项目组SourceLinkBitbucketGitHost指定Bitbucket主机的域和Bitbucket的版本。该版本非常重要因为用于访问文件的URL格式随版本4.7更改。默认情况下源链接采用新格式4.7版。gitweb (pre-release)ItemGroupPackageReference IncludeMicrosoft.SourceLink.GitWeb Version1.1.0-beta-20204-02 PrivateAssetsAll/
/ItemGroup开发人员必须选择生成源链接文件。这些文件中包含的URL可能指向私有源存储库这些存储库可能不打算公开给有权访问符号文件的任何人因此开发人员应做出明智的选择。开源开发人员通常选择不参与源链接文件生成因为他们通常不存在公开问题。公司开发人员还应选择采用以下方式选择源链接文件生成所有应用程序资产二进制文件符号和源代码都在公司防火墙内使用因此只有有权访问这些资产的用户才能看到它们。二进制资产是从外部运送的但符号和源仅在公司防火墙内使用过因此只有有权访问符号和源资产的用户才可以查看它们。公司开发人员还有另一个选择可以说是反模式如下所示:二进制和符号资产在外部共享。符号资产包含源链接文件以及可能生成的文件资产。源链接文件指向需要身份验证的符号源例如VSTS。授权用户数量可能很少将可以访问源。未经授权的用户数量可能更多会从他们不理解的端点接收拒绝访问的消息。3.4 源嵌入在某些情况下将源代码嵌入符号中是有益的这样您就可以方便地部署源代码进行调试。但是这是在便利性和PDB大小之间进行权衡的。尽管将源压缩存储在包含许多源文件的PDB中但可能会大大增加PDB的大小。以下嵌入选项适用于Windows和便携式PDB均可用仅嵌入源代码管理未跟踪的源文件例如在生成期间生成的文件。其余文件由源链接映射。嵌入手动选择的源文件子集。嵌入所有源文件EmbedAllSources具有布尔值的Project属性表示所有传递给编译器的源都应嵌入到PDB中。自动嵌入未跟踪的源文件源链接使调试器和其他工具可以查找源控件跟踪的文件的源内容。但是并非所有参与构建的文件都被跟踪。例如在构建期间生成的文件通常不检入存储库。尽管可以手动识别此类文件并标记它们以将其嵌入到PDB中但是这种过程繁琐且容易出错。该SourceLink.Embed项目已经支持自动识别而不是由源代码控制跟踪文件的嵌入。这些API将确定源代码控制未跟踪的文件例如对于git存储库匹配.gitignore文件中条目的文件和设置EmbedUntrackedSources然后将指示编译器嵌入未跟踪的源代码。下面是嵌入源代码的例子在.csproj项目文件内增加如下配置PropertyGroup EmbedAllSourcesTrue/EmbedAllSources!--EmbedUntrackedSourcestrue/EmbedUntrackedSources--
/PropertyGroup4.发布符号文件默认情况下符号被构建为单独的文件以最小化二进制文件的大小。这些文件需要由构建它们的系统例如CI服务器发布并由需要它们的系统例如调试器发现和检索。4.1将符号发布到符号服务器如今符号服务器主要用于在企业环境中托管符号文件。符号服务器工具可用于此类环境并且最近也已集成到VSTS中并作为服务公开。对于在NuGet.org上发布其库的开发人员而言可公开使用的符号服务器的选项受到限制并且发布和使用符号的过程比应有的要复杂得多。因此在NuGet.org上发布的易于调试的软件包数量很少。符号包snupkg今天符号包用于分发符号和源。良好的调试体验依赖于调试符号的存在因为它们提供了一些关键信息例如已编译的代码与源代码之间的关联、局部变量的名称、堆栈跟踪等。你可以使用符号包 (.snupkg) 来分发这些符号并改善 NuGet 包的调试体验。如果使用 dotnet CLI 或 MSBuild则除 .nupkg 文件外还需要设置 IncludeSymbols 和 SymbolPackageFormat 属性以创建 .snupkg 文件。创建 .snupkg 文件有多种方式实现该需求。将以下属性添加到 .csproj 文件PropertyGroupIncludeSymbolstrue/IncludeSymbolsSymbolPackageFormatsnupkg/SymbolPackageFormat
/PropertyGroup在命令行上指定这些属性dotnet pack MyPackage.csproj -p:IncludeSymbolstrue -p:SymbolPackageFormatsnupkg或者使用msbuildmsbuild MyPackage.csproj /t:pack /p:IncludeSymbolstrue /p:SymbolPackageFormatsnupkg使用nugetnuget pack MyPackage.nuspec -Symbols -SymbolPackageFormat snupkg
nuget pack MyPackage.csproj -Symbols -SymbolPackageFormat snupkg发布服务包到nuget# 为方便起见首先使用 NuGet 保存 API 密钥
nuget SetApiKey Your-API-Key
# 将主包发布到 nuget.org 后按如下方式推送符号包。
nuget push MyPackage.snupkg
# 还可以使用以下命令同时推送主包和符号包。当前文件夹中必须同时有 .nupkg 和 .snupkg 文件。
nuget push MyPackage.nupkg4.2 不使用服务器直接嵌入发布符号包和源文件嵌入符号文件和源代码更简单它不需要网络或互联网连接也不需要任何配置即可指定源代码存储库和符号服务器的位置。因为配置私有的符号包服务我暂时并没有找到合适的平台因此我高度推荐你采用这种方式非常的便捷您只需要在csproj内增加如下代码即可完成嵌入的便携式PDB以及源文件的发布。PropertyGroupDebugSymbolsTrue/DebugSymbolsDebugTypeEmbedded/DebugTypeEmbedAllSourcesTrue/EmbedAllSources
/PropertyGroup对于.NET应用程序来说嵌入PDB文件不会影响编译器的优化所以也完全不会影响应用的性能。4.3 使用私有gitlab保护代码结合第3小节的介绍我们可以很方便的结合gitlab sourceLink来制作嵌入符号包保护源码的发布方式PropertyGroupTargetFrameworknetcoreapp3.1/TargetFramework !-- Optional: Publish the repository URL in the built .nupkg (in the NuSpec Repository element) --PublishRepositoryUrltrue/PublishRepositoryUrl!-- Optional: Embed source files that are not tracked by the source control manager in the PDB --EmbedUntrackedSourcestrue/EmbedUntrackedSources!-- Optional: Build symbol package (.snupkg) to distribute the PDB containing Source Link --DebugTypeEmbedded/DebugType!--IncludeSymbolsfalse/IncludeSymbolsSymbolPackageFormatsnupkg/SymbolPackageFormat--/PropertyGroupItemGroupPackageReference IncludeMicrosoft.SourceLink.GitLab Version1.0.0 PrivateAssetsAll //ItemGroup如果能早点提供该方式相信几年前的方案我应该能胜出是吧5.使用PDB符号和SourceLink在Visual Studio或其他工具中使用符号应该很方便。它需要适用于所有.NET实现包括.NET Core.NET FrameworkXamarinUnity和UWP。使用符号进行调试的主要场景有以下三种在开发阶段调试应用程序。在这种情况下需要在构建系统外部检索第三方库符号同时将应用程序符号生成为构建的一部分。在部署状态下调试应用程序。在这种情况下需要检索应用程序和库符号。该方案将附加到正在运行的应用程序。调试应用程序的故障转储。在这种情况下需要应用程序和库符号。5.1符号和二进制文件一起分发此方案适用于开发阶段。如果符号已经嵌入二进制文件中则不适用。NuGet是二进制分发的一种常见情况它允许将符号和二进制文件一起部署。关键特征是符号文件将直接存在于磁盘上已加载的代码文件旁边从而使调试器可以轻松地找到给定二进制文件的匹配符号文件。根据本文档中的指导二进制文件和符号通常会以与以下示例类似的结构并置在NuGet包中。//lib/netstandard2.0foo.dllfoo.pdb.NET Core开发是以NuGet为中心的这有助于解决此问题。在开发过程中例如使用dotnet run. NET Core运行时默认情况下从NuGet缓存加载库从而使调试器可以在同一位置查找匹配的符号文件。.NET Framework开发使用NuGet但形式上使用较少。构建项目时NuGet库将被复制到应用程序bin目录而不是符号。结果代码二进制和符号之间的链接丢失了。构建系统应使用以下逻辑以更好地启用带符号的调试如果将代码二进制文件复制到某个位置则还要将符号文件复制到同一位置。在大多数情况下这将是应用程序bin目录。5.2 符号和二进制文件分开分发此方案适用于调试已部署的应用程序崩溃转储以及调试NuGet软件包中未附带符号的第三方库。在这些情况下您需要从符号服务器获取符号。如上所述我们建议为上传到NuGet.org的符号提供公共符号服务。您也可以根据需要使用其他符号服务器。5.3 获取和消耗源文件获取和消耗源文件主要是首先具有获取符号的功能。有了符号后调试器将发现以下一种或多种情况是正确的符号文件包含调试器正在寻找的源文件的嵌入式源此时调试器将使用该源。该符号文件是Windows PDB包含嵌入式源服务器信息。可以使用诸如pdbstr或GitLink之类的构建工具使用源服务器信息来修改现有的Windows PDB。该符号文件包含一个嵌入式源链接文件此时调试器将解释并执行源链接文件中的声明。否则将无法通过本文档中讨论的机制获得源注意如果调试器无法在符号文件中或通过源链接找到源文件它仍可以尝试使用**简单符号查询协议**在符号服务器上查找它。这将允许在二进制文件和符号构建完成之后稍后使源可用的情况。6 小结弄懂SourceLink和pdb的关系竟然花费了我一个元旦假期本来计划在假期内出篇文章简单介绍下发现在自己都没有搞清楚的情况写这些是对大家和自己的不负责任因此还是静下心来仔细理清楚各个环节希望能对大家有所帮助。