各位老铁们,大家好,今天由我来为大家分享net新闻网站源码分享,以及新闻发布网站源码的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
前言
随着.NET5.0Preview8的发布,许多新功能正在被社区成员一一探索;这其中就包含了“单文件发布”这个炫酷的功能,实际上,这也是社区一直以来的呼声,从WinForm的msi开始,我们就希望有这样一个功能,虽然在docker时代,单文件发布的功能显得“不那么重要”,但正是从这一点可以看出,.NET的团队成员一直在致力于实用功能的完善。
在Java的世界里,单文件发布一直伴随着他们的成长,War文件可以直接上传到Tomcat上运行,话说我们还是有那么一丢丢的羡慕的,不过凡事有利就有弊,单文件发布对于细分模块的热更新来说,还有有一点点的不方便。
不过瑕不掩瑜,在微服务概念越来越火热的今天,相信单文件发布的功能带给大家更多的是兴奋。
什么是单文件发布
首先,我们要清楚的了解,什么是单文件发布。
官方的目标定义:
.Net5.0单个文件解决方案应为:
广泛兼容:可以将包含IL程序集,随时运行的程序集,复合程序集,本机二进制文件,配置文件等的应用程序打包为一个可执行文件。可以直接从打包软件直接运行应用程序的托管组件,而无需提取到磁盘。可与调试器和工具一起使用。
从上面的目标可以看出,和以往版本最大的不同在于:将所有依赖打包到一个可执行文件中,可直接运行,不影响调试操作。
注意上面的这句话“将所有依赖打包到一个可执行文件中”,而在以往,我们使用dotnetpublish将应用程序进行发布之后,我们会看到,在publish下有许多项目依赖的dll文件,在.NET5.0到来之后,这些依赖文件可收纳到一个文件中,瞬间让人感受到了清凉。
发布操作指令相关
命令
可选参数
配置文件设置参数
除了可以使用命令行参数的形式,还可以通过配置文件的形式设置发布参数,编辑项目文件,添加配置节点到文件中并保存即可。
<PropertyGroup>\n<TargetFramework>net5.0</TargetFramework>\n<RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n<PublishSingleFile>true</PublishSingleFile>\n<IncludeContentInSingleFile>true</IncludeContentInSingleFile>\n</PropertyGroup>
关于RID说明见:https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
这是截止本文发布前的RID版本,不排除.NET5.0有新的发布
其它参数
除了上面的三个可选参数,我在查询文档的过程中还发现,官方还提到了其它参数的使用,目前不确定是否有效
<PropertyGroup>\n<SelfContained>true</SelfContained>\n<!–启用使用assemby修剪-仅支持自包含应用程序–>\n<PublishTrimmed>true</PublishTrimmed>\n<!–启用AOT编译目前暂不支持预编译–>\n<!–<PublishReadyToRun>true</PublishReadyToRun>–>\n</PropertyGroup>\n<ItemGroup>\n<ContentUpdate=&34;>\n<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n<ExcludeFromSingleFile>true</ExcludeFromSingleFile>\n</Content>\n</ItemGroup>
还可以通过设置ExcludeFromSingleFile元素,该设置将指定某些文件不嵌入单个文件之中。
编写待打包的应用程序
为了更直观的看出正常发布和单文件发布的区别,我们特别准备了一个Web应用程序,并对两个程序集进行依赖引用。
准备好项目,编译成功,尝试发布,打开PowerShel控制台,分别输入以下命令
dotnetpublish-rlinux-x64/p:PublishSingleFile=true\ndotnetpublish-rwin-x64–self-contained=false/p:PublishSingleFile=true
linux-x64和win-x64两个目录下,分别有publish目录,由于平台的不同,所引用的依赖也不一样,这是我们早就了解过的,我们看看打包前后的区别
以上执行的两条命令语句,会为我们生成Linux和Windows两个平台的程序包,从上图中可以看出,在打包之前,项目的各种引用依赖都被复制到了发布目录下,这也是我们之前的程序发布方式,在经过打包后,所有依赖文件都被装入了一个可执行文件中,在Linux平台下表现为:PreviewWebApplication,Windows平台下则为:PreviewWebApplication.exe。从打包效果来看,迁移将变得更加方便了。
运行打包程序
打包后的程序和未打包的发布程序在运行方式上没有太多的差异性,在Windows平台上,只需要双击PreviewWebApplication.exe就可以运行该打包程序了,本示例创建的是一个WebApi的程序,直接访问程序侦听的地址后得到接口返回的结果,如果您创建的是带有Razor视图或者携带其它资源文件的,可能无法访问指定的url。
在程序成功运行起来后,我们发现,打包程序并没有解压缩文件到磁盘,而是直接从包中加载文件到内存中运行;这是巨大的进步,也是和War文件根本的区别。
需要注意的是,该.exe文件并不能单独复制到别的地方运行,你必须把.exe当前目录完整的复制才能运行,这涉及到主机探测的问题,下面我们将会一一提到。
跨平台的打包文件
通过上面的示例我们了解到,打包程序总是为不同的平台生成独立的包程序,这是为什么呢?这里就涉及到一个概念,也就是ToolInterfaceStandard(TIS)
ExecutableandLinkingFormat(ELF)
CommonObjectFileFormat(COFF)于1983年引入,最初使用在AT&T的UNIX系统上。由于COFF的各种局限性,比如:节的最大数量受到限制,节名称,所包含的源文件的长度受到限制,并且符号调试信息无法支持实际的语言。最后,在SystemVRelease4(SVR4)发布后,AT&T使用ELF替代了COFF。
工具接口标准委员会援引委员会规范文件的说明:可执行文件和链接格式最初由UNIX系统开发和发布实验室(USL)作为应用程序二进制接口(API)的一部分。工具接口标准委员会(TIS)选择将不断发展的ELF标准作为便携式对象文件。该标准适用于各种操作系统的32位英特尔架构环境的格式。ELF标准旨在通过向开发人员提供具有一组跨多个操作环境的二进制接口定义。这将减少不同接口实现的数量,从而减少需要重新编写和编译的代码。
ELF文件结构又分为三种类型,分别是:
PortableExecutable(PE)
在Windows阵营,微软在此COFF标准的基础上,又进行了创新和发展出了PE文件标准
PEFormat该规范描述了Windows操作系统家族下的可执行文件(图像)和目标文件的结构。这些文件分别称为可移植可执行(PE)和公用对象文件格式(COFF)文件。
从上面的两种规范中可以看出,LinuX和Windows都有各自的文件格式规范,而这种规范在一定程度上是不兼容的,不论是从文件结构还是解析方式;所以.NET5.0中的打包程序必须为不同的平台实现独立的打包器。打包器的实现在runtime中的Microsoft.NET.HostModel库中。
认识了ELF和PE文件结构之后,我们就可以对打包器代码进行阅读理解。
Microsoft.NET.HostModel
你可以从github上下载.NET5.0的源代码,转到目录:
runtime/src/installer/managed/Microsoft.NET.HostModel
源码不太多,可直接进行阅读,主要理解层次关系即可。
打包器主要包含了三大部分的内容,分别是AppHost、Bundler、ComHost
在文件Bundle/Manifest.cs的头部,我们看到了“单文件程序”的文件结构定义
BundleManifestisadescriptionofthecontentsofabundlefile.\nThisclasshandlescreationandconsumptionofbundle-manifests.\n\nHereisthedescriptionoftheBundleLayout:\n_______________________________________________\nAppHost\n\n\n————EmbeddedFiles———————\nTheembeddedfilesincludingtheapp,its\nconfigurationfiles,dependencies,and\npossiblytheruntime.\n\n\n\n\n\n\n\n————BundleHeader————-\nMajorVersion\nMinorVersion\nNumEmbeddedFiles\nExtractionID\nDepsJsonLocation[Version2+]\nOffset\nSize\nRuntimeConfigJsonLocation[Version2+]\nOffset\nSize\nFlags[Version2+]\n——ManifestEntries———–\nSeriesofFileEntries(foreachembeddedfile)\n[FileType,Name,Offset,Sizeinformation]\n\n\n\n_________________________________________________
从上面的文件结构中,我们可以非常清晰的看到,单文件程序的结构一共分为三大部分,分别是:
文件头信息的查看
我们可以通过一些工具去查看已经打包好的文件,在Linux下,可以使用readelf/objdump等程序来获取PreviewWebApplication文件的信息。在Windows下,可以使用PETools等工具
Linux下readelf读取文件头信息
从图中我们可以看到Type:DYN(Sharedobjectfile)这是一个标准的共享对象文件,关于ELF头部信息的内容不再展开,有兴趣的同学可以自行学习相关内容。
Windows下PETools读取文件头信息
已经打包好的程序内部包含了319(Linux)、Windows(359)个文件,Windows版本在未打包前是84.3MB,打包后是69.8MB,最重要的是在运行时无需解压缩,直接从Bundle中运行文件。
文件中的第三部分,也就是“实体清单(ManifestEntries)的写入代码在Bundle\\Bundler.cs\\AddToBundle
longAddToBundle(Streambundle,Streamfile,FileTypetype)\n{\nif(type==FileType.Assembly)\n{\nlongmisalignment=(bundle.Position%AssemblyAlignment);\nif(misalignment!=0)\n{\nlongpadding=AssemblyAlignment-misalignment;\nbundle.Position+=padding;\n}\n}\nfile.Position=0;\nlongstartOffset=bundle.Position;\nfile.CopyTo(bundle);\nreturnstartOffset;\n}
在成员方法GenerateBundle(IReadOnlyListfileSpecs)内部迭代调用了AddToBundle方法,完成了实体清单文件的写入。
//代码片段\n\npublicstringGenerateBundle(IReadOnlyList<FileSpec>fileSpecs)\n{\n…\nforeach(varfileSpecinfileSpecs)\n{\nstringrelativePath=fileSpec.BundleRelativePath;\n…\nusing(FileStreamfile=File.OpenRead(fileSpec.SourcePath))\n{\nFileTypetargetType=Target.TargetSpecificFileType(type);\nlongstartOffset=AddToBundle(bundle,file,targetType);\nFileEntryentry=BundleManifest.AddEntry(targetType,relativePath,startOffset,file.Length);\nTracer.Log($&34;);\n}\n}\n\n//Writethebundlemanifest\nheaderOffset=BundleManifest.Write(writer);\n…\n}
因为解压器的实现已经转移到了HostFxr和HostPolicy中,以静态链接库的方式链接到打包器中,且该部分代码由C++进行编写,鉴于C++水平有限,在这里不作介绍。
结束语
编写这篇文章耗费了我大量的时间,期间大量阅读海量的参考资料、文献、标准文档、制作文章配图等等,写干货文章真的需要投入巨大的精力和时间,希望你们喜欢。
主要参考资料
.NET团队计划经理RichardLander的博客:https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-8/Bundler进度表:https://github.com/dotnet/runtime/issues/36590single-file:https://github.com/dotnet/designs/tree/master/accepted/2020/single-fileELF文档:https://refspecs.linuxbase.org/elf/elf.pdfELF维基百科:https://en.wikipedia.org/wiki/Executable_and_Linkable_FormatReadelf:https://sourceware.org/binutils/docs/binutils/readelf.htmlPE文档:https://docs.microsoft.com/en-us/windows/win32/debug/pe-formatPETools:https://github.com/petoolse/petools
关于本次net新闻网站源码分享和新闻发布网站源码的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。