揭示.NET Core和.NET Standard

作为.NET家族的最新成员,有很多关于.NET Core和.NET Standard的误解,以及它们于.NET Framework之间的区别。在这篇文章,我会准确的解释他们究竟是什么,并看看何时应选择哪一个。

在详细介绍之前,首先查看.NET的结构图,它将帮助我们更好的理解.NET Core和.NET Standard所在的未知。当15年前,.NET 框架第一版发布时, 它有一个单一的. NET 堆栈, 可用于构建 Windows 桌面和 Web 应用程序。从那时起,其他.NET 实现也开始出现,比如 Xamarin,使用Xamarin你可以为iOS和Android构建移动应用程序,以及macOS桌面应用程序,如图 1所示.


图 1 .NET 结构图

关于.NET Core和.NET Standard如何融入.NET结构:

  • .NET Core: .NET Core是最新的一个.NET 实现。开放源代码,可用于多个操作系统。使用.NET Core,你可以构建跨平台控制台应用程序和 ASP.NET Core Web 应用程序和云服务。

  • .NET Standard: 这是所有的.NET实现所必须实现的基本Api (通常称为base class library或 BCL)。通过以.NET Standard为目标,您可以构建能够在所有. net 应用程序之间共享的库, 无论它们运行在哪个.NET实现或在哪个操作系统上。

.NET Core 简介

.NET Core是一个.NET Framework 和 Silverlight的一个分支,支持跨平台并且完全开源。它通过启用独立的 XCOPY 部署来优化移动和服务器工作负载。

为了更好的了解.NET Core,让我们详细查看基于.NET Core的开发是如何进行的,同时探索新的基于命令行的工具。你也可以使用 Visual Studio 2017来进行. NET Core开发,但因为你正在阅读本文,你很可能已经熟悉 Visual Studio,所以我将重点介绍新的体验。

当.NET 创建时, 它为 Windows 上的快速应用程序开发进行了大量优化。在实践中,这意味着,.NET 开发和 Visual Studio 是形影不离的好朋友。当然:使用 Visual Studio开发是一种冲击。它极为高效,并且调试器是我用过最好的工具。

但是, 在某些情况下, 使用 Visual Studio 并不是很方便。比如你只是想要简单的通过.NET学习 C#,你不应该下载并安装一个大型的IDE。或者你通过 SSH 访问 Linux 机器,此时无法使用IDE。或者你只是更喜欢使用命令行界面 (CLI)。

这就是名为.NET Core CLI被创建的原因。.NET Core CLI 的主要命令为dotnet。你可以将其用于开发的几乎所有方面, 包括创建、编译、测试和打包项目。让我们通过实例来了解它是如何操作的。

创建并运行一个 Hello World 控制台应用程序 (我在Windows系统使用PowerShell,但是同样可以在macOS或Linux的Bash中运行):

$ dotnet new console -o hello
$ cd hello
$ dotnet run
Hello World!

CLI中的 dotnet new 命令等于Visual Studio中的文件|新建项目。 你可以创建各种不同的项目类型。输入 dotnet new 以查看预安装的不同模板。

现在,让我们将一些逻辑提取到一个类库中。为此,需首先创建一个类库项目平行于你的 hello 项目:

$ cd ..
$ dotnet new library -o logic
$ cd logic

你想要封装的逻辑是构建一个 Hello World 的消息,所以修改 Class1.cs 的内容为下面的代码:

namespace logic
{public static class HelloWorld{public static string GetMessage(string name) => $"Hello {name}!";`}
}

同时你还需要重命名 Class1.cs 为 HelloWorld.cs:

$ mv Class1.cs HelloWorld.cs

注意,您不需要由于此变化更新项目文件。使用在.NET Core的新项目文件会包含项目目录中的所有源文件。因此,添加、 删除和重命名文件并不需要再修改项目文件。这使得命令行文件操作更加顺畅。

若要使用 HelloWorld 类,您需要更新 Hello 应用程序引用的逻辑类库。你可以通过编辑项目文件,或者通过使用dotnet add reference命令:

$ cd ../hello
$ dotnet add reference ../logic/logic.csproj

现在,修改 Program.cs 文件以使用 HelloWorld 类,如下所示.

using System;
using logic;
namespace hello{class Program{static void Main(string[] args){Console.Write("What's your name: ");var name = Console.ReadLine();var message = HelloWorld.GetMessage(name);Console.WriteLine(message);}}}

要生成并运行您的应用程序,只需输入 dotnet run

$ dotnet run
What's your name: Immo
Hello Immo!

你还可以从命令行创建测试。CLI 支持 MSTest,以及流行的 xUnit 框架。本示例中使用xUnit:

$ cd ..
$ dotnet new xunit -o tests
$ cd tests
$ dotnet add reference ../logic/logic.csproj

改变 UnitTest1.cs 的内容,如下所示,添加一个测试。

using System;
using Xunit;
using logic;
namespace tests
{public class UnitTest1{[Fact]public void Test1(){var expectedMessage = "Hello Immo!";var actualMessage = HelloWorld.GetMessage("Immo");Assert.Equal(expectedMessage, actualMessage);}}
}

现在你可以通过调用 dotnet test 运行测试:

$ dotnet test
Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.

为了让事情更有趣一点,让我们创建一个简单的 ASP.NET Core Web 站点:

$ cd ..
$ dotnet new web -o web
$ cd web
$ dotnet add reference ../logic/logic.csproj

编辑 Startup.cs 文件,修改app.Run方法,调用 HelloWorld类:

app.Run(async (context) =>
{var name = Environment.UserName;var message = logic.HelloWorld.GetMessage(name);await context.Response.WriteAsync(message);
});

若要启动 Web 开发服务器,只需使用 dotnet run 命令:

$ dotnet run
Hosting environment: Production
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

浏览到所显示的 URL,应该是 http://localhost:5000。

此时,你的项目文件夹结构应该看上去如下所示:

$ tree /f
│
├───hello
│ hello.csproj
│ Program.cs
│
├───logic
│ HelloWorld.cs
│ logic.csproj
│
├───tests
│ tests.csproj
│ UnitTest1.cs
│
└───web
Program.cs
Startup.cs
web.csproj

为了便于使用Visual Studio编辑文件的文件,让我们同样创建一个解决方案文件并向解决方案中添加的所有项目:

$ cd ..
$ dotnet new sln -n HelloWorld
$ ls -fi *.csproj -rec | % { dotnet sln add $_.FullName }正如你所看到的,.NET Core CLI 功能强大,来自其他背景的开发人员会产生非常熟悉的感觉。无论你使用在Windows PowerShell中使用dotnet还是在Linux或macOS中使用,这些平台的使用体验颇为相似。.NET Core的另一个巨大好处是它支持独立部署。你可以使用Docker,它具有其自己的.NET Core运行时副本。这使你可以在同一台机器使用不同版本的.NET Core而不互相干扰。因为.NET Core的开源特性,你还可以使用*nightly builds*甚至自己修改编译,包含自己所做修改的版本。当然,这已超出了这篇文章的讨论范围。
.NET 标准简介

当你构建现代应用程序时,您的应用程序往往跨平台或需要使用多个.NET 实现。当今时代,客户会期待他们可以在手机中使用 Web APP,数据通过基于云计算的后台服务共享。当使用笔记本电脑时,他们也会想要通过 Web 站点获取访问权限。对于自己的基础架构,你可能想要使用命令行工具,甚至可能通过桌面应用程序让您的员工管理系统。下面是不同.NET实现是如何实现这一目标的。

|           |  OS        |是否开源  |                   目的                              |
| .NET Framework | Windows     |   否   | 构建Windows应用程序,构建运行在IIS上的Web应用程序       |
| .NET Core    | Windows, Linux, macOS |  是  | 构建跨平台命令行应用程序、ASP.NET Core应用程序、云服务  |
| Xamarin     | iOS, Android, macOS  |   是 | 构建iOS、Android移动应用程序、macOS桌面应用程序        |
| .NET Standard     | N/A      |   是 | 创建可以被所有.NET实现(如.NET Core和.NET Framework)所引用的类库    |

在这种环境中,代码共享成为一项重大挑战。你需要理解 Api 是否可用,并确保共享的组件只使用在您正在使用的所有.NET 实现中可用的 Api。

这就是.NET Standard出现的原因,.NET Standard是一种规范,每个.NET Standard定义了所有.NET实现都必须提供的、符合该版本的Api集。你可以看作它然而另一个.NET 堆栈,只是你不能使用.NET Standard构建应用程序,而只能用来构建类库。这是您要从任何地方引用的库的. NET 实现。

你可能想知道.NET Standard包含了那些API,如果你熟悉.NET 框架,你应该熟悉我之前提到的BCL。BCL是独立于UI框架和应用程序模型的基本 API集。它包括基类型、 文件 I/O、 网络、 反射、 序列化、 XML 和其他。

所有的.NET堆栈都实现了某些版本的.NET Standard。按照经验,当构建一个新的.NET实现时,它通常会实现最新版本的.NET Standard。

一个很好的比喻是 HTML 和浏览器: 想象HTML规范是.NET Standard,不同的浏览器则是各种.NET实现,例如.NET Framework,.NET Core和Xamarin。

在这一点上,你可能好奇如何来使用.NET Standard。事实上,你已经使用过了。还记得我们先前创建的逻辑类库吗?让我们仔细看看项目文件:

$ cd logic
$ cat logic.csproj
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework></PropertyGroup></Project>

让我们对比"Hello"控制台应用程序的项目文件:

$ cd ..\hello
$ cat hello.csproj
<Project Sdk="Microsoft.NET.Sdk"><ItemGroup><ProjectReference Include="..\logic\logic.csproj" /></ItemGroup><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>netcoreapp2.0</TargetFramework></PropertyGroup></Project>

正如你所看到的,逻辑类库有一个属性为TargetFramework的项目,其值为 netstandard2.0,控制台应用程序中该项的值为 netcoreapp2.0TargetFramework 属性显示了你使用了哪个.NET实现。所以,控制台应用程序使用了.NET Core 2.0,而类库则使用了.NET Standard 2.0。这意味着你可以在.NET Core程序,使用.NET Framework构建的程序,以及Xamarin程序中引用该逻辑类库。

不幸的是,目前为止,大部分类库还没有针对.NET Standard编译。它们中的绝大多数都是针对.NET Framework编译的。当然,并不是所有的类库都可以 (或应该) 都针对.NET Standard编译。例如,包含 Windows Presentation Foundation (WPF) 控件的类库,需要针对.NET Framework编译,因为 UI 并不是.NET Standard的一部分。然而,更多的通用库只针对.NET Framework编译,仅仅是因为他们创建时,.NET Standard还不存在。

在.NET Standard 2.0 中,API 集增加到足够大,因此大多数(如果不是全部)的通用库都可以针对.NET Standard编译。因此,Nuget上存在的通用类库中,70%的类库都只使用了.NET Standard 的 Api。但是,仍然只有一小部分被显式标记为与.NET Standard兼容。

为了使得开发人员可以无障碍的使用它们,添加了兼容模式。如果你安装的NuGet包没有为你的目标框架提供类库,也没有为.NET Standard提供,NuGet会尝试退回.NET Framework。换句话说,你可以同添加.NET Standard类库一样,添加.NET Framework的类库引用。

我会为你展示此操作。在我的示例中,我将使用写于2007年,名为PowerCollections的类库,此类库已经有一段时间未进行更新,并且仍然针对.NET Framework 2.0编译。我将通过NuGet安装这个类库到 Hello 程序中。

$ dotnet add package Huitian.PowerCollections

此库提供了BCL没有提供一些集合类型,比如 bag,。让我们修改 Hello 应用程序来使用它,如下所示.

using System;
using Wintellect.PowerCollections;
namespace hello
{class Program{static void Main(string[] args){var data = new Bag<int>() { 1, 2, 3 };foreach (var element in data)Console.WriteLine(element);}}
}

如果你运行该程序,您将看到以下内容:

$ dotnet run
hello.csproj : warning NU1701: Package 'Huitian.PowerCollections 1.0.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This may cause compatibility problems.
1
3
2

所以,刚刚发生了什么?Hello应用程序的目标框架为.NET Core 2.0。由于.NET Core 2.0 实现.NET Standard 2.0,它同时具有对.NET Framework类库引用的兼容性模式。然而,并不是所有的.NET Framwork都能工作在所有的.NET实现中。例如,他们可能会使用 Windows Forms 或 WPF Api。NuGet则并不知道这些信息,因此,它给了你一条警告消息,似的你可以意识到这种情况,对由此造成的问题进行故障排除,减少排除故障的时间。

请注意,每次生成程序,你都将看到此警告。这避免了你在包安装过程中没有注意到警告,或者干脆忘记了这个警告。

当然,没有什么比每次生成程序时收到警告更糟糕的了。所以,这里的建议是,当你验证你的应用程序后,就可以可以禁用针对该软件包的警告。因为应用程序运行良好(它正确打印了您创建的bag中的内容),所以你现在可以禁止显示此警告。要做到这一点,编辑 hello.csproj 文件,并将 NoWarn 属性添加到包引用:

<PackageReference Include="Huitian.PowerCollections" Version="1.0.0" NoWarn="NU1701" />

如果你现在再次运行该程序,应该就不会再看到此警告了。如果你使用兼容模式安装另一个NuGet包,你同样会收到针对另一个包的运行警告。

这款新工具还允许类库在生成时,将NuGet程序包作为生成的一部分。这使得你与世界 (使用nuget.org) 或只是在您的组织内分享你的类库 (通过发布自己的包到Visual Studio Team Services 或 MyGet)成为了一项简单的工作。新项目也支持多个目标框架,使得你在单个项目中针对多个.NET实现进行生成。这意味着您可以使用条件编译 (#if) 以适配类库到.NET 的特定实现。它还允许你为特定于平台的 Api 构建.NET Standard wrappers。然而,这些都超出了本文的范围。

  • 总结

.NET Standard规范了所有的.NET实现都必须提供的API。它为.NET家族带来了一致性,并使你能够生成可供所有.NET实现使用的类库。它取代了PCL来构建共享的组件。

.NET Core是.NET Standard的其中一个实现,为建立控制台应用程序、 Web 应用程序和使用ASP.NET Core的云服务进行了优化。它的SDK中附带了一个强大的工具,除使用Visual Studio进行开发外,还支持完整的基于命令行的开发流程。
你可以了解通过aka.ms/netstandardfaq 和 aka.ms/netcore 了解更多.


Immo Landwerth is a program manager at Microsoft, working on .NET. He focuses on .NET Standard, the BCL and API design.

相关文章: 

  • .NET Core 2.0 正式发布信息汇总

  • .NET Standard 2.0 特性介绍和使用指南

  • .NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决

  • .NET Core 2.0 特性介绍和使用指南

  • Entity Framework Core 2.0 新特性

  • 体验 PHP under .NET Core

  • .NET Core 2.0使用NLog

  • 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

  • 解决Visual Studio For Mac Restore失败的问题

  • ASP.NET Core 2.0 特性介绍和使用指南

  • .Net Core下通过Proxy 模式 使用 WCF

  • .NET Core 2.0 开源Office组件 NPOI

  • ASP.NET Core - Razor页面之Handlers处理方法

  • ASP.NET Core Razor页面 vs MVC

  • Razor Page–Asp.Net Core 2.0新功能  Razor Page介绍

  • ASP.Net Core 2.0中的Razor Page不是WebForm

  • ASP.NET Core Razor 视图组件

  • Error Handling in ASP.NET Core

  • ASP.NET Core中为指定类添加WebApi服务功能

  • .Net Core 全局配置读取管理方法 ConfigurationManager

  • ASP.NET Core Web服务器 Kestrel和Http.sys 特性详解

  • asp.net core 2.0 web api基于JWT自定义策略授权

  • 体验 ASP.NET Core 中的多语言支持(Localization)

  • ASPNET Core 2.x中的Kestrel服务器

  • asp.net core mvc View Component 应用

  • .net core 使用Redis的发布订阅

  • Configuration Extensions - 简化配置,让你配置支持变量

  • ASP.NET Core 运行原理剖析

原文地址:http://www.jianshu.com/p/ae24babe606d


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用wxjava实现发表内容、预览信息以及推送文章

大家好&#xff0c;我是雄雄。 文章目录前言保存草稿的方法获取草稿箱列表根据media_id获取草稿箱信息给指定人发送预览文章推送文章&#xff08;按照标签推送&#xff09;前言 今天分享的内容有如下几个&#xff1a; 保存草稿根绝media_id会哦去草稿箱的信息发表内容&#x…

指针数组(三)

#include<stdio.h>void g(int *pArr,int len){pArr[2]88;pArr[4]88;}void f(){int a[]{1,2,3,5,9},i;g(a,5);for(i0;i<5;i){printf("%d\t",a[i]);}}main(){f();}利用指针改变数组里的内容和内容

spring cloud+dotnet core搭建微服务架构:服务发现(二)

前言上篇文章《手把手教你使用spring clouddotnet core搭建微服务架构&#xff1a;服务治理&#xff08;-&#xff09;》实际上只讲了服务治理中的服务注册&#xff0c;服务与服务之间如何调用呢&#xff1f;传统的方式&#xff0c;服务A调用服务B&#xff0c;那么服务A访问的是…

猿创征文|公众号开发之路——为了研究公众号,我注册了公司

大家好&#xff0c;我是雄雄。 内容先知&#x1f60a;1.前言&#x1f636;2.想法&#x1f913;3.注册及研究&#x1f4aa;4.注册公司现在是北京时间&#xff1a;2022年9月10日23:34&#xff0c;农历八月十五日&#xff0c;2022年的教师节&#xff0c;也是中秋节&#xff0c;祝大…

动态数组(四)

#include<stdio.h>void f(int *q){*q200;}main(){int *p(int *)malloc(sizeof(int));*p10;printf("%d\n",*p);f(p);printf("%d\n",*p);}动态数组应用&#xff1a;&#xff08;记得导入#include<malloc.h>&#xff09; #include<stdio.h>…

Docker 实战笔记

Docker的安装与配置CentOS前提条件目前&#xff0c;CentOS 仅在发行的版本中的内核支持DockerDocker 运行在CentOS 7 上要求系统为64位&#xff0c;系统内核版本在3.10以上。本次测试运行使用的是 centOS 7.2 64位的系统版本。使用代码 uname -r即可查看系统内核版本Docker软件…

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

转载自 JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解 现实企业级Java开发中&#xff0c;有时候我们会碰到下面这些问题&#xff1a; OutOfMemoryError&#xff0c;内存不足 内存泄露 线程死锁 锁争用&#xff08;Lock Contention&#xff09; Java进…

jeecg微服务中如何实现机构的概念(当前机构只能查到其子机构)

大家好&#xff0c;我是雄雄。 内容先知前言代码实现前言 以前&#xff0c;我们做的国家平台项目&#xff0c;都是采用现在开源的框架来做的&#xff0c;比如若依&#xff0c;bladex&#xff0c;相比之下&#xff0c;若依用的要稍多点儿。因为那时候刚开始接触vue&#xff0c;…

初学结构体(一)

#include<stdio.h>struct Student{int age;float score;char sex;};main(){struct Student st{25,88,M};printf("%d\n",st.age); struct Student *pst&st;pst->age100;printf("%d\n",st.age);printf("%d",pst->age); }构造结构…

.NET Conf 2017后初尝Xamarin Forms 3.0@Linux

对很多.NET粉&#xff0c;.NET Conf 2017的东西估计提前一个月都熟悉了&#xff0c;Xamarin粉估计最大惊喜不是Xamarin Live Player, 也不是Xamarin.Forms混合NativeControl &#xff0c;而是Xamarin.Forms 3.0&#xff0c;因为它融入到 Linux平台. Xamarin.Forms 跨平台&#…

Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

转载自 Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比 redis作为一种高效的缓存框架&#xff0c;使用是非常广泛的&#xff0c;在数据存储上&#xff0c;在运行时其将数据存储在内存中&#xff0c;以实现数据的高效读写&#xff0c;并且根据定制的持久化规则…

微信小程序中使用画布canvas实现动态心电图绘制

大家好&#xff0c;我是雄雄。 内容先知前言效果图实现代码前言 近期&#xff0c;接了个项目&#xff0c;三端&#xff08;小程序、PC、公众号&#xff09;同步开发&#xff0c;PC端没的问题&#xff0c;以前一直做的就是PC端&#xff0c;但是小程序和公众号之前没有做过&…

nssl1163-小x游世界树【树形dp,二次扫描和换根法】

正题 题目大意 一棵树&#xff0c;一条边的权是原本的权值减去出发点的加速。 求一个点使得这个点到所有点路径边权和最小。 解题思路 我们先求出以1为根时的答案 然后用换根法 我们从1转移到2&#xff0c;我们会发现 红色的部分的路径都减去的紫色的路径长度&#xff0c;蓝…

结构体跨函数应用(二)

#include<stdio.h> struct Student { int age;char sex; };int main(void){struct Student st;InputStudent(&st);printf("%d,%c",st.age,st.sex);}void InputStudent(struct Student *pstu) {(*pstu).age88;pstu->sexF;}老是出现警告&#xff0c;排查好…

ASP.NET Core依赖注入解读使用Autofac替代实现

1. 前言关于IoC模式&#xff08;控制反转&#xff09;和DI技术&#xff08;依赖注入&#xff09;&#xff0c;我们已经见过很多的探讨&#xff0c;这里就不再赘述了。比如说必看的Martin Fowler《IoC 容器和 Dependency Injection 模式》&#xff0c;相关资料链接都附于文章末尾…

jmeter如何进行一个简单的测试(超级详细,有图有文字,闭着眼都能成功)

大家好&#xff0c;我是雄雄。 内容先知前言软件获取开始测试1.新建线程组2.创建一个请求3.添加HTTP信息头4.开始测试5.查看请求情况前言 上头问题要服务器的配置&#xff0c;基于我们现在做的项目&#xff0c;需要安排别人去采购服务器&#xff0c;给出的消息是&#xff1a;2…

开封游(一)

今天去开封玩了一下&#xff0c;白天在路程上耽搁太多时间&#xff0c;主要在晚上玩的。终于到显示我米9夜景功能的时候了。 去了包公祠&#xff0c;西司夜市&#xff0c;鼓楼夜市。 下午先去了包公祠 下面是夜景了&#xff0c;特别的炫酷。 首先是西司夜市 进去的时候 这个…

C#中的两把双刃剑:抽象类和接口

问题出现&#xff1a;我们在使用C#的抽象类和接口的时候&#xff0c;往往会遇到以下类似的问题&#xff0c;大致归纳如下:(1)抽象类和接口有什么本质的区别和联系&#xff1f;(2)什么时候选择使用抽象类&#xff0c;然啥时候使用接口最恰当呢&#xff1f;(3)在项目中怎样使用才…

开封游(二)

短暂的永远浪漫&#xff0c;漫长换来不满。人就是这样&#xff0c;第一天是怀着期盼喜悦的心情来的&#xff0c;等到二天&#xff0c;被漫长的行程磨平心境后就再也不想出来旅游了。 总之第二天的心情只能用疲倦来概括。 本来愉悦的心情&#xff0c;而转折点是在吃完海底捞之…

.NetCore之下载文件

本篇将和大家分享的丝.NetCore下载文件&#xff0c;常见的下载有两种&#xff1a;A标签直接指向下载文件地址和post或get请求后台输出文件流的方式&#xff0c;本篇也将围绕这两种来分享&#xff1b;如果对您有好的帮助&#xff0c;请多多支持。允许站点不识别content-type下载…