C#高级编程第11版

导航

第一章 .NET Applications and Tools

1.1 选择技术

.NET技术在Windows平台的开发上有着出色的表现,时至今日,它甚至可以创建在三大操作系统(Windows, Linux, Mac)上的通用程序。

.NET Core的出现是.NET技术发明以来最大的一次创新,它可以创建跨平台的应用,并且使用现代化模式(modern patterns)。

.NET Core和NuGet包管理工具配合使用使得微软能快速的发布新的功能特性。随着功能越来越多,使用何种技术方案来创建应用程序是一个值得深思的问题。

本章节提供了不同技术方案所能创建的Windows应用、Web服务的详细信息,告诉读者如何选择数据库访问方式,并且着重描述了.NET Framework和.NET Core之间的差异。

1.2 回顾.NET 历史

要了解C#和.NET能干什么,最好是先对它的发展历史有所了解。这个发展的历史表会重复用到,所以已经抽离出来放到 C# 全版本特性一览 里了。

这里着重介绍一下CLR和.NET Framework的关系。 扩展

而当你创建.NET Core项目时,你需要注意它的各个版本的技术支持会在何时结束。

LTS(Long time Support),通常在第一个LTS版本发布后保持3年技术支持,如果发布了下一个LTS版本了,则支持时间为Min(LTS发布时间+3年,下一个LTS发布时间+1年)。EOL(End of Life),结束支持。Maintence,支持中。

Version Release Latest Patch Patch Release SUPPORT LEVEL End of Support
1.0 2016.06.27 1.0.16 2019.05.14 EOL 2019.06.27
1.1 2016.11.16 1.1.13 2019.05.14 EOL 2019.06.27
2.0 2017.08.14 2.0.9 2018.07.10 EOL 2018.10.01
2.1 2018.05.30 2.1.16 2020.02.18 LTS 2021.08.21
2.2 2018.12.04 2.2.8 2019.11.19 EOL 2019.12.23
3.0 2019.09.23 3.0.3 2020.02.18 Maintenance 2020.03.03
3.1 2019.12.03 3.1.2 2020.02.18 LTS 2022.12.03

简单地讲,想获得足够长时间的技术支持,选最新发布的LTS版本构建应用即可。

1.2.1 C# 1.0 —— 一种新语言

C# 1.0是一门全新的编程语言,用于.NET Framework开发。在它设计发布的时候,整个.NET Framework已经包含有大概3000个类库和CLR。

因为版权的原因,微软并不能随意修改Java源代码,于是他们找来了Anders Hejlsberg,负责设计C#。在去微软工作前,Hejlsberg在Borland公司负责设计Delphi,一种基于Pascal的程序语言。起初他在微软负责J++(微软版Java)。由于Hejlsberg的个人经历,C#的设计思想主要借鉴了C++,Java以及Pascal。

因为C#是在Java和C++之后设计的,微软分析了它们一些典型的编程bug,并试图通过语法规范使得使用C#的程序员避免同样的错误。

以下就是部分C#的改进之处:

  • if 语句里必须是能返回Boolean值的表达式(在C++里允许用整型代表true和false)。

  • C# 里使用struct关键字定义值类型,而class关键字定义引用类型(在Java里仅支持class;而C++里的struct和class除了访问权限外,没什么本质上的区别)。

  • 支持虚方法和非虚方法(这点跟C++类似;Java里都是虚方法,可以随意override)。

当然还有更多的改进部分,这里不一一赘述。

在.NET和CLR设计之前,为了支持各种编程语言,它们各自拥有一个独立的运行时,像JScript.NET、VB.NET、C++.NET等等。最终它们被统一成了CLR,即公共语言运行时。.NET编译器负责把每种语言编译成中间代码(IL,Intermediate Language),然后由CLR的 Just-In-Time 编译器实时解释成机器原生指令执行。

中间代码IL其实就像一种面向对象的机器代码,可以用 ildasm.exe 查看。注意IL是托管代码(managed code)。

CLR还包含了其它部分,如垃圾回收管理GC(Garbage Collect),负责回收那些不再引用的托管代码;安全机制,决定运行中的代码允许访问的内容和权限;调试扩展,例如允许用C#的类库调试VB的代码;线程管理,负责处理后台程序的线程创建。

.NET Framework 1.0的类库很庞大。为了快速定位到相应的功能类库,使用了命名空间(Namespace)的组织方式。如System.Windows.Forms用来开发Windows桌面应用,System.Web用来开发ASP.NET,WebService负责桌面应用和Web应用之间的通信,.NET Remoting负责不同.NET程序之间的交互,Enterpise Services则负责创建应用服务器上的COM+组件。

ASP.NET Web Forms技术旨在让开发者像开发桌面应用一样开发Web程序,这样开发者不需要懂HTML和Javascript。Web Forms的服务端控件会自动为你生成相应的HTML和Javascript代码。

C# 1.2和.NET 1.1版本主要修复了前面版本的一些bug并追加了一些新功能。

1.2.2 带有泛型的C# 2 和.NET 2

C# 2和.NET 2是一次巨大的更新。在这个版本里,C#语言自身以及它编译成的中间语言IL都有所变化。这就是为什么CLR从1.1升级成2.0的原因。其中最重要的部分就是引入了泛型(Generics)的概念。

泛型允许你在创建类型的时候,不必要预先知道其内置类型(inner types)是啥,只有在创建一个实例(instance)的时候才会明确定义实际类型。

这次提升同样为Framework类库新增了不少类,比如新的泛型集合,你可以在System.Collection.Generic里找到它。因为这个新特性,1.0版本定义的旧集合类可能就不怎么用了。当然这些旧的集合类依然能调用,就算是在最新的.NET Core里。

1.2.3 .NET 3.0 —— WPF、WCF和WF

虽然.NET 3.0提供了海量的新类型、命名空间和类库,但它并没有增加任何新的C#特性(Features)。本次框架更新中最大的部分应该是 Windows Presentation Foundation(WPF),一种开发桌面应用程序的技术。

最早的Windows Forms提供的Windows Controls是基于像素(pixels)的,然而WPF却是基于DirectX直接绘制的。WPF的矢量技术使得WPF窗体可以任意伸缩(resize)而不会失真。WPF模板(Templates)还支持完全自定义外观。举个例子,一个为机场开发的软件界面上可以提供一个像飞机一样的按钮。总而言之,WPF开发的软件界面可以做得跟传统的Windows程序完全不一样。

在System.Windows下新增的类基本都属于WPF,除了原有的System.Windows.Forms。WPF的用户界面(user interface)可以用类似XML的语法进行创建,我们称之为XAML,全称是XML for Application Markup。

在.NET 3.0以前,应用程序之间的数据交互主要通过ASP.NET Web Serivces和.NET Remoting来实现,消息队列(Message Queue)只是一个备选项。不同的技术有着各自的优缺点,让人挠头的是,还有着各自的API。一个典型的企业软件显然需要用到不止一种数据交互的方式,因此开发人员需要对所有的API都了如指掌。Windows Communication Foundation(WCF) 解决了这个问题。它将各自的API集成到一起,通过WCF配置文件,开发人员可以用一套API解决所有的交互问题。

.NET 3.0中的第三大部分是 Windows WorkFlow(WF),相关的类都集中在System.Workflow命名空间下。为了避免在开发不同软件的时候各自创建一个工作流引擎,.NET Framework中集成了一个工作流引擎(但是Microsoft自己为自己各个产品创建了不同的工作流引擎)。

.NET 2.0的时候,基础类库中有8000多个类,而到了3.0,则增长到了大约12000个。

如果你想了解WPF和WCF的内容,请翻阅上一个版本的书籍《Professional C# 6 and .NET Core 1.0》。

1.2.4 C# 3 和.NET 3.5 —— LINQ

.NET 3.5框架是和C# 3.0版本一起发布的。本次更新最大的加强地方就在于定义了一种新的查询语法。你可以通过相同的查询语法,查找或排序一组对象、XML文档以及数据库。

本次新增的特性只是一种C#语法糖(syntax sugar),因此并没有修改任何IL代码。虽然你也可以选择用原有的基础语法实现查询,但是你需要编写更多的代码。C#希望简化这些编写步骤,减轻程序员的负担。通过使用LINQ(Language Integrated Query)或者Lambda表达式,你可以使用同一种语法访问对象集合,数据库和XML文档。

为了支持LINQ访问数据库,.NET 3.5集成了LINQ to SQL模块。.NET 3.5第一版发布的时候还同时发布了Entity Framework。它俩都能提供LINQ引擎和数据库之间的分层映射(map of hierarchies),只不过Entity Framework的功能更强大,而LINQ to SQL则更易用。后来,LINQ to SQL直接在Entity Framework内部实现了,并保留至今。最新发布的Entity Framework Core(EF Core)则看起来和第一版EF有相当大的区别。

.NET 3.5的另外一项新技术是插件模型(Add-in model),相关的类都在System.AddIn命名空间下。插件技术提供了进程外可执行的强大特性,只是它并不那么容易驾驭。

1.2.5 C# 4 和.NET 4.0 —— dynamic 和TPL

C# 4的主题是动态-集成(dynamic-integrating)脚本语言以及如何将其应用到COM组件集成上。本次更新里,C#里新增了dynamic关键字,命名参数和可选参数,增强了泛型的协变和逆变(co - and contra-variance)。

另外的功能加强主要体现在.NET Framework上,由于多核CPU的面世,并行编程开始越来越重要。TPL(Task Parallel Library)类库包含的TaskParallel类提供了线程抽象(abstractions of threads)功能使得开发人员可以更容易地创建并行代码。

因为.NET 3.0提供的工作流引擎并没有完美地达到它预期的效果,.NET 4发布了全新的工作流平台。为了避免和3.0的工作流冲突,新的工作流类库定义在System.Activity命名空间下。

想使用C# 4的增强功能你需要升级你的CLR,从CLR 2升级到CLR 4。

VS2010发布的时候打包了一项新的Web应用创建技术:ASP.NET MVC 2.0。跟ASP.NET Web Forms不同的是,这项新技术更关注MVC模式,以便更好的组织项目结构。不仅如此,它同样关注HTML和Javascript的编程发展,HTML5的发布在开发者社区掀起了一股HTML和Javascript的热潮。因为HTML5是一项新发布的标准,旧的Visual Studio和ASP.NET MVC也需要配合着升级更新。

1.2.6 C# 5 和异步编程

C# 5只有两个新的关键字asyncawait。然而,它们大大的简化了异步编程。Windows 8系统开始,触摸(touch)开始成为一项重要的功能,轻易阻塞用户界面(UI)线程会带来糟糕的用户体验。当使用鼠标的时候,用户可能习惯用鼠标滑轮滚动界面获取信息。但是在触摸屏(touch interface)上,用手指滚动屏幕的时候,如果界面僵死了没有任何响应,是很让人恼火的一件事情。

Windows 8同样介绍了一个用于Windows Store Apps(也称Modern apps, Metro apps, Universal Windows apps, 最近统称为Windows apps)的新编程接口:Windows Runtime。这是一个原生运行时(native runtime),使用了语言投射(language projections),看起来像.NET。许多WPF控件都根据这个运行时进行重新设计,.NET Framework的某些子集也可以用在这些Apps上。

因为之前发布的System.AddIn类库又复杂又慢,.NET 4.5框架发布了一个新的复合类库(composition framework):MEF(Managed Extensibility Framework),它被定义在System.Composition命名空间下。

ASP.NET Web API发布了一个新版本的跨平台交互方案。之前的WCF跟很多其他的网络协议一样,提供的是有状态和无状态的交互服务。而新的API与WCF不一样,它基于Restful(Representational State Transfer)软件架构,更加简单易用。

1.2.7 C# 6 和.NET Core 1.0

C# 6并没有像泛型、LINQ又或者async那样带来巨大的功能提升,但是它有许多小巧而实用的语法增强,以便你用更少的代码就可以实现原有的功能,这样可以大大的减轻你的代码量。这些新特性主要是通过一个新的编译引擎来实现的,代号Roslyn,或者称之为.NET编译平台(Compiler Platform)。

之前我们应用.NET Framework的时候,通常是发布一个完整的.NET Framework版本,但近些年来我们不再只单单发布一个完整版(Full Version)。因为有些应用场景只需要精简版框架(smaller frameworks)支持。举个例子,Silverlight是一项允许动态内容(dynamic content)的浏览器插件(plug-in)技术。第一版Silverlight仅仅支持通过Javascript编写,第二版包括了.NET Framework的一个子集。显而易见的是,服务器端(server-side)的类库对于Silverlight来说是不必要的,因为它只需要在客户端(Client)运行,因此Silverlight的安装包从核心特性里移除了不必要的类库和方法,使得它足够轻量也便于移植。最新的Silverlight桌面版是在2011年12月发布的。Silverlight可以用到Windows Phone编程上,如Silverlight 8.1和Windows Phone 8.1配套使用,但要小心的是,Silverlight移动版和Silverlight桌面版是有差异的。

在Windows桌面应用开发方面,越来越快的开发节奏使得对庞大的Framework做出优化势在必行。有个新的词叫DevOps,指的是开发人员和运维人员协同工作,又或者同一个人兼顾开发和运维,同样需要快速迭代(have new features available in a fast way)。在一个庞大的Framework里创建新特性或者修复bug可不是一项简单的任务。

因为存在着不少精简的.NET版本(如Silverlight,Silverlight for Win Phone),.NET桌面版和精简版之间的公共代码(share code)维护就变得很重要。一项用于在不同.NET版本之间共享代码的技术是可移植类库(the portable class library,简称PCL)。随着时间的增长和越来越多不同版本.NET Framework的发布,PCL的管理越来越复杂,逐渐成为了一个噩梦。

为了解决这些问题,我们需要一个新的.NET设计方案。新版的Framework被命名为.NET Core。比起原来的.NET Framework,新生的.NET Core更加小巧,基于模块化的NuGet包,为不同应用分发不同的运行时(has a runtime that's distributed with every application),开源,且跨平台。

为了创建新的Web应用程序,ASP.NET Core 1.0重写了ASP.NET。它并不能直接向后兼容老版本的ASP.NET MVC,你需要按照ASP.NET Core MVC做一些修改。虽然这会增加你的工作量,但ASP.NET Core还是有很多优点的,比如更低的网络延迟(overhead with every network request),这有利于提升用户体验,而且它可以直接跑在Linux上。ASP.NET Core不包含ASP.NET Web Forms,因为Web Forms最初设计的初衷就不是最好的实现(not designed for best performance),它仅仅只是为了Winform程序员能用Winform的方式简单地进行Web开发。

当然,不是所有的应用程序都能简单的迁移到.NET Core上。这也是为什么庞大的Framework仍在持续更新的原因,即使那些更新完全无法跟.NET Core的速度相比(not completed at as fast a pace as .NET Core)。ASP.NET Web Forms在所有版本的.NET中依然可用(available on the full .NET stack)。

1.2.8 C# 7 和.NET Core 2.0

为了更快更高效,C# 7.0正式版于2017年3月发布,并且其次级版本7.1和7.2很快就在同年8月和9月进行发布。通过项目配置,你可以选择你想要的编译版本。

C# 7.0同样提供了很多新特性,最关键的特性是函数式编程:模式匹配(pattern matching)和元组(tuples)。

.NET Core 2.0主要关注于如何更好地将现有的.NET Framework程序向.NET Core迁移。之前1.0版本无法支持的一些.NET Framework类型在2.0版本也得到了很好的支持。.NET Core 2.0新增了超过20000个API。举个例子,二进制序列化,还有Dataset也回归了,而且你还可以将这些特性应用到Linux上。另外一个有助于将历史应用(legacy applications)迁移到.NET Core上的特性是Windows兼容包(Windows Compatibility Pack,Microsoft.Windows.Compatibility)。这个NuGet包定义了很多API,如WCF,注册表访问,加密,目录服务,绘制等等。

.NET Standard 是一套正式的 .NET API 规范,使开发人员能够通过同一组 API 生成可在各种 .NET 实现中使用的可移植库。

.NET Standard

各种 .NET 实现以特定版本的 .NET Standard 为目标。 每个 .NET 实现版本都会公布它所支持的最高 .NET Standard 版本,这种声明意味着它也支持以前的版本。 例如,.NET Framework 4.6 实现 .NET Standard 1.3。也就是说,它会实现在 .NET Standard 版本 1.0 到 1.3 中定义的所有 API。 同样,.NET Framework 4.6.1 实现 .NET Standard 1.4,而 .NET Core 1.0 则实现 .NET Standard 1.6。

你可以在Visual Studio中下载一个扩展程序.NET Portability Analyzer,它可以用于检测你的应用程序,告诉你如何将你的程序迁移到.NET Core。你可以配置你需要迁移的目标平台,例如你要使用的.NET Core,.NET Framework,.NET Standard,Mono,Silverlight,Windows,Xamarin等等,生成的结果可以选择JSON、HTML或者Excel格式,具体的配置如下图所示。

.NET Portability Analyzer

1.2.9 选择技术,继续前行

当你了解了Framework中留存着各种各样的技术的理由之后,你就能更好的选择应用程序需要的开发技术。举个例子,如果你想要创建Windows桌面应用,Windows Forms就不再是那么理想的选择,你最好使用基于XAML的技术,如UWP。当然选择某项技术的原因不止于此,譬如你想让你的程序能在Win7下跑,那么你就用不了UWP,只能用WPF。但你可以在创建你的WPF应用的时候,考虑到它会切换到UWP或者Xamarin的扩展性。

当你想创建Web应用时,最安全的方案当然时选择最新的ASP.NET Core和ASP.NET Core MVC,尽量不要使用ASP.NET Web Forms。想访问数据库的时候,最好使用Entity Framework Core,用新的MEF(Managed Extensibility Framework)代替旧的System.AddIn。

许多业务系统还用着原有的Windows Forms或者ASP.NET Web Forms又抑或是其他一些老的技术。你并不是非得将他们迁移到新平台上,只需要用新技术开发新的应用即可。必须有充足的理由——例如,代码臃肿使得维护成为一场噩梦、又或者用户需要你快速发布你的新版本、抑或是使用新技术能提高你的编码效率,才有必要将它们重构成新的技术架构。一刀切地将它们迁移到新的技术架构未必是有价值的,旧有的Windows Forms和ASP.NET Web Forms依然会支持许多年。

本书主要是基于最新的技术,介绍创建各类应用当下使用哪种技术方案是最优的。假如你需要维护旧的业务系统,你可以查阅《C#高级编程》的过往版本,里面详细介绍了ASP.NET WebForms,WCF,WinForms,System.AddIn,Workflow Foundation和其他的一些遗留技术。所有的这些历史技术在.NET Framework里依然提供支持。

1.3 .NET 术语

下图展示了.NET技术架构包含的内容:

整体

所有的.NET Framework,.NET Core和Mono的项目可以使用同一套基于.NET Standard标准的类库,因为这些技术的底层其实是一样的编译平台,编程语言和运行时构件。他们没有共享一套完全一致的运行时,但他们共同使用运行时的基础构件。举个例子,.NET Framework和.NET Core就共用一个实时(Just-In-Time)编译器,名字叫RyuJIT。

使用.NET Framework,你可以构建Windows Forms,WPF和传统ASP.NET应用,运行在Windows系统上。

而使用.NET Core,你可以创建跨平台的ASP.NET Core和控制台应用。.NET Core还可以在UWP里使用,但是Linux没有UWP。因为UWP主要使用了Windows Runtime技术,这项技术只在Windows系的操作系统有效。

Xamarin提供了Xamarin.IOS和Xamarin.Android以及相关类库,使得你可以用C#为IPhone和Android手机开发APP。通过Xamarin.Forms,你可以在两个移动平台间共享用户界面(user interface)。Xamarin现在依旧基于Mono Framework,一款.NET技术的变体。在某些点上,它甚至可以迁移到.NET Core上。

然而以上这些并不是最重要的,最重要的是这些技术都使用同样的基于.NET Standard规范的一套类库。

在上图的最下一层,你可以看到除了.NET Standard规定的类库外,.NET Framework,.NET Core和Mono的底层共享了部分基础构件。如运行时构件(runtime components),像GC和RyuJIT(新的编译器)。GC包含在CLR,CoreCLR和.NET Native中,而RyuJIT则在CLR和CoreCLR里使用。新的.NET编译平台(Roslyn)和编程语言则被所有的这些平台使用。

1.3.1 .NET Framework

本文写作的时候,.NET Framwork已经更新到了4.8版本,在过去的17年的时间里,它一直在持续优化和加强。在《C#高级编程》过往版本的书籍里讨论了许多曾经用过的技术。这个框架主要是用来创建Windows Forms和WPF应用程序。.NET Framework仍然提供Windows Forms的增强功能,如高分辨率(High DPI)。

就算你想接着使用ASP.NET Web Forms技术,最新的.NET Framework框架也完全支持,如果你需要将它们迁移到.NET Core上的话,你需要重写某些代码。是否重写取决于曾经的代码质量以及你想要添加的C#新特性。

1.3.2 .NET Core

.NET Core是一项全新的.NET技术,本书主要关注点在此。这个框架是开源的,你可以在 https://github.com/dotnet 上找到它的源代码。它的运行时在CoreCLR Repository下,这个框架包含了集合类,文件系统访问,控制台,XML等等,更多的内容在CoreFX Repository下。

跟.NET Framework不同的是,你的应用程序需要的特定框架版本,你需要独立安装到系统中,比如你用的.NET Core 1.0框架,发布你的应用的时候,你还需要同时提供.NET Core 1.0的运行时。以前你部署多个ASP.NET程序到一台服务器上的时候可能会有诸多问题,但是不用担心,这些已经过去了,现在你可以将运行时打包到你的应用程序里一起发布,这样你就再也不用担心服务器上安装的究竟是哪个版本的框架了。

.NET Core的设计初衷是模块化访问(modular approach),这个框架被分解成一系列的NuGet包,因此你不需要处理所有的包。功能包集(Metapackages)将功能相近的包集合起来,你可以只引用你需要的功能包集。功能包集也跟着升级到了.NET Core 2.0和ASP.NET Core 2.0。使用ASP.NET Core 2.0,你只需要引用Micorsoft.AspNetCore.All就可以使用所有创建ASP.NET Core Web应用所需的关键包。

.NET Core可以快速迭代,现在更新它的运行时不会影响任何在跑的业务程序,因为运行时打包在应用程序里了。现在Microsoft可以更快的发布新的.NET Core,包括它的运行时。

1.3.3 .NET Standard

.NET Standard并不是一种技术,只是一个规范。这套规范指定了那些必须实现的API,而.NET Framework,.NET Core和Xamarin则遵守这套规范进行实现。

.NET Standard有不少版本,每个版本都会新增一些API。根据你需要的API,你可以选择一套标准构建你的支持类库。你必须检查你所选的平台是否能满足你需要的Standard版本。

你可以在https://docs.microsoft.com/en-us/dotnet/standard/net-standard上找到各种平台能支持的Standard版本。下面是一些你需要先知道的比较重要的部分:

  • .NET Core 1.0支持.NET Standard 1.6;.NET Core 2.0支持.NET Standard 2.0;.NET Core 3.0支持.NET Standard 2.1。
  • .NET Framework 4.6.1支持.NET Standard 2.0。
  • UWP build 16299支持.NET Standard 2.0;更旧的版本只支持.NET Standard 1.4。
  • 想要让你的Xamarin支持.NET Standard 2.0你需要Xamarin.IOS 10.14和Xamarin.Android 8.0以上版本。

1.3.4 NuGet 包

早些时候,程序集(assemblies)会不断的在不同的应用程序里复用(reusable)。当你需要从你自己写的代码那引用一些Public类型的时候,你需要在引用的位置添加程序集和命名空间的引用。使用类库也意味着你需要更改一些配置项,修改一些脚本,这样才能用上新功能特性。这也是使用NuGet包来管理程序集的其中一个原因。

NuGet包是一个ZIP文件,里面包含了必要的程序集,还包括配置信息以及需要运行的PowerShell脚本。

另外一个使用NuGet包的理由是你可以很方便的获取它,不单只Microsoft还有很多第三方的社区也提供NuGet包。通常你可以从NuGet的服务器上获取他们,访问地址是:http://www.nuget.org/

在Visual Studio的项目引用里,你可以打开NuGet包管理工具,你可以联网查找需要的Package并添加到你的应用程序里。在管理工具里你甚至可以找到那些尚未正式发布到NuGet服务器上的包(通常是预览版prerelease)。你可以在已安装页里看到项目使用了哪些NuGet包。

1.3.5 命名空间

.NET里的类是以命名空间(namespaces)的方式进行组织的,通常是以System开头。

不过新发布的.NET类的命名空间不再以System开头,而是用Microsoft。像Entity Framework Core的命名空间就是Microsoft.EntityFrameworkCore,新的依赖注入框架的命名空间则是Microsoft.Extensions.DependencyInjection.

1.3.6 公共语言运行时CLR

UWP使用的是.NET NATIVE框架,通过AOT(Ahead of Time)编译器,直接将IL编译成机器代码(native code)。这种方式与Xamarin.IOS很像。在其他的应用场景中,还有用到.NET Framework的和.NET Core开发的应用程序。为了满足不同应用场景的需要,CLR(Common Language Runtime)应运而生。然而.NET Core用的运行时叫CoreCLR,而.NET Framework用的叫CLR。所以,CLR究竟能干啥?

在你的应用程序可以被CLR执行之前,你编写的代码(可能用C#或者其他语言书写的)需要先编译一次。整个.NET的编译过程分两步:

  • 先将C#之类的源代码编译成MSIL(Microsoft Intermediate Language);
  • 然后通过CLR将MSIL编译成指定平台的机器代码。

IL代码可以包含在.NET程序集中。在执行的时候,CLR的JIT编译器会实时编译IL代码并转换成特定平台的机器代码。

新的CLR和CoreCLR集成了一个新的JIT编译器,叫做RyuJIT。它不仅比以前的编译器要快的多,而且对VS调试过程中的ENC(Edit & Continue)功能提供了更好的支持。ENC功能允许你在调试的时候随时修改局部代码,并继续进行调试,不需要重新启动调试过程。

运行时还包括一套类型系统(type system),通过Type loader从程序集里加载各种类型。类型系统的安全体系(Security infrastructure)负责验证哪些可信类型是允许的——例如,继承。

创建完类型实例后,这些实例在不被引用的时候同样需要被销毁以便腾出足够的内存供系统循环使用。运行时里有垃圾回收机制(Garbage Collector)。GC负责清理托管堆上那些不再引用的内存。

运行时还负责管理线程。用C#创建线程并不需要通过后台操作系统,而是通过CLR托管,虚拟出若干线程,就好像它们真实存在操作系统中。

1.3.7 Windows Runtime

Windows 8开始,操作系统提供了另外一套类库:Windows Runtime。这套运行库主要由UWP使用的,而Win 8系统提供的是1.0版本,后续的Win 8.1提供了2.0版本,Win 10提供的是3.0版本。

跟.NET Framework不一样的是,这套运行库是通过原生代码(native code)创建的。当它用于.NET Apps的时候,包含的类型和方法跟.NET很类似。通过语言投射(Language Projection)的帮助,Windows Runtime可以用Javascript、C++,也可用.NET语言进行开发,而且看起来就跟原生开发环境一样(like it's native to programming environment)。大小写不同的方法名,表现也不一样;同样的方法和类型可能有不同的命名空间,取决于他们用在哪。

Windows Runtime同样提供了一系列由命名空间组织的对象。如下表所示,他们和.NET提供的类并没有什么实质上的区别,只不过,Windows Runtime的类型提供了一些额外的功能以便用它开发的Apps可以在UWP上运行。

命名空间 描述
Windows.ApplicationModel 定义了App的声明周期以及不同App之间的交互。
Windows.Data 定义了基础数据类型如Text,JSON,PDF和XML数据如何工作。
Windows.Devices GPI,智能卡,打印机,扫描仪等等外接设备的使用。
... 等等

1.4 用.NET Core CLI 编译

本书的大部分章节可能都不需要用到Visual Studio,你只需要任意一个文本编辑器和命令行。为了创建和编译你的应用程序,你可以直接使用CLI(the .NET Core Command Line Interface)。下面我们介绍它的安装与使用。

1.4.1 设置环境

假如你安装了最新发布的VS2017,你可以直接启动CLI工具。就像前面提到的,你可以直接启动CLI不需要通过VS2017。大部分的例子也可以在Linux和OS X系统上运行。想下载这些应用,你可以访问https://dot.net,然后点击开始(Get Started)按钮。从这里开始,你可以下载.NET SDK。

如果你是Windows系统用户,你会下载一个可执行的安装包,直接运行即可安装SDK。如果你是Linux用户,根据你使用的Linux版本的不同,你可能需要:

  • Ret Hat和CentOS用户,可以通过yum命令安装。
  • Ubuntu和Debian用户,可以用apt-get命令。
  • Fedora用户,使用dnf install。
  • SLES/openSUSE,使用zipper install。
  • mac系统用户,则下载一个.pkg类型的文件即可。

Windows系统下,不同版本的.NET Core运行时和NuGet包都保存在指定的文件夹(User Profile)下。当你使用.NET进行开发的时候,这个文件夹的内容会慢慢增加。不管你开发多少个项目,NuGet包都不会单独存在对应的项目中,而是统一保存在这个特定的文件夹里。这种设计的好处是你不为N个项目下载同一个NuGet包N次,而且NuGet包管理器会隔段时间清理掉你不再使用的NuGet包。

安装完.NET Core CLI工具后,你可以通过以下命令查看有多少可用功能:

dotnet --help 或者
dotnet -h

1.4.2 创建应用程序

.NET工具提供了一个非常简单的方式创建一个"Hello world!"应用程序。只需要输入以下命令行:

dotnet new console --output HelloWorld

这个命令会创建一个新的HelloWorld的目录,添加Program.cs文件和它的源代码,并且生成项目文件HelloWorld.csproj。从.NET Core 2.0开始,这条命令的后续你可以执行dotnet restore命令,然后下载所有NuGet包。你可以在obj目录下找到project.assets.json文件,在文件中你可以看到应用程序的依赖关系和所需的类库版本。如果创建命令中不包含--output或者-o参数,则不会创建新的目录,代码文件和项目文件将会被生成在命令执行的目录中。

Program.cs的内容如下所示:

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

这是.NET Core CLI自动生成的代码,让我们进一步看看它的语法。Main方法是.NET应用程序的入口点(entry point),CLR总是从static Main方法开始执行。Main方法需要放在一个class里。在这里的class名为Program,事实上可以是任意class,名字并没有限定。

Console.WriteLine语句调用了Console类里面的WriteLine方法,你可以在System命名空间下找到Console类,你不需要每次都写上System.Console.WriteLine,因为在代码文件开头的时候我们用using引用了System命名空间。

完成代码编写后,你需要编译它然后才能执行。

自动生成的项目文件名为:HelloWorld.cspj,跟以前的项目文件相比,新的项目文件减少了部分项,精简成如下的形式:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
	<OutputType>Exe</OutputType>
	<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
</Project>

在这个项目文件中,OutputType定义了项目输出类型,控制台程序输出的是Exe文件。TargetFramework指定了项目依赖的框架和要生成的版本,在这里我们生成的是.NET Core 2.0应用程序。你可以修改这个元素值,并且你可以通过TargetFrameworks定义多个生成平台,如下所示:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
	<OutputType>Exe</OutputType>
	<!--注意是TargetFrameworks,复数-->
	<TargetFrameworks>netcoreapp2.0;net47</TargetFrameworks>
</PropertyGroup>
</Project>

这样编译器就会为你分别创建适用于.NET Core 2.0和.NET Framework 4.7的应用程序。

Sdk属性指定了这个项目使用的SDK包,Microsoft主要发布了两个SDK,Microsoft.NET.Sdk供控制台应用使用,而Microsoft.NET.Sdk.Web则用于ASP.NET Core创建的Web应用。

将源文件添加到项目视图里并不是必须的操作,项目根目录与其子目录下所有的带有.cs扩展名的文件都会在编译的时候自动引用并编译。带.resx扩展名的资源文件则会以嵌入资源的形式自动引用。因此你可以按照个人需要将代码文件和资源文件"从项目中排除/包括到项目"中。

同样的你不需要手动添加.NET Core包的引用,当你指定了target framework为netcoreapp2.0的时候,由元数据包Microsoft.NetCore.App定义的一系列数据包会自动添加到项目引用中。

1.4.3 构建应用程序

想用CLI生成项目,你需要更改命令行的目录,进入到项目文件所在的目录中,然后你就可以用dotnet build命令生成,如果你按照上面小节修改了你的csproj文件的TargetFramework,你看到的生成信息可能会如下所示 :

用于 .NET Core 的 Microsoft (R) 生成引擎版本 16.4.0+e901037fe
版权所有(C) Microsoft Corporation。保留所有权利。

  c:UsersMonkeyHelloWorldHelloWorld.csproj 的还原在 313.81 ms 内完成。
  HelloWorld -> c:UsersMonkeyHelloWorldinDebug
etcoreapp2.0HelloWorld.dll
  HelloWorld -> c:UsersMonkeyHelloWorldinDebug
et47HelloWorld.exe

已成功生成。
    0 个警告
    0 个错误

已用时间 00:00:01.65

注意命令dotnet new和dotnet build现在包含了下载依赖的NuGet包操作。你也可以显式地使用dotnet restore命令显式地下载NuGet包。

编译后,你会发现包含IL代码的程序集保存在bin/debug/[netcoreapp2.0|net47]目录中,如果你有仔细查看目录下的内容的话,你会发现.NET Core生成的是DLL文件,而.NET Framework 4.7生成的是EXE文件。.NET Core生成的程序集依赖于System.Console程序集,但是Framework生成的EXE则是从mscorlib程序集中查找Console类。

如果你想发布你的程序,你需要指定--Configuration Release选项(可以缩写成-c Release):

dotnet build --configuration Release

后续章节的一些代码实例可能会用到C# 7.1或者C# 7.2的特性,然而默认的编译器版本是C# 7.0。为了能用上C#的最新版本特性,你需要手动指定你的项目文件,如下所示的配置项将使用最新的C#特性进行编译:

<PropertyGroup>
	<LangVersion>latest</LangVersion>
</PropertyGroup>

1.4.4 运行应用程序

想运行生成好的程序,你可以输入dotnet run指令:

dotnet run

注意指令的运行目录下需要有项目文件,否则就会提示:

找不到要运行的项目。请确保目录中存在项目,或使用 --project 传递项目路径。

但是当你的项目生成了多个目标框架时,直接运行会提示:

你的项目面向多个框架。请指定要使用“--framework”运行的框架。

因此对上面两小节生成好的项目,我们可以加上framework选项执行,你应该会看到类似的如下所示的信息:

dotnet run --framework netcoreapp2.0
Hello World!

在Windows系列系统中,你不需要使用dotnet run指令运行应用。你可以直接使用dotnet指令调用相应的DLL:

dotnet bin/debug/netcoreapp2.0/HelloWorld.dll

你可以生成可执行文件,但是可执行文件只能运行在指定平台上。打包和发布的具体过程我们会在后续章节进行介绍。

注意:

  • 你可能使用的是Windows系统,并且你已经从"Hello World!"的示例程序中了解到app在windows系统中是如何创建、编译和生成的。同样地,你可以使用.NET CLI Tools在Linux和OS X系统中执行相同的命令,它们的效果是一样的。
  • 本书的着重点在于Windows系统,因为VS2017提供了比其他系统更强大的开发平台。但是本书的大部分例子都是基于.NET Core的,因此你也可以在其他系统上运行这些例子。
  • 你也可以使用免费的Visual Studio Code在Linux和OS X上直接开发相同的代码,后续的小节会更详细的介绍这两款开发平台。

1.4.5 创建Web 应用程序

你同样可以使用CLI创建Web应用。当你直接输入dotnet new的时候,你将能看到指令的详细信息,如下图所示:

dotnet new指令

我们执行以下指令通过ASP.NET Core MVC创建一个ASP.NET Core Web应用:

dotnet new mvc -o WebApp

切换到WebApp目录下,我们生成并执行它:

dotnet build
dotnet run

你会看到如下的提示信息:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:UsersMonkeyWebApp

然后你就可以打开你的浏览器,访问https://localhost:5001查看生成的网页了,注意这里用到了https,浏览器会提示你这可能不是一个可信链接。

1.4.6 发布应用程序

使用CLI工具你可以创建NuGet包并且发布你要部署的应用程序。我们先来试试创建一个依赖框架(framework-dependent)的部署项,这样你发布的时候不需要那么多的文件。

让我们再次以前面创建的HelloWorld程序为例,你可以使用以下的指令创建需要发布的程序。使用-f选项指定你要发布的框架,使用-c选项指定生成的是Release版本:

dotnet publish -f netcoreapp2.0 -c Release

程序发布所需的文件将会生成到bin/Release/netcoreapp2.0/publish目录下(另外细心的人会发现,在其上级目录bin/Release/netcoreapp2.0下有相同的文件,并且多了一个叫HelloWorld.runtimeconfig.dev.json的文件)。需要注意的是使用这种发布方式,你仍然需要另外安装相关的运行时框架。你可以在这里下载运行时的安装包:https://dotnet.microsoft.com/download/

同一版本的.NET Framework可以支持多个版本的应用程序,举个例子,你安装.NET Framework 4.0再加上后续的更新包,这个4.0框架可以同时支持需要4.0,4.5,4.6甚至4.7框架的应用程序。但与.NET Framework不同的是,你用什么版本的.NET Core运行时编译的程序,你就需要安装什么版本的.NET Core,.NET Core 3.1框架支持不了需要.NET Core 2.0的应用程序。

注意:如果你的应用程序引用了框架以外的NuGet包,这些包必须在csproj文件里声明,你在发布的时候也需要将这些NuGet包打包到你的应用程序里一块发布。

1.4.7 独立部署

与需要在目标环境额外安装运行时的部署方式不同的是,我们可以将运行时打包到应用程序里一起发布。这种方式称之为独立部署。

根据运行平台的不同,程序所需要的运行时也是不一样的。因此,独立部署的时候,你需要指定应用程序运行的平台。在项目文件里通过指定RuntimeIndentifiers元素,可以指定应用程序将发布到哪些系统平台上。如下面的文件所示,这里指定程序将同时发布到Win10,MacOS和Ubuntu Linux系统上:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
	<!--重点-->
	<RuntimeIdentifiers>
		win10-x64;ubuntu-x64;osx.10.11-x64;
	</RuntimeIdentifiers>   
</PropertyGroup>
</Project>

注意:你可以从https://docs.microsoft.com/en-us/dotnet/core/rid-catalog获取不同版本操作系统对应的RID(RuntimeIndentifiers)。

你可以使用-r参数指定要为某个系统平台进行生成,如果缺省了该参数,因为我用的是windows系统,则默认为windows系统进行生成。

我们执行以下指令:

> dotnet publish -c Release -r win10-x64
> dotnet publish -c Release -r osx.10.11-x64
> dotnet publish -c Release -r ubuntu-x64

在bin/Release/netcoreapp2.0目录下,会生成指定目标系统的目录,因为我们执行了3遍命令,所以生成的是3个。在每个目录下都打包了一系列在该平台运行程序所需的DLL和另外一些文件,如ubuntu下的是.so文件,macOS下的是.dylib文件,它们其实是各自系统中的可执行文件,你可以在ubuntu和macOS下直接执行它们而不需要安装任何运行时。

经过测试,就算不在csproj文件里进行配置,CLI也可以通过命令行生成指定系统的部署包。后续会详细介绍部署的更多细节。

1.5 使用Visual Studio 2017

接下来,让我们使用VS2017代替命令行。在本小节中将会介绍Visual Studio最重要的部分以便你能开始上手它。更多详细的功能会在第18章介绍。

1.5.1 安装Visual Studio 2017

Visual Studio 2017提供了一个新的Installer安装程序以便你能更容易的安装你需要的产品。使用此安装程序,你可以选择你需要的开发环境,为了后续章节的案例,请安装上以下这些工作环境:

  • Universal Windows Platform development

  • .NET desktop development

  • ASP.NET and Web development

  • Azure development

  • Node.js development

  • Mobile development with .NET

  • .NET Core cross-platform development

1.5.2 创建项目

你可能会被Visual Studio拥有海量的选项和功能菜单吓到。但作为本书入门的第一章,我们只会用到里面最简单的功能,来创建一个简单的应用。大量的功能其实是为了兼容历史应用程序,包括其他.NET语言开发的。

打开VS,第一步你要做的是创建一个项目。选择菜单项:文件->新建->项目。你将会看到如下图所示的对话框,里面列举了所有你能创建的项目类型:

创建项目

作为本书的读者,你应该更关注的是C#项目的创建。在第一章的时候,你可以选择.NET Core分类里的Console App(.NET Core)。在它上方你可以看到.NET Framework的选项,但你不必感到困惑,这个选择并不会影响到.NET Core类型的项目。

在对话框的下方,你可以输入应用程序的名称(Name),选择项目保存的目录(Location),还可以输入解决方案的名称(Solution Name)。一个解决方案可能会包含多个项目。点击确定(OK)按钮,一个控制台App项目就创建完成了。

1.5.3 使用解决方案管理器

解决方案管理器

在解决方案管理器里,你可以看到解决方案,每个项目都是归属于某个解决方案的,你可以选择一个代码源文件,展开它,可以看到其所属的类和方法。你还可以在每个文件节点点击鼠标右键打开菜单,不同类型的节点的右键菜单都不相同。你可以注意到有一个"编辑项目文件"的菜单项,点击它或者双击项目"HelloWorld"节点,你都可以进入csproj文件的编辑界面,就跟你在前面CLI小节里看到的一样。

1.5.4 配置项目属性

你可以点击项目->右键菜单->属性,打开项目配置界面。这里你可以配置各种各样的项目属性,如程序名称,程序集命名空间,生成路径等等。VS2017默认使用的C#语言版本是C# 7.0,后续有些例子我们可能会使用到C#7.1或者更高的特性,你可以在"生成->高级"里选择合适的语言版本,这个修改会体现在csproj项目配置文件里。

注意:当你想修改项目属性的时候,你需要确认你在"应用程序->目标框架"里选择了正确的框架。如果你只修改了C#编译器的版本,它只影响调试环境。如果此时你选择了比较新的语言特性,而你的目标框架不支持的话,调试的时候没什么问题,但在发布版本的时候,就会失败。通常来说你会想支持所有的配置,请尽量选择"所有配置"项。

1.5.5 了解编辑器

VS编辑器是一款非常强大的编辑器。它提供了智能提示(IntelliSense),方便你在编写代码的过程中调用各种方法和属性,而且支持Tab自动补全。在你键入代码的时候,会实时编译并且用下划线标识出代码的语法错误。鼠标悬停在提示的代码上面会提示一小段具体的错误信息。

一项超实用的产品功能是代码片段(code snippets),它可以让你只需要敲几个字符就补全完整的代码。举个例子,你可以只敲入cw,然后摁两下Tab,编辑器就会自动给你置换成Console.WriteLine();VS内置了很多代码片段,你可以通过"工具->代码片段管理器"查看,选择Csharp语言,选择Visual C#组,你可以看见所有预定义的代码片段。

1.5.6 生成项目

你可以通过"生成->生成解决方案"来编译你的项目,假如出现Error,"错误列表"窗口会给出所有的错误(Errors)和警告(Warnings)信息。"输出"窗口有时候比"错误列表"窗口更加的可靠,因为"错误列表"可能会包含一些旧的缓存数据,所以你可能不太容易从大量的错误信息中定位到实际的bug所在。"输出"窗口通常会给出生成过程中使用的不同工具的具体信息。你可以通过"视图->输出"打开"输出"窗口。

Output

1.5.7 运行程序

想直接运行程序的话可以选择"调试->开始执行(不通过调试)"。这将会直接运行你的程序,直到你手动关闭它。你可以通过项目属性配置应用程序的参数和生成目录。

1.5.8 调试

如果你想调试你的程序,首先你需要点击编辑器左侧灰色竖条的区域先创建断点(breakpoints),然后你可以通过"调试->开始调试"启动你的调试过程。当代码执行到断点的时候就会停下,此时你可以选择单步执行(step into),单步跳过(step over)或者跳出函数体(step out of methods)。将鼠标悬停在变量上可以看到它此时的实际值。你也可以在监视窗口中添加各种变量,以便查看它们在运行过程中值的实际变化。你还可以在调试过程中随时修改变量值。

调试

以上介绍的部分就是VS里最主要的功能,第18章会更详细地介绍整个Visual Studio。

1.6 应用程序类型和技术

你可以使用C#来创建控制台应用,本书的第一章主要讲的是这块。但是对于很多业务系统来说,控制台程序都不是第一选择。你可以用C#创建由多种.NET技术配合使用的复杂应用。下面的几小节主要介绍你可以用C#编写的一些应用。

1.6.1 数据访问

在我们了解应用程序都有哪些类型之前,让我们先认识一下所有应用程序都需要的基础功能:数据访问。

文件和目录可以通过简单的API进行调用,然而,在某些场景,这些简单的API显得不那么灵活。使用Stream API操作流会使你的应用程序更加的灵活可用,因为它提供了更丰富的功能,如加密或者压缩。使用Stream会使读写数据变得更加容易。我们会在第22章详细介绍文件流。Stream还可以将对象序列化成XML或者JSON格式,我们将在扩展章节2-XML和JSON里介绍它。

想读写数据库的数据,你可以直接使用ADO.NET(25章介绍ADO.NET和事务),或者你可以通过抽象层,Entity Framework Core(26章介绍)。EF Core提供了一种实现实例对象和数据库之间的关系映射的技术。

EF Core 1.0进行了全新的设计,这点你从名字上就可以看出来。代码需要重新改写才可以从旧的EF迁移到新的EF Core 1.0上。旧的设计模型,例如数据库优先或者模型优先,已经被摒弃,因为代码优先是一种更好的选择。这次完全的重建使得新的EF不单只能支持关系型数据库,还能支持NoSQL。EF Core 2.0更是添加了很多新的特性,本书会一一介绍。

1.6.2 Windows 应用程序

如今创建Windows应用程序最好的选择应该是Universal Windows Platform,当然如果你要支持旧的操作系统,譬如Win7,你只能先用WPF。本书并不介绍WPF,你可以在《C#高级编程第10版 - Professional C# 6.0 and .NET Core 1.0》中找到WPF的详细介绍。

UWP和WPF相比,提供了一种更新(more modern)的XAML方式来创建用户界面。举个例子,数据绑定(data binding)可以在编译时就直接绑定数据(compiled binding variant),您可以在编译时得到直接发现错误,而不是像以前一样不显示。使用UWP开发的应用程序在实际客户机器上运行之前就已经被编译成机器代码了。而且微软还提供了一套配套的设计方案,叫流畅设计体系(Fluent Design)。

注意:第33章"Windows Apps"将详细地介绍XAML,XAML空间以及Apps的生命周期。你可以用WPF,UWP或者Xamarin进行开发,通过使用MVVM架构,它们可以共享很多公有代码。第34章"Patterns with XAML Apps"将会详细介绍MVVM。想创建更酷更炫的App外观,可以翻阅第35章"Styling Windows Apps"。而36章"高级Windows Apps"则深入介绍UWP的高级特性。

1.6.3 Xamarin

如果Windows也能在移动手机应用市场中参上一脚的话,想必对Microsoft来说也是极好的。因此通用的Windows Apps需要也能运行在手机上。然而理想很美满,现实很骨感,使用Windows的智能手机几乎是过去式了。然而,通过Xamarin技术,你可以使用C#和XAML创建IOS和Android应用。是的你没看错,就是你熟悉的C#,Xamarin给你提供了相应的API,来创建Android和IOS应用。

为了能让你开发的应用能在Android上跑,在.NET和Android的Java运行时之间,有一个映射层,包括ACW(Android Callable Wrappers)和MCW(Managed Callable Wrappers)。而想在IOS上跑,则通过预编译器(AOT Compiler)直接将.NET托管代码编译成IOS原生代码(native code)。

Xamarin.Forms提供了创建用户界面的XAML代码并尽可能地使得它们能同时运行在Android,IOS,Windows和Linux系统上。XAML只是提供了适配全平台的UI控件。如果你想使用某个平台独有的控件,你可以创建一个特定平台的渲染器(platform-specific renderers)。

1.6.4 Web 应用程序

最早的ASP.NET发布的时候完全颠覆了传统的Web开发模型,ASP.NET Core又大改了一次。ASP.NET Core开发的Web应用拥有更优异的表现和可扩展性,同时,支持跨平台。

ASP.NET Web Forms不再包含在ASP.NET Core中,虽然它还可以在.NET Framework中应用。

ASP.NET Core MVC基于我们熟知的Model-View-Controller(MVC)模式,并且更容易编写单元测试。它有着明确的前后端分离,你可以用HTML,CSS和Javascript编写用户界面,用C#编写后端服务。

1.6.5 Web API

曾经的SOAP和WCF很好的完成了他们的使命,现在他们不再是必须的了。最新的Apps使用的是RESTful(Representational State Transfer)的思想和新的Web API。使用ASP.NET Core创建Web API更加地容易进行数据交互并且它完全满足超过90%的分布式应用需求。这项技术基于REST,它定义了如何创建无状态和可伸缩的Web Services,提供了最佳的体验。

客户端可以获取JSON或者XML格式的数据。JSON和XML可以使用OData(Open Data specification)进行格式化。

这些新的API特性使得从不同平台的Web客户端传输过来的数据更好解析处理(easy to consume from web clients)。

创建新的Web API是实现微服务(microservices)的一种好方式。这种方式创建的微服务足够小并且可以独立部署,自己处理数据存储。

为了更准确地定义这些服务,我们遵循OpenAI的制定的新标准(https://www.openapis.org/)。这项标准可以通过Swagger工具更好地实现(This standard has its roots with Swagger.)。

1.6.6 WebHooks 和SignalR

为了在服务器和客户端之间实现实时的Web响应(Web functionality)和双向交互,ASP.NET Core提供了两项新技术,WebHooks和SignalR,在.NET Core 2.1框架里可用。

SignalR允许当信息可用时就推送信息到客户端,它使用的是WebSocket的技术推送的信息。

WebHooks允许你整合到公共服务上(public services),并且这些服务可以被用ASP.NET Core创建的Web API服务调用。WebHooks是一项接收推送通知的技术,例如从Github,Dropbox或者其他的服务提供商那接收通知。

1.6.7 Microsoft Azure

现在你在考虑研发图(development picture)的时候再也不能忽略云(cloud)的存在。虽然本书中没有明确的章节介绍云技术,Microsoft Azure依然会在本书的某些章节中有所提及。

Microsoft Azure提供了SaaS,IaaS,PaaS和FaaS,以及一些介于这些服务之间的服务。下面让我们简要的介绍一下:

1.6.7.1 Software as a Service

SaaS提供完整版的软件,你不需要考虑服务器,更新包以及其他一切相关的管理。Office365就是一款SaaS类型的产品(Offerings),可以通过云使用E-mail和其他服务。SaaS产品里跟开发人员相关的是Visual Studio Team Services。Visual Studio Team Services是运行在云上的TFS(Team Foudation Server),它可以创建私有的代码仓库,跟踪bugs和工作项,也提供生成和测试服务。第18章我们会介绍Visual Studio可以使用的DevOps特性。

1.6.7.2 Infrastructure as a Service

另外一种服务提供方式是IaaS。虚拟机就是这种类型的具体体现。你需要自己管理操作系统和管理更新。当你创建了虚拟机,你可以决定要使用哪种级别的硬件(例如128核的CPU)。在本书写作的时候,128核,2TB内存和4TB的SSD属于"M系列"虚拟机。

你可以选择预装Windows,Windows Server或者Linux操作系统,并预装配套的软件,如SQLServer,BizTalk Server,SharePoint,Oracle等等。

我使用虚拟机是因为我经常只需要一周用几个小时,而虚拟机是按时间计费的。假如你想尝试在Linux系统上编译和运行.NET Core程序而你又没有一台Linux主机,在Azure上创建一个Linux虚拟机是一件很轻松的事情。

1.6.7.3 Platform as a Service

对开发人员来说,Azure跟我们最密切相关的部分应该是PaaS。你可以访问数据存储和读取服务,使用App Services的计算能力和网络性能,在应用程序里集成一些开发者服务。

为了在云上存储数据,你可以使用关系型数据存储的SQL Database。SQL Database几乎与本地(on-premise)版本的SQL Server完全一致。也有一些NoSQL的解决方案,如CosmosDB,可以提供不同的存储选项,像存储JSON数据,关系(relationships),或者表存储,而且Azure还可以直接存储blobs类型的数据(如图片和视频)。

App Services可以用来做你创建的ASP.NET Core应用和WebAPI的宿主。

Microsoft Azure同样提供了不少开发者服务,其中之一就是Visual Studio Team Services。Visual Studio Team Services允许你管理源代码,自动生成,测试和持续部署(deployments-continous integration,CI)。

开发者服务还包括Application Insights。随着发布版本的速度越来越快,了解用户究竟在使用App的过程中做了什么操作开始变得越来越重要。哪些菜单从来没被用过(因为用户完全找不到他们)?用户按照一个怎么样的路径来使用App以便完成他们的任务?使用AI,你可以获取很多有用的匿名用户数据,从中找出用户使用应用过程中存在的问题,而通过DevOps你可以快速完成修复。

你也可以使用认知服务(Cognitive Services),它提供了强大的图片处理功能。你使用Bing搜索的API,通过语音服务(language service)了解用户说了什么,以及其他许许多多的服务。

1.6.7.4 Functions as a Service

FaaS是一项云服务的新概念,也叫无服务器计算技术(Serverless computing tecknologies)。当然,最后也肯定要跑在某台服务器某台机器上。只是,你在使用Web App的时候,不用再像使用App Services那样为CPU和内存付费。取而代之的是,你仅仅需要为你耗费的资源付费——比如在特定存储空间和时间的限制下被访问了多少次。Azure Function提供了FaaS部署的方案。

注意:29章将会介绍如何使用Azure提供的Application Insights,而在32章,不仅仅提及ASP.NET Core MVC创建的Web API,也会介绍Azure Function能提供的服务功能,而在Bonus第4章,会介绍Microsoft Bot Service和Cognitive Services。

1.7 开发工具

在开始介绍C#的具体代码之前,本章的最后一小节,主要介绍开发工具和VS2017的各个版本。

1.7.1 Visual Studio Community

社区版是一个免费的开发版本,主要面向一些开源的项目,学院教学和小型的软件开发团队。跟Express版不同的是,此版本允许使用Visual Studio的扩展功能。

1.7.2 Visual Studio Professional

专业版拥有比社区版更多的功能,比如CodeLens和TFS源代码管理与团队开发。使用专业版你还可以订阅MSDN,获取微软开发和测试中的一些产品信息。

1.7.3 Visual Studio Enterprise

与专业版不同的是,企业版包含了大量的测试工具,如Web Load & Performance Testing,Unit Test Isolation with Microsoft Fakes, 以及Coded UI Testing(Unit Testing功能所有版本的VS都提供)。通过Code Clone你可以发现你解决方案里clone的代码。企业版还包括各种架构和建模工具,用来分析和验证解决方案的架构。注意通过VS授权(Subscription)你有权免费使用Azure,具体可用时间根据你的授权情况而定(contingent on the type of Visual Studio subscription)。

1.7.4 Visual Studio for Mac

VS for Mac源于Xamarin Studio,但现在它能提供更丰富的功能。这个编辑器和Visual Studio的很像,所以你能很快的熟悉它。使用VS for Mac你不仅可以创建Xamarin apps,你还可以创建ASP.NET Core Apps,它们都可以在三大操作系统上使用。本书的很多章节的例子,你可以用VS for Mac来练习。只有在涉及到UWP的那些章节用不了,因为它要求Windows系统的配合。

1.7.5 Visual Studio Code

VS Code则是一个完全不同的开发工具,而不是VS的某个版本。VS提供基于项目的各种功能,模板和工具,而VS Code只是一个普通的代码编辑器,仅仅提供少量的文件管理。但是,VS Code可以运行在Windows,Linux和macOS上。本书的大部分代码你也可以用VS Code进行编辑,但是VS Code处理不了UWP和Xamarin应用程序。你可以使用VS Code用于开发.NET Core控制台程序,或者ASP.NET Core 1.0 Web应用程序。你可以从https://code.visualstudio.com/上下载Visual Studio Code。

1.8 小结

这一章节介绍了大量的技术背景和新技术所做的更改。了解这些技术的发展历史有助于你的新方案选型以及决定如何维护现有的业务系统。

你了解了.NET Framework和.NET Core之间的差异,你也了解了如何用CLI创建执行一个HelloWorld应用程序。

你了解了公共语言运行时的各项功能并且了解了创建不同Windows应用和数据访问的技术。你也回顾了ASP.NET Core的优点。

第二章我们将深入讲解C#的语法,你将会学习变量,程序流的实现,如何通过命名空间组织你的代码,以及其他更多的知识。

扩展

.NET Framework和CLR

C#跟Java一样为了以后在不同的平台上运行,在操作系统上面在抽象出了一层,Java中叫虚拟机,C#中叫公共语言运行时(Common Language Runtime,简称CLR)。

C#编译出来的是微软通用中间语言(MSIL),它不能直接被机器识别,只能运行在CLR上。所以有时C#语言规范出了一些新特性,编译器要支持肯定得做些更新。

但CLR要更新不呢?这个看情况,如果那些新特性,编译器翻译过来后跟以前的东东一样,比如语言中多了一些语法糖,实际上原理还没变。那CLR不用更新就能支持。

但如果新特性编译器翻译过来更以前的东东不一样了,这时就得更新CLR去支持。


.NET Framework是以CLR为基础,支持多种语言(C#、VB.NET、C++、Python等)的开发编程平台。

公共语言运行时(CLR)和框架类库(Framework Class Library,简称FCL)是.Net Framework的两个主要组成部分。

.NET Framework

目前为止微软推出了3个版本的CLR,分别是 1.1, 2.0 , 4.0。其中CLR1.1支持C#1.0、C#1.1和C#1.2的特性,而CLR2.0支持C#2.0、C# 3.0特性,C# 4.0以后的特性就需要CLR 4.0支持。

我们平时说程序需要什么运行环境考虑的是需要什么版本的CLR支持,只是安装的时候我们装的是.NET Framework而已。需要特别注意的是.Net 4是基于CLR4的,而.Net 2.0/3.0/3.5都是基于CLR2.0,3.0/3.5其实只是在2.0的基础上增加了新的功能,并没有改变CLR。

注意SP(Service Pack)后缀,这类安装包支持往前版本的所有特性。如上图所示,.NET Framework 2.0 SP2支持面向版本1.0及其在版本 2.0之前开发的应用程序,安装.NET Framework 2.0 SP2就相当于支持了CLR 1.1和CLR 2.0。

当程序需要CLR2.0环境时,你就需要安装2.0、3.0或者3.5。 建议是安装3.5 SP1,因为这样就已经包含了2.0、3.0 的所有内容。如果还要支持CLR 4,则需要另外安装4.X。因为.NET Framework 4之后微软取消了分层的做法,后续不再推出.NET Framework SP,而是按需安装。

参考

原文地址:https://www.cnblogs.com/zenronphy/p/ProfessionalCSharp7Chapter1.html