.NET Core – 快速指南

.NET Core – 快速指南


.NET Core – 概述

.NET Core 是 Microsoft 维护的最新通用开发平台。它适用于不同的平台,并以一种使 .NET 快速、灵活和现代的方式进行了重新设计。这恰好是微软的主要贡献之一。开发人员现在可以使用 .NET 构建 Android、iOS、Linux、Mac 和 Windows 应用程序,所有这些都在开源中。

在本教程中,我们将介绍 .NET Core 和一些新的创新,包括 .NET Framework 更新、.NET Standard 和通用 Windows 平台更新等。

.NET Core 的特点

以下是 .NET Core 的主要特征 –

开源

  • .NET Core 是一个开源实现,使用 MIT 和 Apache 2 许可证。

  • .NET Core 是一个 .NET Foundation 项目,可在 GitHub 上获得。

  • 作为一个开源项目,它促进了更透明的开发过程,并促进了活跃和参与的社区。

跨平台

  • 无论您的平台目标如何,在 .NET Core 中实现的应用程序都可以运行,并且可以重用其代码。

  • 它目前支持三种主要操作系统 (OS)

    • 视窗

    • Linux

    • 苹果系统

  • 受支持的操作系统 (OS)、CPU 和应用程序场景将随着时间的推移而增长,由 Microsoft、其他公司和个人提供。

灵活部署

  • .NET Core 应用程序可以有两种类型的部署 –

    • 依赖框架的部署

    • 独立部署

  • 通过依赖于框架的部署,您的应用程序依赖于安装了您的应用程序和第三方依赖项的系统范围版本的 .NET Core。

  • 通过独立部署,用于构建应用程序的 .NET Core 版本也与应用程序和第三方依赖项一起部署,并且可以与其他版本并行运行。

命令行工具

  • 所有产品场景都可以在命令行中执行。

兼容的

  • .NET Core 通过 .NET 标准库与 .NET Framework、Xamarin 和 Mono 兼容

模块化的

  • .NET Core 通过 NuGet 在较小的程序集包中发布。

  • .NET Framework 是一个包含大部分核心功能的大型程序集。

  • .NET Core 作为较小的以功能为中心的包提供。

  • 这种模块化方法使开发人员能够通过在他们的应用程序中仅包含他们需要的那些 NuGet 包来优化他们的应用程序。

  • 较小的应用程序表面积的好处包括更严格的安全性、减少的服务、提高的性能以及在按使用量付费的模型中降低成本。

.NET 核心平台

.NET Core 平台包含以下主要部分 –

  • .NET Runtime – 它提供了类型系统、程序集加载、垃圾收集器、本地互操作和其他基本服务。

  • Fundamental Libraries – 一组框架库,提供原始数据类型、应用程序组合类型和基本实用程序。

  • SDK & Compiler – 一组 SDK 工具和语言编译器,可在 .NET Core SDK 中提供基本的开发人员体验。

  • ‘dotnet’ 应用程序主机– 用于启动 .NET Core 应用程序。它选择运行时并托管运行时,提供程序集加载策略并启动应用程序。同样的主机也用于以几乎相同的方式启动 SDK 工具。

.NET Core – 先决条件

在本章中,我们将讨论部署和运行所需的各种依赖项。其中包括使用 Visual Studio 开发的 Windows 计算机上的 .NET Core 应用程序。

支持的 Windows 版本

以下版本的 Windows 支持 .NET Core –

  • 视窗 7 SP1
  • 视窗 8.1
  • 视窗 10
  • Windows Server 2008 R2 SP1(完整服务器或服务器核心)
  • Windows Server 2012 SP1(完整服务器或服务器核心)
  • Windows Server 2012 R2 SP1(完整服务器或服务器核心)
  • Windows Server 2016(完整服务器、Server Core 或 Nano Server)

依赖关系

  • 如果您在早于 Windows 10 和 Windows Server 2016 的 Windows 版本上运行 .NET Core 应用程序,则它还需要 Visual C++ Redistributable。

  • 如果您使用 .NET Core 安装程序,则会自动为您安装此依赖项。

  • 如果您通过安装程序脚本安装 .NET Core 或部署独立的 .NET Core 应用程序,则需要手动安装 Visual C++ Redistributable for Visual Studio 2015。

  • 对于 Windows 7 和 Windows Server 2008 计算机,您需要确保您的 Windows 安装是最新的,并且还包括通过 Windows 更新安装的修补程序 KB2533623。

Visual Studio 的先决条件

  • 要使用 .NET Core SDK 开发 .NET Core 应用程序,您可以使用您选择的任何编辑器。

  • 但是,如果您想使用 Visual Studio 在 Windows 上开发 .NET Core 应用程序,您可以使用以下两个版本 –

    • 视觉工作室 2015

    • Visual Studio 2017 RC

  • 默认情况下,使用 Visual Studio 2015 创建的项目将基于 project.json,而使用 Visual Studio 2017 RC 创建的项目将始终基于 MSBuild。

.NET Core – 环境设置

在本章中,我们将讨论 .NET Core 的环境设置。它是对 .NET Framework 的重大重新设计。要在您的应用程序中使用 .NET Core,您可以使用两个版本 –

  • 视觉工作室 2015
  • Visual Studio 2017 RC

视觉工作室 2015

要使用 Visual Studio 2015,您必须安装以下内容 –

  • Microsoft Visual Studio 2015 更新 3
  • Microsoft .NET Core 1.0.1 – VS 2015 工具预览版 2

Microsoft 提供了一个免费版本的 Visual Studio,其中也包含 SQL Server,可以从https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx和 Microsoft .NET Core 1.0 下载.1 – VS 2015 Tooling Preview 2 可从https://www.visualstudio.com/downloads/下载

您还可以按照以下 URL https://www.microsoft.com/net/core/#windowsvs2017上的安装指南进行操作

安装 Visual Studio 2015

按照以下步骤安装 Visual Studio 2015 –

步骤 1 – 下载完成后,运行安装程序。将显示以下对话框。

下载

步骤 2 – 单击安装开始安装过程。

安装

步骤 3 – 安装完成后,您将看到以下对话框。

完全的

步骤 4 – 关闭此对话框并根据需要重新启动计算机。

第 5 步– 从开始菜单打开 Visual Studio;您将收到以下对话框。可能需要几分钟的时间来加载并最终第一次使用。

打开

步骤 6 – 加载后,您将看到以下屏幕。

加载中

步骤 7 – Visual Studio 安装完成后,关闭 Visual Studio 并启动 Microsoft .NET Core – VS 2015 Tooling Preview 2。

发射

步骤 8 – 选中复选框并单击安装。

复选框

步骤 9 – 安装完成后,您将看到以下对话框。

应用就绪

您现在已准备好使用 .NET Core 启动您的应用程序。

视觉工作室 2017

在本教程中,我们将使用 Visual Studio 2015,但如果您想使用 Visual Studio 2017,Visual Studio 2017 RC 中包含用于 Visual Studio 的 .NET Core 工具的实验版本,您可以在此处查看安装指南https: //www.microsoft.com/net/core/#windowsvs2017

.NET Core – 入门

Visual Studio 2015 为开发 .NET Core 应用程序提供了一个功能齐全的开发环境。在本章中,我们将在 Visual Studio 中创建一个新项目。安装 Visual Studio 2015 工具后,即可开始构建新的 .NET Core 应用程序。

核心应用

New Project对话框中,在 Templates 列表中,展开 Visual C# 节点并选择 .NET Core,您应该会看到以下三个新项目模板

  • 类库 (.NET Core)
  • 控制台应用程序 (.NET Core)
  • ASP.NET Core Web 应用程序 (.NET Core)

在“新建项目”对话框的中间窗格中,选择“控制台应用程序 (.NET Core)”并将其命名为“FirstApp”,然后单击“确定”。

第一个应用

Visual Studio 将打开新创建的项目,您将在解决方案资源管理器窗口中看到该项目中的所有文件。

要测试 .NET 核心控制台应用程序是否正常工作,让我们添加以下行。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
  
namespace FirstApp { 
   public class Program { 
      public static void Main(string[] args) { 
         Console.WriteLine("Hello guys, welcome to .NET Core world!"); 
      } 
   } 
}

现在,运行应用程序。您应该会看到以下输出。

输出

.NET Core – 数字

.NET Core 支持标准的数字整数和浮点基元。它还支持以下类型 –

  • System.Numerics.BigInteger 是一个没有上限或下限的整数类型。

  • System.Numerics.Complex 是一种表示复数的类型。

  • System.Numerics 命名空间中的一组启用单指令多数据 (SIMD) 的向量类型。

积分类型

.NET Core 支持长度从 1 个字节到 8 个字节的不同范围的有符号和无符号整数。所有整数都是值类型。

下表代表了积分类型及其大小;

Type 签名/未签名 大小(字节) 最小值 最大值
Byte 未签名 1 0 255
Int16 2 −32,768 32,767
Int32 4 −2,147,483,648 2,147,483,647
Int64 8 −9,223,372,036,854,775,808 9,223,372,036,854,775,807
SByte 1 -128 127
UInt16 未签名 2 0 65,535
UInt32 未签名 4 0 4,294,967,295
UInt64 未签名 8 0 18,446,744,073,709,551,615

每个整数类型都支持一组标准的算术、比较、相等、显式转换和隐式转换运算符。

您还可以使用 System.BitConverter 类处理整数值中的各个位。

浮点类型

.NET Core 包括三种原始浮点类型,如下表所示。

Type 大小(字节) 最小值 最大值
Double 8 −1.79769313486232e308 1.79769313486232e308
Single 4 −3.402823e38 3.402823e38
Decimal 16 −79,228,162,514,264,337,593,5 43,950,335 79,228,162,514,264,337,593,543,9 50,335
  • 每个浮点类型都支持一组标准的算术、比较、相等、显式转换和隐式转换运算符。

  • 您还可以使用 BitConverter 类处理 Double 和 Single 值中的各个位。

  • Decimal 结构有自己的方法,Decimal.GetBits 和 Decimal.Decimal(Int32()),用于处理十进制值的各个位,以及它自己的一组方法来执行一些额外的数学运算。

大整数

  • System.Numerics.BigInteger 是一种不可变类型,表示任意大的整数,其值在理论上没有上限或下限。

  • BigInteger 类型的方法与其他整数类型的方法非常相似。

复杂的

  • System.Numerics.Complex 类型表示一个复数,即具有实数部分和虚数部分的数字

  • 它支持一组标准的算术、比较、相等、显式转换和隐式转换运算符,以及数学、代数和三角方法。

SIMD

  • Numerics 命名空间包括一组用于 .NET Core 的启用 SIMD 的向量类型。

  • SIMD 允许在硬件级别并行化某些操作,从而在对向量执行计算的数学、科学和图形应用程序中产生巨大的性能改进。

  • .NET Core 中支持 SIMD 的向量类型包括以下内容 –

    • System.Numerics.Vector2、System.Numerics.Vector3 和 System.Numerics.Vector4 类型,它们是 Single 类型的 2、3 和 4 维向量。

    • Vector <T> 结构允许您创建任何原始数字类型的向量。原始数字类型包括 System 命名空间中除 Decimal 之外的所有数字类型。

    • 两种矩阵类型,System.Numerics.Matrix3×2,表示一个3×2的矩阵;和 System.Numerics.Matrix4×4,表示 4×4 矩阵。

    • System.Numerics.Plane 类型表示三维平面,System.Numerics.Quaternion 类型表示用于对三维物理旋转进行编码的向量。

.NET Core – 垃圾收集

在本章中,我们将介绍垃圾收集的概念,它是 .NET 托管代码平台最重要的特性之一。垃圾收集器 (GC) 管理内存的分配和释放。垃圾收集器充当自动内存管理器。

  • 您不需要知道如何分配和释放内存或管理使用该内存的对象的生命周期

  • 每当您使用“new”关键字声明对象或值类型被装箱时,就会进行分配。分配通常非常快

  • 当没有足够的内存来分配对象时,GC 必须收集和处理垃圾内存,以使内存可用于新的分配。

  • 此过程称为垃圾收集

垃圾回收的优势

垃圾收集提供以下好处 –

  • 您无需在开发应用程序时手动释放内存。

  • 它还有效地在托管堆上分配对象。

  • 当不再使用对象时,它将通过清除它们的内存来回收这些对象,并保持内存可用于将来的分配。

  • 托管对象会自动获得干净的内容,因此它们的构造函数不必初始化每个数据字段。

  • 它还通过确保一个对象不能使用另一个对象的内容来提供内存安全。

垃圾收集条件

当以下条件之一为真时,会发生垃圾收集。

  • 系统物理内存不足。

  • 托管堆上已分配对象使用的内存超过了可接受的阈值。该阈值会随着过程运行而不断调整。

  • GC.Collect的方法被调用,并在几乎所有情况下,你不必调用此方法,因为垃圾收集器连续运行。此方法主要用于特殊情况和测试。

几代人

.NET 垃圾收集器有 3 代,每一代都有自己的堆,用于存储分配的对象。有一个基本原则,即大多数对象要么是短期的,要么是长期存在的。

第一代 (0)

  • 在第 0 代中,首先分配对象。

  • 在这一代中,对象通常不会超过第一代,因为在下一次垃圾回收发生时它们不再被使用(超出范围)。

  • 第 0 代收集起来很快,因为它关联的堆很小。

第二代 (1)

  • 在第 1 代中,对象有第二次机会空间。

  • 生命周期很短但在第 0 代集合(通常基于巧合的时间)中幸存下来的对象进入第 1 代。

  • 第 1 代收集也很快,因为其关联的堆也很小。

  • 前两个堆仍然很小,因为对象要么被收集,要么被提升到下一代堆。

第三代 (2)

  • 在第 2 代中,所有长对象都存在并且其堆可以增长到非常大。

  • 这一代的对象可以存活很长时间,没有下一代堆来进一步提升对象。

  • 垃圾收集器有一个额外的大对象堆,称为大对象堆 (LOH)。

  • 它是为 85,000 字节或更大的对象保留的。

  • 大对象不分配给分代堆,而是直接分配给 LOH

  • 对于已运行很长时间或处理大量数据的程序,第 2 代和 LOH 集合可能需要花费大量时间。

  • 众所周知,大型服务器程序有 10 多 GB 的堆。

  • GC 使用多种技术来减少它阻止程序执行的时间。

  • 主要方法是以不干扰程序执行的方式在后台线程上执行尽可能多的垃圾收集工作。

  • GC 还为开发人员提供了一些影响其行为的方法,这对于提高性能非常有用。

.NET Core – 代码执行

在本章中,我们将了解 .NET Core 的执行过程,并将其与 .NET Framework 进行比较。托管执行过程包括以下步骤。

  • 选择编译器
  • 将代码编译为 MSIL
  • 将 MSIL 编译为本机代码
  • 运行代码

代码执行

选择编译器

  • 它是一个多语言执行环境,运行时支持多种数据类型和语言特性。

  • 要获得公共语言运行时提供的好处,您必须使用一种或多种面向运行时的语言编译器。

将代码编译为 MSIL

  • 编译会将您的源代码转换为 Microsoft 中间语言 (MSIL) 并生成所需的元数据。

  • 元数据描述代码中的类型,包括每种类型的定义、每种类型成员的签名、代码引用的成员以及运行时在执行时使用的其他数据。

  • 运行时在执行期间根据需要从文件和框架类库 (FCL) 中定位和提取元数据。

将 MSIL 编译为本机代码

  • 在执行时,即时 (JIT) 编译器将 MSIL 转换为本机代码。

  • 在此编译期间,代码必须通过检查 MSIL 和元数据的验证过程,以确定代码是否可以确定为类型安全的。

运行代码

  • 公共语言运行时提供了使执行能够发生的基础结构以及可以在执行期间使用的服务。

  • 在执行期间,托管代码接收诸如垃圾收集、安全性、与非托管代码的互操作性、跨语言调试支持以及增强的部署和版本控制支持等服务。

.NET Core 代码执行过程

现在让我们将代码与 .NET Framework 相比如何使用 .NET Core 执行。在 .NET Core 中,这些组件有很多替代品,它们是 .NET Framework 的一部分。

.NET Core 代码执行

  • 在 .NET Core 中,现在我们有一系列新的编译器,就像我们有用于 C# 和 VB 的 Roslyn。

  • 如果要将 F# 与 .NET Core 结合使用,还可以使用新的 F# 4.1 编译器。

  • 实际上这些工具是不同的,如果我们使用 C# 6 或更高版本,我们也可以将 Roslyn 与 .NET Framework 一起使用,因为 C# 编译器最多只能支持 C# 5。

  • 在 .NET Core 中,我们没有框架类库 (FCL),因此使用了一组不同的库,我们现在拥有 CoreFx。

  • CoreFx 是 .NET Core 类库的重新实现。

  • 我们还有一个新的 .NET Core 运行时,称为 CoreCLR,并利用了 JIT 编译器。

  • 现在的问题是,为什么我们要重新实现 .NET 框架中已有的所有这些组件。

  • 所以答案与微软实施 .NET Core 的原因相同。

.NET Core – 模块化

.NET Core 的另一个考虑因素是构建和实现模块化的应用程序。无需安装整个 .NET Framework,您的应用程序现在只需安装所需的即可。让我们去视觉工作室看看模块化。

这是我们在解决方案资源管理器中的简单 .NET Core 应用程序。让我们展开 References,您将看到对 .NETCoreApp 的引用

.Net 核心应用

在 .NETCoreApp 中,您将看到对 NuGet 的包引用;让我们扩大它。

NuGet

您将看到整个系列的 NuGet 包参考。如果您曾在 .NET Framework 中工作过,那么这些命名空间中的许多会看起来很熟悉,因为您已经习惯了在 .NET Framework 中使用它。

.NET Framework 被分成许多不同的部分,并使用 CoreFx 重新实现;这些作品作为单独的包进一步分发。

框架

  • 现在,如果您展开 NETStandard.Library,您将看到其他引用。您甚至会注意到我们在此应用程序中使用的 System.Console。

  • 现在,您不必将所有内容都引入 .NET Framework 中,而只需引入应用程序所需的内容。

  • 还有其他一些好处;例如,如果需要,这些模块可以单独更新。

模块化带来性能优势,您的应用程序可以运行得更快,尤其是 ASP.NET Core 应用程序。

.NET Core – 项目文件

在本章中,我们将讨论 .NET Core 项目文件以及如何在项目中添加现有文件。

让我们理解一个简单的例子,其中我们已经创建了一些文件;我们必须在我们的 FirstApp 项目中添加这些文件。

下面是Student.cs文件的实现

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
  
namespace FirstApp { 
   public class Student { 
      public int ID { get; set; } 
      public string LastName { get; set; } 
      public string FirstMidName { get; set; } 
      public DateTime EnrollmentDate { get; set; } 
   } 
}

这是Course.cs文件的实现

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
  
namespace FirstApp { 
   public class Course { 
      public int CourseID { get; set; } 
      public string Title { get; set; } 
      public int Credits { get; set; } 
   } 
}

现在让我们将这三个文件保存在您的磁盘和项目的源文件夹中。

源文件夹

  • 现在,如果您熟悉 .NET 并且这是一个传统的 .NET 框架控制台应用程序,那么了解如何在 Visual Studio 的项目中添加这些文件很重要。

  • 您首先需要将文件拖到解决方案资源管理器中以将它们复制到您的项目文件夹中,因为您的项目需要引用这些文件。

  • .NET Core 的好处之一是项目文件 (project.json) 所采用的方法;我们可以将文件拖放到项目的根目录中,然后这些文件将自动包含在我们的项目中。

  • 我们不必像过去那样为 Visual Studio 中的传统 .NET Framework 应用程序手动引用文件。

现在让我们打开您项目的根目录。

根

现在让我们将所有三个文件复制到项目的根目录中。

项目

您现在可以看到复制到根文件夹的所有文件。

现在让我们进入 Visual Studio;您将收到以下对话框。

视觉的

单击“全部是”以重新加载您的项目。

全部同意

您现在将文件自动包含在您的项目中。

.NET Core – 包参考

在本章中,我们将讨论如何在 .NET Core 应用程序中添加包以及如何查找特定包。我们可以直接去NuGet添加包,但是这里我们会看到一些其他的地方。

现在让我们转到位于此处的 .NET Core 源代码 – https://github.com/dotnet/corefx

源代码

在 CoreFx 存储库中,打开src文件夹 –

核心外汇

您将看到对应于不同包的整个文件夹列表。现在让我们搜索 Json –

杰森

还有另一种方法可以找到你的包,如果你熟悉 .NET Framework,你可能知道各种类型,但是 .NET Core 中的包的组装完全不同,你不会知道这些包在哪里。

如果您知道类型,则可以使用https://packagesearch.azurewebsites.net/搜索反向包搜索

反向包装

您可以在此处输入您想要查找的任何类型的包裹。然后,这个站点会扫描 NuGet 并为你找到相关的包。

现在让我们搜索DataContractJson

数据合约Json

您现在将看到我们获得了相同的包裹;让我们点击包裹。

包裹

您现在将看到 NuGet 页面;你需要确认你需要这个包。您可以使用几种方法将其添加到您的应用程序中。

让我们打开 project.json 文件。

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
   "dependencies": { 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1" 
      } 
   }, 
   "frameworks": { 
      "netcoreapp1.0": { 
         "imports": "dnxcore50" 
      } 
   } 
} 

这是新的项目格式,在此文件中,您将看到依赖项部分。让我们添加一个新的依赖项,如下所示。

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
   "dependencies": { 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1" 
      }, 
      "System.Runtime.Serialization.Json": "4.0.2" 
   }, 
   "frameworks": { 
      "netcoreapp1.0": { 
         "imports": "dnxcore50" 
      } 
   } 
}

现在,如果您查看您的参考资料,您将看到System.Runtime.Serialization.Json包已添加到您的项目中。

跑步

另一种方法是转到 NuGet 管理器并浏览要添加的包。

浏览套餐

.NET Core – 创建 UWP 应用

在本章中,我们将讨论如何使用 .NET Core 创建 UWP 应用程序。UWP 也称为 Windows 10 UWP 应用程序。此应用程序不能在以前版本的 Windows 上运行,但只能在未来版本的 Windows 上运行。

以下是 UWP 可以顺利运行的一些例外情况。

  • 如果你想在本地运行它,你必须有 Windows 10,你也可以在 Windows 8 上开发,然后你需要在模拟器上运行它,但鼓励使用 Windows 10。

  • 对于 UWP 应用程序,您还需要 Windows 10 SDK。让我们打开 Visual Studio 2015 安装程序,然后修改 Visual Studio。

  • 在选择功能页面上,向下滚动,您将看到通用 Windows 应用程序开发工具,如下所示选中该选项。

在这里你可以看到不同版本的 SDK 和最新的 Tools 更新,点击 Next。

2015年专业

现在,单击安装按钮。

安装按钮

安装完成后,您将需要重新启动系统。

设置完成

现在让我们按照以下步骤实现 UWP。

  • 首先,启动 Visual Studio 2015。

  • 点击文件菜单,选择新建→项目;将出现一个新项目对话框。您可以在对话框的左窗格中看到不同类型的模板。

文件菜单

  • 在左窗格中,您可以看到树视图,现在从模板 → Visual C# → Windows 中选择通用模板。

  • 从中心窗格中,选择空白应用程序(通用 Windows)模板。

  • 通过在名称字段中键入UWPFirstApp为项目命名,然后单击确定。

UWPFirstApp

  • 出现目标版本/最低版本对话框。默认设置适用于本教程,因此选择“确定”以创建项目。

默认设置

  • 在这里,我们有一个可以针对所有 Windows 10 设备的项目,您会注意到 .NET Core 和 UWP 都是多目标的简化。

  • 当一个新项目打开时,其文件显示在解决方案资源管理器窗格的右侧。您可能需要选择解决方案资源管理器选项卡而不是属性选项卡来查看您的文件。

  • 虽然Blank App(通用窗口)是一个最小的模板,但它仍然包含大量文件。这些文件对于所有使用 C# 的 UWP 应用都是必不可少的。您在 Visual Studio 中创建的每个项目都包含这些文件。

  • 要查看正在运行的示例,让我们打开 MainPage.XAML 并添加以下代码。

<Page 
   x:Class = "UWPFirstApp.MainPage" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:local = "using:UWPFirstApp" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   mc:Ignorable = "d">  
   
   <Grid Background = "{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
      <StackPanel HorizontalAlignment = "Center"> 
         <TextBlock Text = "Hello, world!"  
            Margin = "20" 
            Width = "200" 
            HorizontalAlignment = "Left"/> 
         <TextBlock Text = "Write your name." 
            Margin = "20" 
            Width = "200" 
            HorizontalAlignment = "Left"/> 
         <TextBox x:Name = "txtbox"  
            Width = "280" 
            Margin = "20" 
            HorizontalAlignment = "Left"/> 
         <Button x:Name = "button" Content = "Click Me" 
            Margin = "20" 
            Click = "button_Click"/> 
         <TextBlock x:Name = "txtblock"  
            HorizontalAlignment = "Left" 
            Margin = "20"/> 
      </StackPanel> 
   </Grid> 

</Page> 

下面是C#中按钮的点击事件。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices.WindowsRuntime; 

using Windows.Foundation; 
using Windows.Foundation.Collections; 

using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation;  

// The Blank Page item template is documented at 
// http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409  

namespace UWPHellowWorld { 
   /// <summary> 
   /// An empty page that can be used on its own or navigated to within a Frame. 
   /// </summary> 
   public sealed partial class MainPage : Page { 
      public MainPage() { 
         this.InitializeComponent(); 
      }  
      private void button_Click(object sender, RoutedEventArgs e) { 
         if (txtbox.Text != "") 
            txtblock.Text = "Hello: " + txtbox.Text; 
         else 
            txtblock.Text = "You have not write your name"; 
      } 
   } 
} 

现在让我们在本地机器上运行上述代码,您将看到以下窗口。现在在文本框中键入任何名称,然后按Click Me按钮。

点击我

.NET 核心 – MSBuild

在本章中,我们将讨论什么是 MSBuild 以及它如何与 .NET Core 配合使用。MSBuild 是 Microsoft 和 Visual Studio 的构建平台。在 UWP 应用程序中,如果打开项目文件夹,则会看到 project.json 和 *.csproj 文件。

项目.json

但是,如果您打开我们之前的 .NET Core 控制台应用程序,则会看到 project.json 和 *.xproj 文件。

文件

  • .NET Core 构建系统或 project.json 构建系统不足以满足 UWP 需求;这就是 UWP 仍在使用 *.csproj (MSBuild) 构建系统的原因。

  • 但就构建系统而言,project.json 将移出。

  • 现在,如果您想将一些现有文件添加到我们在控制台应用程序中添加的 UWP 应用程序中,那么您需要将这些文件添加到项目文件夹中。此外,您还需要在解决方案资源管理器中包含您的项目。

现在让我们考虑以下文件;将这些文件复制到您的项目文件夹中。

项目文件夹

项目

让我们回到 Visual Studio 并打开解决方案资源管理器。

解决方案资源管理器

  • 您现在可以看到,对于 UWP 应用程序,仅复制文件是不够的,因为在解决方案资源管理器中,我们看不到这些文件。

  • 现在我们还必须通过单击上面屏幕截图中突出显示的“显示所有文件”图标来包含这些文件,您现在将看到项目文件夹中的所有文件。

显示所有文件

这两个文件仍然没有包含在我们的项目中。要包含这些文件,请选择这些文件并右键单击任何文件,然后选择Include in Project

包含在项目中

现在这些文件也包括在内。可以预见的一件好事是在未来版本的 SKD 工具和 Visual Studio 中删除 *.csproj 文件的 project.json 方法。

.NET Core – 元包

在本章中,我们将讨论控制台应用程序和 UWP 应用程序之间的引用。如果您查看控制台应用程序解决方案资源管理器中的参考,您将看到如下所示的 .NETCoreApp。

控制台应用程序

.NETCoreApp 是一个针对 .NET Core 应用程序的新框架。现在,如果您查看 UWP 应用程序的引用,它会看起来有点不同,如下所示。

UWP 应用程序

  • 这样做的主要原因是因为在 UWP 中我们有 *.csproj,所以我们回到了旧的引用风格,我们只能针对具有这种项目类型的一个框架。

  • 但是参考文献是相似的。您现在可以看到,在 UWP 应用程序中,Miscrosoft.NETCore.UniversalWindowsPlatform NuGet 包引用类似于控制台应用程序中的 Microsoft.NETCore.App NuGet 引用。

  • Miscrosoft.NETCore.UniversalWindowsPlatform 和 Microsoft.NETCore.App 都是元包,这意味着它们由其他包组成。

  • 在控制台应用程序中,我们可以深入查看 Microsoft.NETCore.App 中的其他包,但我们无法在解决方案资源管理器中执行相同的 Miscrosoft.NETCore.UniversalWindowsPlatform。

  • 但是,我们可以使用另一个工具 NuGet Package Explorer 来查看。现在让我们在浏览器中打开这个 url – https://npe.codeplex.com/downloads/get/clickOnce/NuGetPackageExplorer.application,你会看到一个小的实用程序下载。

  • 下载完成后,双击该文件。

打开文件

  • 单击安装以在 NuGet 包资源管理器上开始安装。

NuGet 包资源管理器

  • 安装完成后,您将看到以下对话框。

完成的

  • 现在让我们单击“从在线提要打开包”选项。

在线订阅

  • 默认情况下,它将搜索 nuget.org 提要。现在让我们在搜索框中搜索 Microsoft.NETCore.UniversalWindowsPlatform,您将看到如下所示的 1 个结果。

Nuget 组织提要

  • 单击打开链接,它将打开此元包的顶级依赖项。

打开链接

  • 现在让我们并排打开 .NETCore 应用程序的 .NETCore 元包和 UWP 应用程序的元包。

元包

  • 您现在可以看到每个元包由不同的包集组成。

  • .NET Core 至少在目前是 .NET Framework 中可用类的子集,但正在增长,并将按照 .NET Framework 的基类。

  • UWP 基于 .NET Core,它是可用于 Windows 应用商店开发的 API 的超集。

由于 .NET Core,我们现在有更多的 API 可用于开发。

Windows 运行时和扩展 SDK

Windows 运行时组件是独立的对象,您可以从任何语言(包括 C#、Visual Basic、JavaScript 和 C++)实例化和使用它们。除了我们在上一章中看到的 .NET Core 元包之外,UWP 应用程序还默认引用了通用 Windows SDK。

通用 Windows SDK

通用 Windows 是对 Windows 运行时的引用,它已被纳入一系列 API 合同。

设备系列中的 API 集被细分为称为 API 合同的细分。您可以在此处找到不同 API 合同的列表https://msdn.microsoft.com/en-us/library/windows/apps/dn706135.aspx

应用程序接口

Windows 运行时中的大多数 API 都被分解为一个单一的契约。现在让我们在 API Contracts 页面上搜索 Universal 关键字。

API 合同页面

您可以看到各种 API 的链接,您还可以看到 Universal 系列非常庞大,它有 12 页的文档。

您还可以在此页面上搜索电话 API 合同。

电话接口

现在让我们点击Windows.Phone.PhoneContract并向下滚动;您现在将看到手机或移动设备的电池信息。

电池信息

如果您想在已有信息的基础上添加此信息,则应手动添加引用。现在让我们转到 Visual Studio 并右键单击解决方案资源管理器中的引用。

选择添加引用…

添加引用

您现在可以看到通用 Windows 的新参考类别;在此类别下有 Core 指的是核心通用 Windows API 合同

API 合约

  • 扩展允许我们扩展功能,您将看到不同的参考移动、桌面和其他扩展。

  • 有不同的 SKD 扩展,您可以在顶部添加以获得更多 API。

  • 您还可以看到不同的版本。因此,请确保您获得最新版本以获取更新的 API,然后单击“确定”。

更新的 API

您现在可以看到UWP 的 Windows Mobile 扩展已添加为参考。

.NET Core – 创建 .NET 标准库

类库定义了可以从任何应用程序调用的类型和方法。

  • 使用 .NET Core 开发的类库支持 .NET 标准库,它允许任何支持该 .NET 标准库版本的 .NET 平台调用您的库。

  • 完成类库后,您可以决定是将其作为第三方组件分发,还是将其作为与一个或多个应用程序捆绑在一起的组件包含在内。

让我们从在控制台应用程序中添加一个类库项目开始;右键单击解决方案资源管理器中src文件夹,然后选择添加 → 新建项目…

新项目

在“添加新项目”对话框中,选择 .NET Core 节点,然后选择类库 (.NET Core) 项目模板。

在名称文本框中输入“UtilityLibrary”作为项目名称,如下图所示。

实用程序库

单击“确定”以创建类库项目。创建项目后,让我们添加一个新类。右键单击解决方案资源管理器中的项目,然后选择添加 → 类…

班级

在中间窗格中选择类并在名称和字段中输入 StringLib.cs,然后单击添加添加类后,请替换 StringLib.cs 文件中的以下代码。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
  
namespace UtilityLibrary { 
   public static class StringLib { 
      public static bool StartsWithUpper(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
         return false; 
         Char ch = str[0]; 
         return Char.IsUpper(ch); 
      } 
      public static bool StartsWithLower(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
         return false; 
         Char ch = str[0]; 
         return Char.IsLower(ch); 
      } 
      public static bool StartsWithNumber(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
         return false;  
         Char ch = str[0]; 
         return Char.IsNumber(ch); 
      } 
   } 
} 
  • 类库UtilityLibrary.StringLib包含一些方法,如StartsWithUpperStartsWithLowerStartsWithNumber,它们返回一个布尔值,指示当前字符串实例是否分别以大写、小写和数字开头。

  • 在.NET核心,所述Char.IsUpper方法返回true字符是否为大写,所述Char.IsLower方法返回true如果一个字符为小写,并且类似地,Char.IsNumber方法返回true,如果字符是数字。

  • 在菜单栏上,选择构建、构建解决方案。该项目应该编译没有错误。

  • 我们的 .NET Core 控制台项目无权访问我们的类库。

  • 现在要使用这个类库,我们需要在我们的控制台项目中添加这个类库的引用。

为此,展开 FirstApp 并右键单击 References 并选择Add Reference…

第一应用

在 Reference Manager 对话框中,选择 UtilityLibrary,我们的类库项目,然后单击OK

现在让我们打开控制台项目的 Program.cs 文件并将所有代码替换为以下代码。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using UtilityLibrary; 

namespace FirstApp { 
   public class Program { 
      public static void Main(string[] args) { 
         int rows = Console.WindowHeight; 
         Console.Clear(); 
         do { 
            if (Console.CursorTop >= rows || Console.CursorTop == 0) { 
               Console.Clear(); 
               Console.WriteLine("\nPress <Enter> only to exit; otherwise, enter a string and press <Enter>:\n"); 
            } 
            string input = Console.ReadLine(); 
            
            if (String.IsNullOrEmpty(input)) break; 
            Console.WriteLine("Input: {0} {1,30}: {2}\n", input, "Begins with uppercase? ", 
            input.StartsWithUpper() ? "Yes" : "No"); 
         } while (true); 
      } 
   } 
} 

现在让我们运行您的应用程序,您将看到以下输出。

应用

为了更好地理解,让我们在您的项目中使用您的类库的其他扩展方法。

.NET Core – 可移植类库

在本章中,我们将讨论什么是 PCL(可移植类库),以及我们为什么需要 PCL。为了理解这个概念,让我们打开我们在上一章中创建的类库项目文件夹。

PCL

在此文件夹中,您可以看到除了 project.json 和 CS 文件之外,我们还有 *.xproj 文件,这是因为 Visual Studio 将 .NET Core 项目类型设置为 *.xproj 而不是 *.csproj。

正如 Microsoft 所提到的,*.xproj 将消失,但它仍然存在于预览版 2 工具中。正如我们所介绍的,UWP 应用程序使用 *.csproj。

工装

现在让 *.csproj 引用和 *.xproj 实际上是不可行的,并且该功能不会实现,因为 *.xproj 将移出。

因此,相反,我们需要一个可以在控制台应用程序和 UWP 应用程序之间共享的类库,PCL 来了。

什么是PCL

现在让我们了解什么是 PCL –

  • 可移植类库项目使您能够编写和构建在多个 .NET Framework 平台上工作的托管程序集。

  • 您可以创建包含您希望在多个项目中共享的代码(例如共享业务逻辑)的类,然后从不同类型的项目中引用这些类。

  • 它还可以帮助您快速轻松地为 Microsoft 平台构建跨平台应用程序和库。

  • 可移植的类库可以帮助您减少开发和测试代码的时间和成本。

  • 使用此项目类型编写和构建可移植的 .NET Framework 程序集,然后从面向多个平台(如 Windows 和 Windows Phone 等)的应用程序中引用这些程序集。

现在让我们从解决方案资源管理器中删除我们创建的类库。同时,将其从解决方案文件夹中删除,并进一步添加一个新的项目项。

去掉

在左侧窗格中选择Visual C# → Windows模板,然后在中间窗格中选择 Class Library (Portable)。

在名称字段中输入 StringLibrary 并单击确定以创建此项目。

字符串库

现在我们需要选择要参考的目标框架。让我们暂时选择 Windows Universal 和 ASP.NET Core,然后我们将重新定位它。单击“确定”

重新定位

可以看到它已经创建了一个 PCF 格式的新项目。现在让我们在解决方案资源管理器中右键单击 StringLibrary 项目并选择属性。

特性

单击目标 .NET 平台标准。

目标

单击是;它现在是同一个类库,只有一个细微的区别。不同之处在于它也可以被 UWP 使用,因为它包含 *.csproj 文件而不是 *.xproj。

类库

现在让我们添加一个新类;为此,您需要在解决方案资源管理器中右键单击项目并选择添加 → 类…

添加新班级

在中间窗格中选择 class 并在 name 字段中输入StringLib.cs,然后单击Add添加类后,请替换 StringLib.cs 文件中的以下代码。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
  
namespace StringLibrary { 
   public static class StringLib { 
      public static bool StartsWithUpper(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
            return false; 
         Char ch = str[0]; 
         return Char.IsUpper(ch); 
      } 
      public static bool StartsWithLower(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
            return false; 
         Char ch = str[0]; 
         return Char.IsLower(ch); 
      } 
      public static bool StartsWithNumber(this String str) { 
         if (String.IsNullOrWhiteSpace(str)) 
            return false; 
         Char ch = str[0]; 
         return Char.IsNumber(ch); 
      } 
   } 
} 

让我们构建这个可移植的类库项目,它应该编译没有错误。现在我们需要在我们的控制台项目中添加这个可移植类库的引用。因此,展开 FirstApp 并右键单击 References 并选择Add Reference…

参考

在 Reference Manager 对话框中,选择 StringLibrary,这是我们的可移植类库项目,然后单击OK

图书馆项目

您可以看到 StringLibrary 引用已添加到控制台项目中,并且也可以在 project.json 文件中看到。

您现在可以再次运行该应用程序,您将看到相同的输出。

运行应用程序

现在让我们在您的项目中使用可移植类库的其他扩展方法。您的 UWP 应用程序也将使用相同的可移植库。

.NET Core – 添加对库的引用

在本章中,我们将讨论如何向您的库添加引用。添加对库的引用就像添加对其他项目的引用一样,例如控制台项目和 UWP 项目。

UWP项目

现在可以看到 PCL 项目默认有一些引用。您还可以根据您的应用程序需要添加其他引用。

在 PCL 库中,您还可以看到 project.json 文件。

{ 
   "supports": {}, 
   "dependencies": { 
      "NETStandard.Library": "1.6.0", 
      "Microsoft.NETCore.Portable.Compatibility": "1.0.1" 
   }, 
   "frameworks": { 
      "netstandard1.3": {} 
   } 
}

向您的库添加引用的一种方法是直接在 project.json 文件中键入它。如您所见,我们在依赖项部分下添加了一些引用,如以下代码所示。

{ 
   "supports": {}, 
   "dependencies": { 
      "NETStandard.Library": "1.6.0", 
      "Microsoft.NETCore.Portable.Compatibility": "1.0.1", 
      "System.Runtime.Serialization.Json": "4.0.3", 
      "Microsoft.EntityFrameworkCore": "1.1.0" 
   }, 
   "frameworks": { 
      "netstandard1.3": {} 
   } 
} 

现在让我们保存此文件,您将看到参考文献现在已添加到您的库中。

添加了参考文献

向库添加引用的另一种方法是 NuGet 包管理器。现在让我们右键单击StringLibrary (Portable)项目并选择Mange NuGet Packages…

便携的

在浏览选项卡上,您可以搜索任何 NuGet 包;假设我们要添加“System.Runtime.Serialization.Primitives”包。

浏览标签

单击安装按钮,将显示以下屏幕。

按安装

现在,单击确定按钮。

按钮

最后,单击“我接受”按钮开始安装此 NuGet 包。安装完成后,您将看到“System.Runtime.Serialization.Primitives”NuGet 包已添加到您的库中。

安装

.NET Core – 共享库

在本章中,我们将讨论如何将您的库共享为NuGet 包,以便它可以在另一个项目中使用。创建包从要打包并与他人共享的代码开始,通过公共 nuget.org 库或组织内的私有库。包还可以包含附加文件,例如安装包时显示自述文件,并且可以包含对某些项目文件的转换。

现在让我们考虑一个简单的示例,在该示例中,我们将从我们的库中创建一个 NuGet 包。为此,请打开命令提示符并转到库项目的 project.json 文件所在的文件夹。

例子

现在让我们运行以下命令。

dotnet help 

命令

最后,您可以看到不同的命令,例如 new、restore 和 build 等。

最后一个命令是pack;这将创建一个 NuGet 包。现在让我们执行以下命令。

dotnet pack

执行

您现在可以看到在 bin 文件夹中生成了 NuGet 包;让我们打开 bin\Debug 文件夹。

调试文件夹

现在的问题是 NuGet 包里面有什么,看看我们可以使用 NuGet 包资源管理器。现在让我们打开 NuGet 包资源管理器。

打开 NuGet

选择第一个选项Open a local package

第一个选项

选择StringLibrary.1.0.0.nupkg并单击Open

单击确定

您可以看到在包内容部分我们只有 StringLibrary.dll。在包元数据部分,您将看到有关此库的一些信息,例如 ID、版本和所有依赖项。

现在让我们打开StringLibrary.1.0.0.symbols.nupkg

符号

在此 NuGet 包中,您还将看到源文件和*.pdb文件。如果双击StringLib.cs文件,也会看到源代码。

字符串库文件

这里的问题是,如何配置版本、作者和描述等元数据。

project.json 文件用于 .NET Core 项目以定义项目元数据、编译信息和依赖项。现在让我们打开 project.json 文件并添加以下附加信息。

{ 
   "authors": [ "Mark Junior" ], 
   "description": "String Library API", 
   "version" : "1.0.1-*", 
   "supports": {}, 
   
   "dependencies": { 
      "Microsoft.EntityFrameworkCore": "1.1.0", 
      "Microsoft.NETCore.Portable.Compatibility": "1.0.1", 
      "NETStandard.Library": "1.6.0", 
      "System.Runtime.Serialization.Json": "4.0.3", 
      "System.Runtime.Serialization.Primitives": "4.3.0" 
   }, 
   "frameworks": { 
      "netstandard1.3": {} 
   } 
}

您现在可以在此处查看其他信息,例如作者姓名、描述和版本。让我们保存这个文件,构建库项目,然后再次执行“dotnet pack”命令。

.Net 包

在 bin\Debug 文件夹中,可以看到 StringLibrary NuGet 包是用 1.0.1 版本生成的;让我们在 NuGet 包资源管理器中打开它。

版本

您将看到更新后的元数据。现在的问题是,我们如何在另一个包中使用它。

我们需要先在 NuGet 提要中的某处发布,然后才能在另一个项目中使用它。

有两个选项可以发布更新的元数据 –

  • 将其发布到 nuget.org
  • 将元数据推送到私有 NuGet 提要

在这里,我们将使用私有 NuGet 提要,因为它比在 nuget.org 上设置帐户要容易得多。要了解如何将您的包发布到 nuget.org,您可以遵循此处指定的所有指南https://docs.microsoft.com/en-us/nuget/create-packages/publish-a-package

按照以下步骤将更新的元数据推送到私有 NuGet 源。

步骤 1 – 首先,我们需要 nuget 命令行实用程序,我们必须安装它。现在让我们打开 NuGet 包管理器并搜索 nuget.commandline。

步骤 2 – 选择 Nuget.Commandline 并单击安装

命令行

步骤 3 – 单击确定安装 Nuget.Commandline。您也可以通过从以下 URL https://dist.nuget.org/index.html下载来手动安装它,然后设置环境变量。

手动安装

第 4 步– 安装完成后,让我们再次打开命令提示符并转到NuGet 包所在的bin\Debug文件夹并指定以下命令 –

nuget add StringLibrary.1.0.1.nupkg -Source D:\PrivateNugetPackages 

第 5 步– 在上面的命令中,我们将 StringLibrary.1.0.1.nupkg 包添加到我们的私有源,位置是D:\PrivateNugetPackages-Source指定包源。

第 6 步– 您可以看到StringLibrary已安装;所述StringLibrary可以进一步添加到专用饲料。

私人饲料

第 7 步– 让我们转到该文件夹​​。

文件夹

步骤 8 – 在stringlibrary文件夹中,您将看到另一个带有版本名称的文件夹,这里是 1.0.1。

版本名称

NuGet 包位于此处。

创建 Xamarin.Forms 项目

在本章中,我们将讨论如何使用我们创建并发布到私有 NuGet 源的 NuGet 包。因此,首先我们将创建一个 Xamarin.Forms 项目。我们首先需要了解什么是 Xamarin.Forms。

  • Xamarin.Forms 是一个框架,允许开发人员快速创建跨平台用户界面。

  • Xamarin.Forms 是一个跨平台本机支持的 ​​UI 工具包抽象,它允许开发人员轻松创建可在 Android、iOS、Windows 和 Windows Phone 之间共享的用户界面。

  • 用户界面使用目标平台的本机控件呈现,允许 Xamarin.Forms 应用程序为每个平台保留适当的外观。

要启动 Xamarin.Forms,我们需要 Visual Studio 2015 中的一些附加功能。让我们修改您的 Visual Studio 2015 并确保选择以下跨平台移动开发选项。

跨平台

安装完成后,让我们通过选择工具→选项来更新 Xamarin

工具

在左窗格中向下滚动并展开 Xamarin,然后选择Other在对话框的右上角,单击“立即检查”以查看是否有可用更新。

现在检查

您可以看到有更新可用,让我们单击“下载”按钮开始下载。下载完成后,您将收到安装更新的通知。

现在让我们再次打开 Visual Studio 并选择File → New → Project…菜单选项。

更新

在左侧窗格中,选择Visual C# → Cross-Platform模板,然后在中间窗格中,选择Blank Xaml App (Xamarin.Forms Portable)在名称字段中输入名称,然后单击确定。

空白 Xaml 应用程序

选择目标版本和最低版本,然后单击确定。

目标版本

你会看到一系列的项目;在顶部,我们有 PCL 库,它将在 Android、iOS、UWP、Windows 8.1 和 Windows Phone 8.1 等所有平台之间共享。

在这里,我们将重点介绍 PCL 库,并将在此处带来一些代码。让我们展开代码。

展开代码

在此 Xamarin.Forms 模板中,您可以看到通用 App.xaml 和 MainPage.xaml,它们使用可跨这些平台工作的 Xamarin.Forms XAML 框架。

我们需要导入我们的代码,我们还需要我们在上一章中设置的私有 NuGet 提要。

现在让我们打开 NuGet 包管理器。单击 Package source 下拉列表旁边的滚轮。

来源

我们需要在这里添加我们的私人提要,让我们点击加号 (+) 按钮

加

加号按钮

您将看到在可用包源部分中添加了另一个复选框,让我们指定名称和源路径,然后单击OK

源路径

现在让我们转到 Browse 选项卡并从 Package source 下拉列表中选择 PrivateSource,您将看到 StringLibrary NuGet 包。选择 StringLibrary 并单击安装

选择字符串库

单击“确定”,您将看到一个错误。

错误

我们不能在 .NETPortable 配置文件版本 259 中使用库,我们将在下一章中修复这个错误。

定影

.NET Core – PCL 故障排除

在本章中,我们将修复从 Xamarin.Forms 项目中的私有源安装 NuGet 包时遇到的错误。

修复错误

我们将进一步简要地了解这个问题。首先,让我们右键单击 PCL 库并选择属性。

在此页面上,您将看到整个系列的目标框架。从错误中,您可以看到 .NETPortable 配置文件 259 与我们的 StringLibrary 1.0.1 不兼容。但是,它试图从 .NET Standard 1.1 库中获取参考。

兼容的

现在让我们看看 .NET 标准库并确定哪个平台与我们的库不兼容。

平台

您可以看到 Windows Phone Silverlight 8 与 .NET Standard 1.0 兼容。如果您打开以下网页,您将看到 Profile259 仅支持 .NET Standard 1.0。

简介259

现在让我们取消选中 Windows Phone Silverlight 8。

银光

单击确定按钮。

确定按钮

现在要解决此问题,请单击“确定”并取消“更改目标”对话框,然后打开包管理器控制台并执行以下命令。

PM > Uninstall-Package Xamarin.Forms

执行命令

现在让我们转到 PCL 库的属性。单击更改按钮。

PCL库

取消选中 Windows Phone Silverlight 8 并单击确定。

取消选中

您现在可以看到 Windows Phone Silverlight 8 在 Targeted 框架中不再可用。您现在还可以看到作为目标的配置文件。为了看到这一点,让我们卸载 PCL 库并编辑 XamarinApp.csproj 文件。

卸下

您现在可以看到 TargetFrameworkProfile 现在是 Profile111。

目标框架配置文件

如果您打开文档,您将看到 Profile111 支持 .NET Standard 1.1。

文档

现在让我们再次重新加载 PCL 并打开 NuGet 包管理器并尝试从私有源安装 StringLibrary 包。

打包私人提要

从 Dependency behavior 下拉列表中,选择 Ignore Dependencies,然后单击Install

依赖关系

您可以看到 StringLibrary 包现在已从私有源安装。如果您展开 PCL 的引用,那么您将看到 StringLibrary 引用也被添加,如下所示。

PCL 参考

我们已经为 Windows Phone Silverlight 8 问题卸载了 Xamarin.Forms。需要再次安装 Xamarin.Forms。建议安装相同版本。

相同版本

安装完成后,让我们在您的应用程序中使用 StringLibrary 功能。

.NET Core – 创建测试项目

在本章中,我们将讨论如何使用 .NET Core 创建测试项目。单元测试是针对具有应用程序的最小可测试部分(称为单元)的软件的开发过程。他们被单独和独立地检查以确保任何正确的操作。单元测试既可以自动化,也可以手动完成。

现在让我们打开 New Project 对话框并选择Visual C# → .NET Core模板。

可视化C#

在此对话框中,您可以看到没有用于单元测试的项目模板。要创建单元测试项目,我们应该使用命令行实用程序。让我们转到我们创建的解决方案文件夹;创建一个 test 文件夹并在 test 文件夹内创建另一个文件夹并将其命名为StringLibraryTests

字符串库测试

现在让我们使用 dotnet 命令行实用程序通过执行以下命令来创建一个新的测试项目 –

dotnet new -t xunittest

您现在可以看到创建了一个新的 C# 项目;让我们通过执行v命令查看文件夹,您将看到project.jsonTests.cs文件,如下所示。

目录命令

这是 project.json 文件中的代码。

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "debugType": "portable" 
   }, 
   "dependencies": { 
      "System.Runtime.Serialization.Primitives": "4.1.1", 
      "xunit": "2.1.0", 
      "dotnet-test-xunit": "1.0.0-rc2-192208-24" 
   }, 
   "testRunner": "xunit", 
   "frameworks": { 
      "netcoreapp1.0": { 
         "dependencies": { 
            "Microsoft.NETCore.App": { 
               "type": "platform", 
               "version": "1.0.1" 
            } 
         }, 
         "imports": [ 
            "dotnet5.4", 
            "portable-net451+win8" 
         ] 
      } 
   } 
} 

以下是 Test.cs 文件中的代码。

using System; 
using Xunit; 
namespace Tests { 
   public class Tests { 
      [Fact] 
      public void Test1() { 
         Assert.True(true); 
      } 
   } 
} 

要从 NuGet 获取必要的依赖项,让我们执行以下命令 –

dotnet restore

当必要的依赖关系恢复时,我们可以运行测试。

已恢复

可以看到编译成功了;当您往下走时,您可以看到有关所执行测试的一些信息。

测试执行

目前我们执行了 1 个测试,0 个错误,0 个失败,0 个跳过,执行过程所花费的时间也作为信息提及。

.NET Core – 在 Visual Studio 中运行测试

在本章中,我们将讨论如何在 Visual Studio 中运行测试。.NET Core 的设计考虑了可测试性,因此为您的应用程序创建单元测试比以往任何时候都容易。在本章中,我们将在 Visual Studio 中运行和执行我们的测试项目。

让我们在 Visual Studio 中打开 FirstApp 解决方案。

第一应用解决方案

您可以看到它只有两个项目,您将无法看到测试项目,因为我们还没有在我们的解决方案中添加该项目。

让我们先添加一个文件夹并将其命名为test

测试

右键单击测试文件夹。

测试文件夹

选择project.json文件并单击Open

项目 Json 文件

以下屏幕截图显示了Tests.cs文件中的代码作为输出。

测试

它是默认实现,只是测试 True 是否等于 true。它是 xUnit 测试框架,您将看到注释和表示测试方法的 Fact 属性。

using System; 
using Xunit; 
  
namespace Tests { 
   public class Tests { 
      [Fact] 
      public void Test1() { 
         Assert.True(true); 
      } 
   } 
} 

以下是project.json文件的实现

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "debugType": "portable" 
   }, 
   "dependencies": { 
      "System.Runtime.Serialization.Primitives": "4.1.1", 
      "xunit": "2.1.0", 
      "dotnet-test-xunit": "1.0.0-rc2-192208-24" 
   }, 
   "testRunner": "xunit", 
   "frameworks": { 
      "netcoreapp1.0": { 
         "dependencies": { 
            "Microsoft.NETCore.App": { 
               "type": "platform", 
               "version": "1.0.1" 
            }
         }, 
         "imports": [ 
            "dotnet5.4", 
            "portable-net451+win8" 
         ] 
      } 
   } 
}

project.json文件中,对测试框架最重要的依赖是 xunit,它引入了 Fact 属性。它引入了用于使用 xunit 进行测试的测试框架和 API。

我们还有dotnet-test-xunit,这是一个采用者,以便 xunit 可以与 .NET Core 一起使用,特别是与dotnet test命令行实用程序一起使用。然后您将看到将运行xunit 的 testRunner,您还可以看到netcoreapp1.0框架。

您将在下面看到 .NETCore.App 依赖项。

要在 Visual Studio 中运行测试,让我们从测试 → 窗口 → 测试资源管理器菜单选项中打开测试资源管理器

测试浏览器

您可以看到 Visual Studio 自动检测测试。测试的名称namespace.className.TestMethodName组成现在让我们点击Test Explorer 中的 Run All 按钮

运行所有按钮

它将首先构建代码并运行测试,您将看到测试所花费的总时间。让我们更改测试方法,以便我们可以在测试失败时看到输出。

using System; 
using Xunit; 
  
namespace Tests { 
   public class Tests { 
      [Fact] 
      public void Test1() { 
         Assert.True(false); 
      } 
   } 
} 

让我们通过单击Run All按钮链接再次执行测试

全部运行

您现在可以看到测试失败。

.NET Core – 测试库

在本章中,我们将测试我们的 StringLibrary,为此,我们需要重新安排我们的项目,以便我们可以遵循默认约定。

让我们打开global.json文件。

{ 
   "projects": [ "src", "test" ], 
   "sdk": { 
      "version": "1.0.0-preview2-003131" 
   } 
}

在此文件的顶部,您将看到项目设置,默认设置一些文件夹,例如srctest

按照惯例,我们必须在这些文件夹中有项目,这是新的惯例,将用作 .NET Core 的一部分。

在解决方案资源管理器中,您可以看到控制台项目和库项目都在src文件夹中,而测试项目在test文件夹中。

源文件夹

并且解决方案资源管理器中的项目结构并不代表项目在磁盘上的物理位置。现在让我们打开 Solution 文件夹,您将看到StringLibrary项目不在src文件夹中。

字符串库项目

您可以看到srctest文件夹都映射到global.json文件中指定的约定但是,我们有一个不符合惯例的项目 StringLibrary。现在让我们src文件夹中添加StringLibrary项目

在 src 文件夹中,我们有两个项目,我们需要修复问题,以便我们可以正确使用所有项目。让我们回到 Visual Studio 并右键单击 StringLibrary 项目并选择 Remove 选项。它不会删除它,但只会删除该项目。

删除项目

现在右键单击 src 文件夹并选择添加 → 现有项目…

资源中心

浏览到现在位于src文件夹中的 StringLibrary 项目,选择StringLibrary.csproj文件并单击Open

StringLibrary.csproj

我们现在必须控制台应用程序project.json文件中删除对StringLibrary的引用

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
   "dependencies": { 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1" 
      }, 
      "NuGet.CommandLine": "3.5.0", 
      "System.Runtime.Serialization.Json": "4.0.3" 
   }, 
   "frameworks": { 
      "netcoreapp1.0": { 
         "dependencies": { }, 
         "imports": "dnxcore50" 
      } 
   } 
} 

保存更改,然后在控制台项目中再次添加对StringLibrary的引用

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
   "dependencies": { 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1" 
      }, 
   "NuGet.CommandLine": "3.5.0", 
      "System.Runtime.Serialization.Json": "4.0.3" 
   }, 
   "frameworks": { 
      "netcoreapp1.0": { 
         "dependencies": { 
            "StringLibrary": { 
               "target": "project" 
            } 
         }, 
         "imports": "dnxcore50" 
      } 
   } 
}

现在一切都应该可以正常工作了,您可以构建StringLibraryFirstApp(控制台项目)而不会出现任何错误。现在让我们使用 xunit 测试 StringLibrary 功能。我们需要将 StringLibrary 的引用添加到我们的测试项目中。右键单击 StringLibraryTests 项目的引用,然后选择添加引用…

添加

单击“确定”,这会将StringLibrary的引用添加到我们的测试项目中。现在让我们替换Tests.cs文件中的以下代码

using System; 
using Xunit; 
using StringLibrary; 
  
namespace Tests { 
   public class Tests { 
      [Fact] 
      public void StartsWithUpperCaseTest() { 
         string input = "Mark"; 
         Assert.True(input.StartsWithUpper()); 
      } 
      [Fact] 
      public void StartsWithLowerCaseTest() { 
         string input = "mark"; 
         Assert.True(input.StartsWithLower()); 
      } 
      [Fact] 
      public void StartsWithNumberCaseTest() { 
         string input = "123"; 
         Assert.True(input.StartsWithNumber()); 
      } 
   } 
} 

您可以看到我们有三个测试方法来测试 StringLibrary 的功能。让我们单击Run All链接,您将在测试资源管理器中看到以下输出。

运行所有链接

您还可以从命令行运行测试。让我们打开命令提示符并执行dotnet test命令。

.Net 测试

托管可扩展性框架

在本章中,我们将讨论托管可扩展性框架 (MEF)。MEF 可用于第三方插件可扩展性,或者它可以将松散耦合的插件式架构的好处带到常规应用程序中。

  • MEF 是一个用于创建轻量级、可扩展应用程序的库。

  • 它允许应用程序开发人员无需配置即可发现和使用扩展。

  • MEF 是 .NET Framework 4 的组成部分,可在使用 .NET Framework 的任何地方使用,以提高大型应用程序的灵活性、可维护性和可测试性。

  • 您可以在客户端应用程序中使用 MEF,无论它们使用 Windows 窗体、WPF 或任何其他技术,还是在使用 ASP.NET 的服务器应用程序中。

  • MEF 也已作为Microsoft.Composition移植到 .NET Core,但部分移植

  • 移植System.CompositionSystem.ComponentModel.Composition尚不可用。这意味着,我们没有可以从目录中的程序集加载类型的目录。

在本章中,我们将只学习如何在 .NET Core 应用程序中使用 MEF。

让我们了解一个简单的示例,在该示例中我们将在 .NET Core 控制台应用程序中使用 MEF。现在让我们创建一个新的 .NET Core 控制台项目。

在左侧窗格中,选择Templates → Visual C# → .NET Core,然后在中间窗格中,选择 Console Application (.NET Core)。

在名称字段中输入项目名称,然后单击确定。

名称字段

创建项目后,我们需要添加 Microsoft.Composition 的引用,以便我们可以使用 MEF。为此,让我们右键单击解决方案资源管理器中的项目并管理 NuGet 包…

搜索Microsoft.Composition并单击安装

管理

单击确定按钮。

单击按钮

单击我接受按钮。

接受

安装完成后,您会在参考资料中发现错误。

错误参考

让我们打开project.json文件。

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
  
   "dependencies": { 
      "Microsoft.Composition": "1.0.30", 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1" 
      } 
   }, 
  
   "frameworks": { 
      "netcoreapp1.0": { 
         "imports": "dnxcore50" 
      } 
   } 
}

可以看到添加Microsoft.Composition依赖,但问题是这个包与dnxcore50不兼容所以我们需要导入portablenet45+win8+wp8+wpa81现在让我们用以下代码替换您的project.json文件。

{ 
   "version": "1.0.0-*", 
   "buildOptions": { 
      "emitEntryPoint": true 
   }, 
   "dependencies": { 
      "Microsoft.Composition": "1.0.30", 
      "Microsoft.NETCore.App": { 
         "type": "platform", 
         "version": "1.0.1"
      } 
   }, 
   "frameworks": { 
      "netcoreapp1.0": { 
         "imports": "portable-net45+win8+wp8+wpa81" 
      } 
   } 
} 

保存此文件,您将看到错误已得到纠正。

已整改

如果展开引用,您将看到Microsoft.Composition的引用

Microsoft.Composition

首先,我们需要创建一个要导出的接口并实现该接口并使用 export 属性装饰类。现在让我们添加一个新类。

在名称字段中输入您的班级名称,然后单击添加

点击添加

让我们在PrintData.cs文件中添加以下代码

using System; 
using System.Collections.Generic; 
using System.Composition; 
using System.Linq; 
using System.Threading.Tasks; 
  
namespace MEFDemo { 
   public interface IPrintData { 
      void Send(string message); 
   } 
   [Export(typeof(IPrintData))] 
   public class PrintData : IPrintData { 
      public void Send(string message) { 
         Console.WriteLine(message); 
      } 
   } 
} 

如上所述,目录在 Microsoft.Composition 命名空间中不可用。因此,它将从带有导出属性的程序集中加载所有类型并附加到导入属性,如 Program.cs 文件中的 Compose 方法所示。

using System; 
using System.Collections.Generic; 
using System.Composition; 
using System.Composition.Hosting; 
using System.Linq; 
using System.Reflection; 
using System.Threading.Tasks; 
  
namespace MEFDemo { 
   public class Program { 
      public static void Main(string[] args) { 
         Program p = new Program(); 
         p.Run(); 
      } 
      public void Run() { 
         Compose(); 
         PrintData.Send("Hello,this is MEF demo"); 
      } 
      [Import] 
      public IPrintData PrintData { get; set; } 
      
      private void Compose() { 
         var assemblies = new[] { typeof(Program).GetTypeInfo().Assembly }; 
         var configuration = new ContainerConfiguration() 
            .WithAssembly(typeof(Program).GetTypeInfo().Assembly); 
         
         using (var container = configuration.CreateContainer()) { 
            PrintData = container.GetExport<IPrintData>(); 
         } 
      } 
   } 
}

现在让我们运行您的应用程序,您将通过实例化PrintData看到它正在运行

打印数据

要了解有关 MEF 的更多信息,请访问以下 URL https://msdn.microsoft.com/en-us/library/dd460648%28v=vs.110%29.aspx了解更多详细信息。

.NET 核心 – SDK

在本章中,我们将了解 .NET Core 中即将推出的功能。我们将通过在浏览器中打开以下 URL 来开始使用 .NET 命令行工具https://github.com/dotnet/cli

网址

要了解有关进度的更多信息,您可以向下滚动下载最新版本的 .NET Core SDK,您将看到安装程序和二进制文件部分。

二进制部分

您可以看到不同操作系统的最新版本预览工具,让我们根据您的操作系统选择安装程序。

我们正在开发 .NET Core 2.0 的预览版 1。

现在让我们通过打开命令提示符并执行以下命令来查看我们当前的工具。

dotnet --info 

您将看到有关系统上当前安装的 .NET 命令行工具版本的信息,如下所示。

命令行工具

您可以看到目前我们有预览 2 工具。现在让我们运行以下命令来查看命令。

dotnet help new

对于项目的新命令语言,您可以选择 C# 和 F# 以及项目类型等。

项目类型

现在让我们看看最新版本的 .NET Core 的变化。下载安装程序后,双击它进行安装。单击安装。

安装程序

以下屏幕截图显示了安装过程。

过程

它将开始安装过程。一安装完成,关闭此对话框。

安装完成

打开命令提示符并执行以下命令。

dotnet --info

您将在系统上看到当前安装的 .NET 命令行工具版本信息,如下所示。

系统工具

您现在可以看到我们拥有 .NET Core 2 的 preview1 工具。现在让我们在命令提示符中运行以下代码,以了解 .NET Core 2 preview1 中的新命令。

dotnet help new

该命令还可以帮助您将包下载到包缓存中。

包缓存

该命令将打开以下网页,其中包含有关 .NET Core 2 preview1 中新命令的信息。

预览1

让我们向下滚动,您现在可以看到我们可以使用更多模板创建 .NET Core 应用程序。

模板

我们现在也可以使用命令行创建mstest、web、mvcwebapi项目。

.NET Core – MSBuild 和 project.json

.NET Core 决定放弃 project.json 并返回到 MSBuild 和 *.csproj。这在刚刚发布的 .Net Core 2.0 preview1 工具中已经发生了。这相当令人失望,因为 project.json 是一股清新的空气。但是,这是可以理解的,并且也有许多优点。

现在让我们讨论变化带来的优势 –

  • 它将使现有的 Visual Studio 解决方案向 .NET Core 的过渡变得简单。

  • 这是一个巨大的变化,它还可以利用基于 MSBuild 的 CI/RM 的现有投资。

  • 在 MSBuild 中构建期间,我们可以考虑增量编译、解决构建时依赖项、配置管理等。

  • 按时交付 dotnet cli 需要做很多工作,因为它不再只是关于 ASP.NET Core,还有控制台应用程序、UWP 应用程序等。

以下是 MSBuild 和 *.csproj 的变化 –

  • Project.json 文件 (*.xproj) 将被 MSBuild (*.csproj) 替换。

  • project.json 中的功能将开始合并回 *.csproj。

  • 目前尚不清楚他们将如何处理包列表,但有人提到他们可能会将其保留为nuget.json下的 json或将其合并到*.csproj 中

  • 如果使用 Visual Studio,该转换应该是平滑的并且可能是自动的。

MSBuild 的优势

  • MSBuild 是开源的,可在 GitHub 上获得,并且必将成为完全跨平台的。

  • MSBuild 将极大地简化和修剪*.csproj的结构

  • 微软还推出了一个新的项目系统,它可以在不需要 Visual Studio 的情况下启用很多场景,详细信息在这个 URL https://github.com/dotnet/roslyn-project-system/ 上给出

  • 目标是即使使用 MSBuild 设置,在 Visual Studio IDE 中与在外部一样无缝地处理构建和项目。

MSBuild 与 project.json

现在让我们通过执行以下命令,使用 .NET Core preview2 工具创建一个新的控制台项目。

dotnet new -t console 

要查看此项目中创建的所有文件,请运行dir命令。

运行目录

可以看到创建了两个文件,Program.csproject.json文件。

现在让我们通过执行以下命令,使用 .NET Core 2 preview1 工具创建一个控制台应用程序。

dotnet new console 

要查看此项目中创建的所有文件,请运行dir命令。您可以看到创建了三个文件,Program.cs、NuGet.configMSBuild.csproj,而不是 project.json 文件。

安慰

现在让我们并排比较project.jsonMSBuild.csproj文件。

比较

左边是 json 格式的文件,右边是 XML 格式的文件。您可以看到在 project.json 文件的依赖项部分中,有netcoreapp1.0,而在 MSBuild.csproj 文件中,您将看到netcoreapp2.0

使用 MSBuild 恢复和构建

在本章中,我们将讨论如何使用命令行实用程序恢复和构建 MSBuild (*.csproj) 文件。要查看 .NET Core 2.0 预览版 1 中可用的命令,让我们运行以下命令。

dotnet help 

您将看到所有命令,例如新建、还原、构建等。

恢复

以下是Program.cs文件中的默认实现

using System;  
namespace MSBuild { 
   class Program { 
      static void Main(string[] args) { 
         Console.WriteLine("Hello World!"); 
      } 
   } 
} 

现在让我们执行以下命令来查看进度。

dotnet build

你会看到很多错误。这些错误需要纠正。

很多错误

现在让我们运行以下命令。

dotnet restore

可以看到所有的包都恢复了。还生成了一些新文件夹和文件。

生成

要查看目录结构,让我们运行以下命令。

tree /f 

以下是目录结构 –

目录结构

现在让我们再次运行以下命令重建项目。

dotnet build

现在您的项目将成功构建,没有任何错误,并且还创建了 MSBuild.dll。

MSBuild.dll

要查看输出,让我们运行以下命令 –

dotnet run 

您可以在控制台上看到以下输出。

控制台输出

.NET Core – 迁移

在本章中,我们将迁移包含project.json文件构建系统而不是MSBuild (*.csproj)的控制台应用程序因此,我们有一个包含以下文件的旧项目。

以下文件

现在的问题是,我们为什么需要迁移?这个项目是使用 .NET Core 1.0 preview 2 工具创建的,现在我们已经安装了 .NET Core 2.0 preview 1 工具。现在,当您使用 .NET Core 2.0 命令行实用程序构建此应用程序时,您将看到以下错误。

跟随错误

这是因为project.json构建系统在 .NET Core 2.0 中不再可用,因此我们需要迁移才能使其正常工作。要查看可用命令,让我们运行以下命令。

dotnet help 

在命令部分,您可以看到不同的命令,还可以看到将基于 project.json 的项目迁移到基于 MSBuild 的项目migrate命令。

迁移

现在让我们运行以下命令。

dotnet migrate 

您将看到迁移过程的摘要,您还可以在此处看到项目已成功迁移。

迁移成功

现在让我们使用以下命令查看目录结构。

tree /f 

您现在将在项目根目录中看到 *.csproj 文件和 Program.cs 文件,并将 project.json 移动到备份文件夹。

备份文件夹

让我们打开console.csproj文件。现在,您可以通过运行以下命令,使用 MSBuild 系统恢复和构建此项目。

dotnet restore 

您现在可以看到所有包都已恢复。

网络还原

您现在可以使用以下命令构建您的项目。

dotnet build 

您现在可以看到使用 MSBuild 成功构建了项目,并且在..\bin\Debug\netcoreapp1.0文件夹中还生成了 console.dll

MSBuild

以下屏幕截图显示了目录结构和文件。

截屏

觉得文章有用?

点个广告表达一下你的爱意吧 !😁