Microsoft .NET 自 2002 年发行 v1.0 以来,已经过了近 14 个年头,在这 14 年里面,.NET 日渐成熟并成为 Microsoft 的重要开发平台之一,只要是在 Windows 平台上的相关应用,几乎都可以使用 .NET 以及所属的 C# 及 VB 语言来开发,虽然它一直没有真正的跨平台 (也可以说有,但只跨 Windows 生态圈的平台),不过 .NET 与 Visual Studio 的完美整合所产生的生产力,也是软件产业无法否认的强大,Visual Studio 号称地表最强开发工具是一点都不为过。
只是 .NET 的天生包袱终究使得它的可运用范围一直被局限于 Windows 生态圈,对另外一个生态圈 — Linux 与 Open Source 的生态圈而言,一直是微软与 .NET 无法跨过的高墙。直到了微软新任 CEO Satya Nadella 于 2013 年正式上任,并提出 Mobile First, Cloud First 的策略指导原则后,整个微软几乎动起来,试着想要推倒这一面高墙,而第一个产品就是 ASP.NET vNext,随后又宣布了 .NET Core 计划,作为整体策略的第一步。
跨越鸿沟的努力
大家都知道 Microsoft Azure 是微软重要的云端运算产品线,Azure 的开放特性使得 Windows 平台与 Linux 平台的环境都可以建置在 Azure 平台,然而受限于 Windows 的生态圈,微软总是在云端技术的发展中落后,因为云端技术的主流与先锋都是由 Linux 的生态圈发起,这种例子不胜枚举,像是 Docker 利用的是 Linux Container (LXC);Hadoop 是以 Java 开发并运行在 Linux 上;Apache Mesos 与 Spark 等管理与大数据分析平台也是在 Linux 上发展,相较之下,以 Windows 生态圈为主的微软阵营总是在后头追,移植受欢迎的软件平台或套件到 Windows,因此上市时间总比其他阵营晚,这点在 Azure 与 Amazon AWS 的服务竞争中就可见端晲。所以即使 C# 语言的发展速度比 Java 快了几个量级 (例如 C# 的 Lambda Expression 功能 Java 到 Java 8 才出现),但是发展却不如 Java。
因此 2014 年开始,微软终于跨出第一步,由 Satya Nadella 站上第一线向大家宣告 Microsoft Love Linux,自此开始,微软许多的技术与应用开始排山倒海的往 Windows 以外的平台推进,应用面就属 Office for iOS 与 Android 最广为人知,微软在 Windows 10 的发表会上也宣布数项计划,让 iOS 与 Android 的应用程序能直接跑在 Windows 10 平台等。
开发工具的部份则是以 Visual Studio Code 作为先锋,主力部队将由 .NET Core 与其上的 Web 开发平台 ASP.NET Core 担纲,以官方的角色将 .NET 推进到 Linux 与 Open Source 生态圈。即便是 Windows 平台上的 Visual Studio,微软也纳入了来自 Open Source 阵营的知名实作品,例如 bower、Gulp、Grunt、AngularJS 等,并加入了像 Docker Tools 这样的工具,让原本熟悉 Visual Studio 的开发人员能以最少的改变切入非 Windows 的环境。
但是,虽然微软做了很多努力,开发人员还是有些本质上的差异需要习惯,这是因为 Windows 的生态圈重视的是 GUI (图形化界面),但 Linux 生态圈大多数都是以 CLI (命令列界面) 为主,所以 .NET Core 与 ASP.NET Core 也将会着重在 CLI 上,只有在 Windows 上的 Visual Studio 还能保有多数的 GUI 界面,就连 Visual Studio Code 也偏重在 CLI。
.NET Core & ASP.NET Core
微软最早启动的跨平台的开发环境是 Project K,它是 ASP.NET Core 1 在专案初始时期的代号,在一开始的时候就提供了执行器 k.exe、版本管理工具 kvm.exe 以及套件封装与管理工具 kpm.exe,当时就很明显的要使用指令进行开发工作,它和原有的 .NET 执行环境也有很大的不同,它独立于 .NET Framework 的执行期之外,称为 KRE (K Runtime Environment),核心的载入器则称为 KLR (K Language Runtime)。
后来 Project K 被改名为 ASP.NET 5,其下的各个执行环境被改为 .NET 执行环境 (DotNet eXecution environment; DNX),此时作为跨平台核心的 .NET Core 也开始进行,其执行环境称为 Core CLR,不论是 ASP.NET 5 或是 .NET Core 都是具有跨出 Windows 平台能力的执行环境,就连 Windows 10 的 Universal Windows Platform 的 .NET 平台使用的也是 Core CLR,搭配为 Windows 开发的 .NET Native 编译器来强化执行效能。
.NET Core 是第一个由微软官方所开发,具有跨出 Windows 平台能力的开发平台,作为下一代 .NET 开发的基石,同时它会和现有的 .NET Framework 并行,在 Windows 上可同时存有这两种执行环境,而且 .NET Core 的程序可存取 .NET Framework 的类别库以保有相容性 (当然跨出 Windows 后就不行了),.NET Core 本身的类别库也重新设计,改为以套件散布方式提供,也就是说,以 .NET Core 开发的应用程序不再需要传统大包装的 Framework Runtime,只需要执行前下载 Core CLR,并且在执行程序前先行还原套件,就可以执行,而且套件的版本与各应用程序可各自独立,这可是一项重大的进步,以往或许写个小程序还要带大包 Framework 的景象未来将不再复见,同时套件化的管理也保有版本相容性,应用程序可视需要抓取所需的版本,而不用固定在一个大版。
.NET Core 在不同的平台也可以编译成原生码,前面提到 Windows 是使用 .NET Native 编译,Linux 与 Mac 则是使用 LLVM MSIL Compiler (LLILC) 进行编译,.NET Core 的建造工具还可产生 C++ 程序码,再使用 GCC 等编译器编译为原生码。
至于 Web 端的开发平台,则非 ASP.NET 5 莫属,但因为 ASP.NET 5 这个名称很容易让人误会它是 ASP.NET 4.x 的升级版,但其实它是完全重写的新版本,为了不让外界误解,微软决定将它再改一次名字,即现在的名字 ASP.NET Core。它最大的特色就是扬弃了 System.Web.dll 这个 .NET Framework 最大的组件,当然少了 System.Web.dll 也等于宣告 Web Form 不会被移植到 ASP.NET Core,同时微软也花了很多的心力将 System.Web.dll 内的类别进行重构与切割,分散到各个不同的组件,为 ASP.NET Core 的核心进行瘦身,以加快 ASP.NET Core 的执行效能。
当然,ASP.NET Core 和 .NET Core 一样,只需要取得或还原所相依的套件即可执行。而另一个重大的改变,是 ASP.NET Core 不再依赖 IIS,这也归功于 System.Web.dll 的重构,ASP.NET Core 的执行环境由新开发的 Kestrel Server 负责,IIS 退回到 HTTP 的聆听器的角色,微软也特别为了这个需求开发了 IIS Platform Handler,以处理 HTTP 与执行环境之间的讯息转送工作。ASP.NET Core 除了核心之外,它也带来了 MVC 6 这个强悍的开发框架,以及其週边的开发支援,如 ASP.NET Identity 3.0、SignalR 3.0 等新版本的开发框架。
取得开发环境
.NET Core 与 ASP.NET Core 在 RC1 的版本,其 CLI 命令列工具尚未合併,微软已经计划于 RC2 时将两个环境的命令列合併,不过在此之前,还是要各自取得。.NET Core 可以取自其官方网站dotnet.github.io/getting-started/,其工具只有一个:.NET CLI,执行档名称为 dotnet.exe,其下有相关参数可用,较常用的指令有:
ASP.NET Core 的指令则是由 .NET 执行环境提供,分为几个不同的指令:
exe: 执行 ASP.NET Core 程序。
exe: 管理 DNX 的版本,可安装或指定要执行的 DNX Runtime 的版本。
exe: 还原 ASP.NET Core 所需的套件,以及建造程序与封装部署等。
较常用的指令有:
ASP.NET Core 不像 .NET Core 有 .NET CLI 可初始化预设,若是用 Windows 开发,可使用 Visual Studio 产生专案,但若是使用 Mac 或是 Linux 开发时,则建议使用 Yeoman ASP.NET 5 Project Generator,它可以在目录下建立新的专案范本,再使用 Visual Studio Code 或是其他文字编辑工具编辑程序码,完成后使用命令列工具编译执行即可。
认识 project.json
不论是 ASP.NET Core 5 还是 .NET Core,其专案资料夹内都会包含一个 project.json 档案,它记录了这个专案所需要的相关设定,包含使用的 .NET Core/DNX 版本、其相依的套件资讯、特定平台的相依资讯、启动参数与指令、启动事件等,下列内容即是预设 ASP.NET Core 1 的 Web 应用程序专案的 project.json:
{
“userSecretsId": “…",
“version": “1.0.0-*",
“compilationOptions": { “emitEntryPoint": true },
“dependencies": { “EntityFramework.Commands": “7.0.0-rc1-final",
“EntityFramework.MicrosoftSqlServer": “7.0.0-rc1-final",
“Microsoft.AspNet.Authentication.Cookies": “1.0.0-rc1-final",
“Microsoft.AspNet.Diagnostics.Entity": “7.0.0-rc1-final",
“Microsoft.AspNet.Identity.EntityFramework": “3.0.0-rc1-final",
“Microsoft.AspNet.IISPlatformHandler": “1.0.0-rc1-final",
“Microsoft.AspNet.Mvc": “6.0.0-rc1-final",
“Microsoft.AspNet.Mvc.TagHelpers": “6.0.0-rc1-final",
“Microsoft.AspNet.Server.Kestrel": “1.0.0-rc1-final",
“Microsoft.AspNet.StaticFiles": “1.0.0-rc1-final",
“Microsoft.AspNet.Tooling.Razor": “1.0.0-rc1-final",
“Microsoft.Extensions.CodeGenerators.Mvc": “1.0.0-rc1-final",
“Microsoft.Extensions.Configuration.FileProviderExtensions" : “1.0.0-rc1-final",
“Microsoft.Extensions.Configuration.Json": “1.0.0-rc1-final",
“Microsoft.Extensions.Configuration.UserSecrets": “1.0.0-rc1-final",
“Microsoft.Extensions.Logging": “1.0.0-rc1-final",
“Microsoft.Extensions.Logging.Console": “1.0.0-rc1-final",
“Microsoft.Extensions.Logging.Debug": “1.0.0-rc1-final",
“Microsoft.VisualStudio.Web.BrowserLink.Loader": “14.0.0-rc1-final" },
“commands": { “web": “Microsoft.AspNet.Server.Kestrel",
“ef": “EntityFramework.Commands" },
“frameworks": { “dnx451″: { },
“dnxcore50″: { }
},
“exclude": [ “wwwroot", “node_modules" ],
“publishExclude": [ “**.user", “**.vspscc" ],
“scripts": { “prepublish": [ “npm install", “bower install", “gulp clean", “gulp min" ]
}
}
其中最重要的部份是 dependencies 区段,它定义了专案所相依的套件与其版本,在 Visual Studio 编辑时,Visual Studio 会自动扫瞄 NuGet 取得相似的套件名称与版本。
若是使用 Visual Studio Code,也是一样会出现提示:
当开发人员编修过 project.json 的 dependencies 时,Visual Studio 会主动呼叫 dnu restore 指令进行套件还原,此时就可以在 Visual Studio 的参考中看到套件的资讯。
由于 .NET Core 与 ASP.NET Core 可同时在 Windows 与非 Windows 的平台上执行,Windows 平台上是以 4.5.1 为基准,非 Windows 平台则是以 Core 5.0 为基准,若参考到了某一个平台不相容的套件,该套件上的图示会出现惊叹号,且编译时会无法通过,若确定要锁定在 Windows 上时,可将下方 frameworks 区段的 dnxcore50 移除,如此 dnu 就只会以 .NET 4.5.1 版本编译。
frameworks 区段还有另一个好处,是可以将特定平台的组件参考加进来,编译时 dnu 就会取用这些组件一起编译。
commands 区段则定义了传递给 dnx 时的指令参数,不同的指令参数包含了要启动的程序以及其必要参数。如下列,web 指令表示启动 Microsoft.AspNet.Server.Kestrel (Kestrel Server),而 ef 表示启动 EntityFramework.Commands 程序。
其他的 project.json 的区段,可参考 ASP.NET Core 团队写的 Project.json 结构参考:github.com/aspnet/Home/wiki/Project.json-file
前端资源管理
ASP.NET Core 的专案结构将后台资源与前台分开,前台的资源统一置于 wwwroot 资料夹下,应用程序若有什么静态的资源,可以放在这个资料夹内,部署时 dnu 会自动将这个资料夹内的资源配置到网站的根目录下 (但若要让 ASP.NET Core 应用程序能成功存取,还要加入 Microsoft.AspNet.StaticFiles 套件,稍后会提到)。
ASP.NET Core 也引入了前端套件管理服务 bower 与工作执行服务 Gulp/Grunt,在预设的 project.json 内就包含了发行前启动前端套件程序的指令:
在 Visual Studio 里面,针对 Gulp 与 Grunt 提供了工作执行器总管功能,可让开发人员看到工作执行器执行的状态;针对 bower.js 提供了相依套件管理,如同 NuGet 套件管理的操作模式,开发人员能轻鬆的管理前端的相依套件,预设的情况下, bower.js 下载的相依前端套件都会放在 wwwroot/lib 资料夹内。
后端功能管理
ASP.NET Core 的重大改变之一,就是开发人员必须使用程序码来定义功能 (Feature),以往是在 Web.config 以及 IIS 上设定启用或停用功能,在 ASP.NET Core 不再有 Web.config,也不再只能跑在 IIS 上,所以功能的启用要由程序码处理,只有程序码启用的功能才会启用,没有的就不会有作用,在 ASP.NET Core 专案范本内有个 Startup.cs,所有应用程序要启用或停用的功能都要在这里设定。以下的例子是预设专案范本的 Startup.cs 内容 (程序码有修剪过)。
public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole (Configuration.GetSection (“Logging")); loggerFactory.AddDebug (); if (env.IsDevelopment ())
{
app.UseBrowserLink ();
app.UseDeveloperExceptionPage ();
app.UseDatabaseErrorPage ();
} else {
app.UseExceptionHandler (“/Home/Error"); }
app.UseStaticFiles ();
app.UseIdentity ();
app.UseMvc (routes => {
routes.MapRoute (
name: “default", template: “{controller=Home}/{action=Index}/{id?}"); });
}
初次看到这段程序码可能容易觉得适应不良,其实关键是在于 ASP.NET Core 采用来 OWIN (Open Web Interface for .NET) 的架构设计,所有可挂于 ASP.NET Core 的功能组件都会实作一个对 IApplicationBuilder 界面的扩充方法,名称基本上都是以 Use 开头,像是要启用静态档案读取,就是使用 app.UseStaticFiles ();,这个方法定义在 Microsoft.AspNet.StaticFiles 套件内,你必须要加入这个套件的参考,才可以在 Visual Studio 看到这个方法,其他像 app.UseIdentity ();以及 app.UseMvc (); 都是类似的作法。只有用程序码加入 (启用) 的服务,才可以在程序中使用。
ASP.NET Core 本身也具备强大的 Dependency Injection 基础建设,因此开发人员也可以在应用程序中的服务集合中加入自己的服务,例如:
public void ConfigureServices (IServiceCollection services)
{ // Add framework services. services.AddEntityFramework ()
.AddSqlServer ()
.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer (Configuration[“Data:DefaultConnection"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders ();
services.AddMvc (); // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
同样的,ASP.NET Core 的功能模组也扩充了 IServiceCollection 界面的功能,以简化呼叫的语法与语意,例如 serivces.AddMvc (); 表示在服务中加入 MVC 的功能;services.AddIdentity (); 表示加入 ASP.NET Identity 的功能; services.AddEntityFramework (); 表示加入 Entity Framework 的功能等。
应用程序组态
Web.config 在 ASP.NET Core 中不再存在 (wwwroot 里面的 Web.config 是为了要注册 IIS Platform Handler),相关的应用程序设定都移到了 appsettings.json,同时也不再区分 appSettings 与 connectionStrings,例如:
{
“Data": { “DefaultConnection": { “ConnectionString": “…" }
},
“Logging": { “IncludeScopes": false, “LogLevel": { “Default": “Verbose",
“System": “Information",
“Microsoft": “Information" }
}
}
组态档也不是预设就能在程序中生效,一样要使用程序码将组态档加入,才可以在程序中使用。Microsoft.Extensions.Configuration 定义了 ASP.NET Core 与 .NET Core 的组态系统,并提供 JSON、INI、XML 等组态档格式的支援。
// Set up configuration sources. var builder = new ConfigurationBuilder ()
.AddJsonFile (“appsettings.json") .AddJsonFile ($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment ())
{
builder.AddUserSecrets ();
}
builder.AddEnvironmentVariables ();
Configuration = builder.Build ();
总结
.NET Core 与 ASP.NET Core,这两个主要的开发平台组成的 Core 家族,是微软进军非 Windows 生态圈的重要技术,它们都可以运行在 Linux 与 Mac,也可以包装到 Docker 成为容器,.NET Core 让 .NET 能被重新定义,而 ASP.NET Core 带来许多改变,从正式脱离 System.Web.dll 开始,用程序码定义功能、导入知名前端管理框架、不依赖 IIS 的环境等。.NET Core 与 ASP.NET Core 不但能适用于跨平台,也对运行在云端环境与实作微服务 (Microservices) 有着相当大的潜能。
改变是需要习惯的,所以身为微软阵营的开发人员,与其再继续观望,不妨就立刻开始习惯它吧,当你习惯了之后,你会发现在前面的道路是非常宽广的。
====================================分割线================================
文章转载自 开源中国社区[http://www.oschina.net]