包,元包与框架

本文翻译自 Packages, Metapackages and Frameworks

.Net Core 是一种由 NuGet 包组成的平台。一些产品体验受益于代码包的细粒度定义,而另一些受益于粗粒度的定义,这两种定义都是有用的,不能绝对地说哪个好与不好。因此,为了适应这两种区别,一款好的产品应该可以被拆分成一组一组的细粒度的代码包,这些包之间相互独立,单个代码包的正式的名字叫做“元包”(metapackage)。

每个.Net Core 包都支持运行于多种 .Net 运行时中,这些运行时被称为 “框架”(framework)。其中有的框架是传统框架,例如 net46;而另一些则是新的框架,可以认为它们是“基于包的框架”,这种是框架的另外一种新的定义模型。这些基于包的框架整个都是由包组成的,它们自身也被定义成包,这就在框架与包之间形成了一种比较密切的关系。

.Net Core被分割成为一组包,它们提供了基元类型,以及更高层的数据类型,应用组合类型,以及公共的类库。每一个包都代表着单独的同名程序集,例如,System.Runtime 这个包,就包含了 System.Runtime.dll 这个程序集。

把这些包定义成为细粒度的结构风格,有以下好处:

  • 细粒度的包可以在它自己的开发周期内交付,只需要完成仅对相关的其他有限的包进行测试即可。
  • 细粒度的包可以提供不同的OS与CPU支持。
  • 细粒度的包可以单独依赖于某一个类库。
  • 应用可以变得更小,因为没有引用的包不会变成最终发布的一部分。

上述好处仅适用于某些特定的场合。比如,Net Core 的所有包会在同一个发布周期内提供对同一个平台的支持,在这种情况下,补丁与更新会以小的单独包的形式发布。由于这种小范围的变化,补丁的验证与相关工作,都可以限制到单个平台与类库的需求范围中,这样一来,就可以把工作最小化。

以下是 基于 NuGet 库的 .Net Core 包清单:

  • Sytem.Runtime - 最基础的 .Net Core 包,包含 Object,String,Array, Action 与 IList<T>。
  • System.Collections - 一组基元泛型集合,包含 List<T> 与 Dictionary<K,V>.
  • System.Net.Http - 一组用于 HTTP 网络通信的类型,包含 HttpClient 与 HttpResponseMessage。
  • System.IO.FileSystem - 一组用于读写本地或者网络磁盘存储的类型,包含了 File 与 Dictory 类。
  • System.Linq - 一组对象查询类型,包含了 Enumerable 与 ILookup<TKey, TElement> .
  • System.Reflection - 一组用于类型加载,检查与激活的类型,包含 Assembly, TypeInfo, 与 MethodInfo

包引用在 project.json 文件中定义,在下面的例子中,使用了 System.Runtime 包:

{
"dependencies": {
"System.Runtime": "4.1.0"
},
"frameworks": {
"netstandard1.5": {}
}
}

  

在大部分情况下,你可能不需要直接引用底层的 .Net Core 包,因为引用的包太多了会让你抓狂。所以你只需要引用元包。

元包

元包就是一个 NuGet 包,方便地描述了一组意义相关的包。开发团队利用依赖关系来描述一组包,他们通过这一组包来描述一个框架(framework),然后有选择地发布出去。

引用一个元包,这个操作,实际上添加了对元包中每一个独立包的引用依赖,这意味着这些包中所有的类库(refs 或者 libs)都会在智能感知(IntelliSense)中可用,同时也会发布(lib目录)到你的应用中。

注意: lib 与 ref 指的是 NuGet 包中的相应的文件夹, ref 目录描述的是以元程序集表示的公共API包,lib 目录 包含了这个公共API的在不同框架下的实现。

使用元包有以下好处:

  • 在引用大量细粒度包方面,提供了一种方便的用户体验。
  • 定义了一组经过充分测试与工作良好的包(包括指定的各种版本)。

.Net 标准类库元包:

  • NETStandard.Library - 描述了“.Net 标准类库”的一部分。所有的 .Net 实现(例如, .Net Framework, .Net Core, Mono)都支持 .Net 标准类库,这就是 'netstandard' 框架。

以下是 .Net Core 元包:

  • Microsoft.NETCore.App - 描述了 .Net Core 发行版本的部分类库,也就是 .NETCoreApp 框架。它依赖于NETStandard.Library 这个更小的元包。
  • Microsoft.NETCore.Portable.Compatibility - 一组兼容代理,使基于 mscorlib 的 可移植类库(PCL) 得以运行在 .Net Core上。

元包的引用方法就像普通的 NuGet包一样,在 project.json 中定义。

在下面的例子中, 引用了 NETStandard.Library 这个元包,用来创建一个基于 .Net 运行时的可移植类库。

{
"dependencies": {
"NETStandard.Library": "1.5.0"
},
"frameworks": {
"netstandard1.5": {}
}
}

  

在下面的例子中,引用了 Microsoft.NETCore.App 这个元包,用来创建应用或者是类库,运行于 .Net Core之上,并且充分使用 .Net Core 所有功能。它提供的访问范围,要比 NetStandard.Library 更大。

{
"dependencies": {
"Microsoft.NETCore.App": "1.0.0"
},
"frameworks": {
"netcoreapp1.0": {}
}
}

框架

每一个 .Net Core 包都支持一组框架,在框架文件夹中进行声明(就在前面所说的 lib 与 ref目录中)。框架描述了一组可用的API(以及潜在的其他特性),所以你可以在指定一个目标框架时得到这些功能。当新的API加入时,就会进入版本管理流程。

例如, System.IO.FileSystem 支持以下框架:

  • .NETFramework,版本 4.6
  • .NETStandard,版本 1.3
  • 6种Xamarin 平台 (如, xamarinios10)

很有必要对前两种框架进行对比,因为它们各自代表了一种不同的框架定义方式。

.NETFramework,Version=4.6 这个框架代表了在 .Net Framework 4.6 中可用的API,你可以根据这些API生产自己的类库,引用其中的程序集,并以NuGet包的方发布你的类库,发布后它们会位于lib文件夹下一个名为 net46 的文件夹中。这样,你的

类库就会被那些基于或者兼容 .Net Framework 4.6 的应用程序所使用。这是传统类库的工作方式。

而.NETStandard,Version=1.3这个框架是一个基于包的框架。那些以此框架为目标的包,定义并且实现的API,就组成了这个框架。

可见它们的区别:传统的框架是事先定义好的一个整体,而基于包的框架,则可以对不同的包自由组合。

基于包的框架

框架与包之间的关系是双向的。

首先是为一个给定的框架定义了一组API,如 netstandard1.3。以 netstandard1.3 为目标的包(或者兼容框架,如netstandard1.0)定义了哪些API是可以使用的,听起来像是循环定义,然而并不是。从 “基于包的”这个词本身的角度来讲,框架的API定义是来自于包的,框架本身并不定义任何API。

其次,是这个双向关系中的资产选择。包内部可以含有不同框架的资产,对于一组包或者元包的引用,框架需要决定它应选择哪些资产,例如,是 net46 还是 netstandard1.3。对于交叉资产来说,这个非常重要,例如,一个 net46 的资产可能并不会与 .Net Framework 4.0 或者 .Net Core 1.0 兼容。


你可以在上图中看到这种关系,API 选择 框架 作为目标,并且API定义了框架, 而框架用于资产选择,资产实现了API。

这里出现了一个有趣的问题:框架定义的结束之处,正是消费开始的地方。可以把框架看成是由 project.json 文件给出的功能定义,你所依赖的东西创建了实际上的框架,这个框架独立于那些已经发布出来的完整框架的依赖项。(译者注:可以这么理解,

框架的实际实现取决于你在 project.json 中引用的东西,可能你并不会引用所有的包,所以你所依赖的包是官方框架的全部包的一个子集。)

在.Net Core基础之上,基于包的框架主要有两个:

  • netstandard
  • netcoreapp

.NET Standard

.NET 标准框架(netstandard)意指基于 .Net 标准类库所定义与构建的API。如果你所构建的类库将会用于多种运行平台,应该以基于netstandard进行构建,这样类库就会支持任何一种 兼容 .Net 标准的运行时,比如 .Net Core, .Net Framework以及 Mono/Xamarin。这些运行时中的每一处都支持一种或几种 .Net 标准,至于到底支持哪个版本,则取决于具体实现。

元包 NETStandard.Library 的目标框架是 netstandard。要以 netstandard 为目标框架,最常见的方法是引用此元包。它定义与提供了约40个.Net类库,并与.Net 标准类库所定义的API相关联。你可以引用基于 netstandard 开发的第三方包来使用第三方API。

一个给定的 NETStandard.Library 版本,总是与 netstandard 所公开的最高版本相匹配。 project.json 文件中对于框架的引用,主要是用来从此框架中选择正确的资产。因此,假如定义了 netstandard1.5,就需要 其中的dll资产,而不是 netstandard1.4,或者 net46。

{
"dependencies": {
"NETStandard.Library": "1.5.0"
},
"frameworks": {
"netstandard1.5": {}
}
}

  

这个 project.json 文件中所引用的 框架与元包 并不需要严格匹配,例如下面的 project.json 也是正确的:

{
"dependencies": {
"NETStandard.Library": "1.5.0"
},
"frameworks": {
"netstandard1.3": {}
}
}

  

把构建目标设置为 netstandard1.3 却使用 NETStandard.Library 的 1.5 版本,似乎有点奇怪。然而这是一个合法的用例,因为元包支持更老的 netstandard 版本。可能恰好 你使用了 1.5.0 的元包版本来开发你所有的类库,然后运行于多种版本的 netstandard,在这种情况下,你只需要重新加载 NETStandard.Library 1.5.0 即可,并不需要加载早期版本。

反之则并不成立:把 netstandard1.5 作为运行目标,却使用 NETStandard.Library 的 1.3.0 版本来开发你的类库:你不能够把更高版本的框架作为开发目标,却使用更低版本的元包。元包资产的版本管理机制,与框架的最高版本的定义相匹配。借助于版本管理机制,NETStandard.Library 的第一个版本是 v1.5.0,它包含了 netstandard1.5 的资产。而上面例子中的 v1.3.0 版本,只是为了举例方便,实际上并不存在。

译者注:这一段的各种名词相互绕来绕去,会把人绕晕。举个例子就明白了:因为类库总是向下兼容的,1.5 的实现必然包含了1.3的所有定义,1.5 版本的元包,是可以运行于 1.3 版本的框架之上。

然而这与我们的直觉经验不符,因此作者说看起来很奇怪,因为你在 Win7 上开发的程序(依赖高版本元包),很可能不支持运行在 XP 系统上(低版本框架)。

但是为什么在神奇的 .Net Core 的世界中,这个现象就发生了呢?

这是由 .Net Core 的版本管理机制所决定的。文中并没有给出来具体的解释。关于版本管理,有另外一篇文章会介绍,稍后翻译。

.NET Core Application

.NET Core Application 框架(netcoreapp) 意为: 包与相关的API是 基于.Net Core 特定发布版本以及它所提供的控制台程序模型。.Net Core应用程序必须使用这个框架,因为必须要使用其中的控制台程序模型。同时只运行于 .Net Core 平台的类库也应使用这个模型。使用这框架以后,应用程序(exe)与类库(dll)将只能够运行于.Net Core平台上。(老外好啰嗦啊) 元包 Microsoft.NETCore.App 的目标框架是 netcoreapp 。此元包提供了约 60 个类库,其中大约 40 个是由 NETStandard.Library 提供的,另外20个是由 Microsoft.NETCore.App 自己实现的(addition)。如果你开发的类库的目标框架是 netcoreapp 或其兼容框架(如netstandard),则可以使用 Microsoft.NETCore.App 的这些20个额外类库(addition),来调用这些额外的API。

译注:addition,是指由 Microsoft.NETCore.App 在 NETStandard.Library 基础之上的额外实现,约20个类库。在从传统 Framework迁移过来的代码中,如果你使用了 NETStandard.Library ,可能会出现不识别类或者方法的情况,很有可能是因为这些不识别的部分实现在这20个addition中,改为引用 Microsoft.NETCore.App 可能会解决问题。

由 Microsoft.NETCore.App 额外实现的大部分类库,也可以运行于 其他的 netstandard 框架,如果这些框架满足了它们所依赖的类库的运行环境的话。这意味着 运行于 netstandard 框架的类库也引用这些额外包作为依赖项。

译注:这段话也比较晦涩,再举例子说明。例如 Microsoft.NETCore.App 1.5 (简称App1.5)是 在 NETStandard.Library 1.5 (简称Lib1.5)之上实现了额外20个包(Add20),即 App1.5 = Lib1.5 + Add20。 前面说 Lib1.5 可以运行于框架 netstandard 1.5(简称 Std1.5),以及 Std1.3 之上,如果这个 Add20 也可以运行于 Lib1.3 的话,那么就可以得到 App1.5 也可以运行于 Lib1.3。

.Net Core 中的包、元包与框架(Packages, Metapackages and Frameworks)的更多相关文章

  1. .net core中的那些常用的日志框架(NLog篇)

    前言 咱们上回讲到,.net core中内置的Logging日志框架的使用,以及浅显的讲解,接下来,给大家介绍一个第三方日志框架(NLog). NLog简介 NLog是适用于各种.NET平台(包括.N ...

  2. .net core中的那些常用的日志框架(Serilog篇)

    前言 上文说到Nlog日志框架,感觉它功能已经很强大,今天给大家介绍一个很不错的日志框架Serilog,根据我的了解,感觉它最大的优势是,结构化日志,它输出的日志是Json的格式,如果你使用的是Mon ...

  3. .net core中的那些常用的日志框架(Logging篇)

    前言 日志,在我们每个项目中是必不可少的,它不仅能在调试的时候测试数据,而且在项目上线,也是我们排查错误的得力助手,那我就能谈谈,用的多的几个日志框架吧!如果有不对的地方,欢迎来指教错误,谢谢! As ...

  4. 在.NET Core中使用Exceptionless分布式日志收集框架

    一.Exceptionless简介 Exceptionless 是一个开源的实时的日志收集框架,它可以应用在基于 ASP.NET,ASP.NET Core,Web Api,Web Forms,WPF, ...

  5. .NET Core中的包、元包与框架

    本文为翻译文章,原文:Packages, Metapackages and Frameworks .NET Core是一个由NuGet包组成的平台.一些产品受益于细粒度包的定义,也有一些受益于粗粒度包 ...

  6. 大话DI依赖注入+IOC控制反转(二) 之 浅析.Net Core中的DI与IOC

      转发时请注明原创作者及地址,否则追究责任.原创:alunchen 在上一篇文章中,我们聊了很多关于定义的方面,比较孤燥,下面我们结合.Net Core聊一下依赖注入&控制反转. 三种对象生 ...

  7. .Net Core 学习笔记1——包、元包、框架

    .Net Core 是由NuGet包(package)组成的平台. 一起使用的多个包的集合:元包(Metapackage) package 包 (对应以前的程序集概念) Framework 框架 as ...

  8. 解决 .net core 中 nuget 包版本冲突问题

    今天在一个 asp.net core 项目中遇到了 nuget 包版本冲突的问题,错误信息如下: Version conflict detected for Microsoft.AspNet.WebA ...

  9. .NET Core中创建和使用NuGet包

    在.NET Core的项目中,如果我们要在项目中引用其它DLL文件,不应该直接在项目引用中添加DLL文件(虽然在.NET Core项目中也可以这么做),建议是去直接下载DLL文件所属的NuGet包.这 ...

随机推荐

  1. codeforces Gym 100500H H. ICPC Quest 水题

    Problem H. ICPC QuestTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/a ...

  2. [Javascript] Monads

    Monads allow you to nest computations. They are a pointed functor that adds mjoin and chain function ...

  3. MyISAM表锁

    MyISAM存储引擎只支持表锁,这也是MySQL开始几个版本中唯一支持的锁类型.随着应用对事务完整性和并发性 要求的不断提高,MySQL才开始开发基于事务的存储引擎,后来慢慢出现了支持页锁的BDB存储 ...

  4. MDIO/MDC(SMI)接口

    转载:http://blog.chinaunix.net/uid-24148050-id-132863.html 1. 简介 The MDIO interface is a simple, two-w ...

  5. 关于设置android:imeOptions属性无效的解决办法

    在对Android的EditText控件进行设置时,经常会限定一下输入法的属性,设置右下角为完成或者搜索等,一般都会想到android:imeOptions属性,但是仅仅这么设置通常是无效的,还要搭配 ...

  6. Asp.Net 之 网页快照

    此文做法不是 Control.DrawToBitmap ,而是直接QueryInterface 浏览器Com对象的 IViewObject 接口,用它实现的Draw方法,画到图像上. 首先,定义IVi ...

  7. 获取Spring-boot系统环境变量方法

    public static ConfigurableApplicationContext context = null; public static void main( String[] args ...

  8. Hill Climber and Random Walk

  9. shareplex三点同步配置

    一.准备工作 主从类型 系统版本 数据库版本 主机地址 主机名 源数据库 Centos6.4 X86_64 11.2.0.4.0 192.168.3.230 dbshareplex 目的数据库 Cen ...

  10. LeetCode 122

    Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price of a ...