2016 年 7 月

第 31 卷,第 7 期

核心 .NET - 具有 .NET Core 工具的 Visual Studio 2015

作者 Mark Michaelis

Mark Michaelis.NET Core RC2 现已推出,这是真正的“候选发布”而非 RC1 Beta 冒充的候选发布(如果是那样,请考虑发布后出现的所有更改)。当前,围绕 .NET Core 的开发焦点主要是跨平台功能。对于支持 Linux 和 Mac OS X 的专注不仅提供了新的 .NET API,还附带提供了运行时甚至工具集。DOTNET.EXE(先前为 DNX、DNVM 和 DNU)等工具,更不必说 Visual Studio Code,使所有非 Microsoft 开发者可以利用 .NET,甚至可以享受一流的开发者体验。

这绝对非常棒,但资深 Microsoft 开发者怎么办? 他们如何在 Windows 和 Visual Studio 上继续开发 .NET Core 项目? 在本文中,我将介绍各种 .NET Core 项目,并详细讲解新的文件类型及其功能。此外,我还会深入介绍新项目结构如何支持你可能引用的开源 NuGet 包的并行调试以及如何单步执行此类项目的源代码。

开始使用

可以开始利用 .NET Core RC2 之前,你需要更新工具 - 此案例中为 Visual Studio 2015 - 以支持新的平台。主要包括两个步骤:

  1. 下载适用于 Visual Studio 2015 的 .NET Core 工具预览版 1,下载地址:microsoft.com/net/core#windows(还可从中找到说明)。
  2. bit.ly/27Rmeaj 安装 Nuget 包管理器。

假定你已安装 Visual Studio 2015,但如果未安装,可从 visualstudio.com 免费获取 Visual Studio 社区版。

新的项目类型

安装所有 Visual Studio 工具后,即可使用“新建项目”向导创建项目(参见图 1)。

Visual Studio .NET Core 项目模板
图 1 Visual Studio .NET Core 项目模板

如你所见,有四类项目(当同时驻留在 Visual C#\Web 和 Visual C#\.NET Core 文件夹中时,项目会出现两次)。

显然,每个项目类型生成一组不同的文件,如图 2 所示。

图 2 每种 Visual Studio 项目类型中包含的文件

文件名 类库 控制台应用程序 ASP.NET Core Web 应用程序 (.NET Core) ASP.NET Core Web 应用程序 (.NET Framework)
app.config       X
Properties\AssemblyInfo.cs X X    
Class1.cs X      
Global.json X X X X
Properties\launchSettings.json     X X
Program.cs   X X X
Project.json X X X X
Project.lock.json X X X X
Project_Readme.html     X X
<Project>.xproj     X X
<Project>.xproj.user     X X
Startup.cs     X X
Web.config     X X

App.config 是一个可选配置文件,类似于传统的 <appname>.config,自 .NET Framework 1.0 起便开始使用。以下代码显示默认文件,用于标识是使用基于服务器的垃圾回收还是使用客户端/工作站类型的垃圾回收(参见 bit.ly/22nm32o 了解更多信息):

<configuration>
  <runtime>
    <gcServer enabled="true"/>
   </runtime>
</configuration>

AssemblyInfo.cs 标识程序集数据,如配置、公司、产品和商标。这是标准的 AssemblyInfo.cs 文件,自 2000 年首次发布 .NET 起便属于 Visual Studio .NET 项目的一部分。

Class1.cs 是 Class1 类的框架 C# 类文件,包括其默认构造函数。

创建首个 .NET Core 项目时,如果选择“创建解决方案的目录”,便会自动生成 Global.json。如本文稍后进行的详细介绍,项目的节点可在调试时标识源代码的其他位置。

LaunchSettings.json 标识各种 Web 托管配置设置,包括用于调试的应用程序 URL;任何存在的 IIS 主机(如 IIS Express);启动、使用前要设置的环境变量,如通过 .NET Core 配置标识环境(开发、测试或生产);SSL 和身份验证。对 Visual Studio 的项目属性窗口上“调试”选项卡所做的更改提供了 UI 以编辑 launchSettings.json 文件,如图 3 所示。

Visual Studio 的项目属性窗口上的“调试”选项卡
图 3 Visual Studio 的项目属性窗口上的“调试”选项卡

图 4 显示了一个示例 launchSettings.json 文件。

图 4 示例 launchSettings.json 文件

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:43799/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication1NetFramework": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Project.json 是一个新的项目文件,它的功能大部分与 *.*PROJ 文件重叠。它可标识项目引用、版本选项(如版本号)等事项,并可标识要编译的平台,例如,是 .NET Core 还是 .NET Framework。稍后将对此进行详细介绍。

Project.lock.json 存储编译所需文件的列表(通常为 NuGet 引用)。与 project.json 文件不同,它包括特定的包版本号,可支持通配符。如果没有 project.lock.json,将完整还原包。Project.lock.json 包括包图片以及本地下载的其他与包相关的数据(已还原)。通常,不会签入此文件,但此文件不存在时,将运行 NuGet 包还原以重新创建。此文件列为 Visual Studio 中 project.json 的子项。

ClassLibrary.xproj 是现成的 MSBuild 文件,定义构建项目时将发生的事项。最新版本可导入 Microsoft.DotNet.targets,它定义了利用新 DotNet.exe 命令的构建任务。与过去的 MSBuild proj 文件不同,xproj 文件非常小,因为大部分信息已(暂时)移到 project.json。

ClassLibrary.xproj.user 会覆盖 Class­Library.xproj 文件,并提供其他 MSBuild 属性,如本地用户调试特定设置(如端口)。通常,不会签入此文件,因为它特定于用户,且在 Visual Studio 中不可见。

Program.cs 定义项目类,包括定义应用程序(甚至包括 Web 应用程序)的主入口点。

Web.config 提供 IIS 的最低配置,指示在何处查找 Web 主机进程并配置所有通信将重定向到此进程,如以下代码所示:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule"
        resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%"    
      stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout"
      forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>

请注意,web.config 不再包含应用设置,此设置将移到通过 Microsoft.Extensions.Configuration 加载的配置文件,请参见我在 2016 年 2 月发布的文章“.NET Core 中的配置”(bit.ly/1OoqmkJ)。

请注意,对于通过 Visual Studio 创建的所有 .NET Core 项目类型,如果在创建新项目时选择“创建解决方案的目录”选项,所有源代码都会放置在解决方案的子目录中。此外,我们希望测试项目将放置在 src 旁边的测试目录中(尽管在适用于 Visual Studio 2015 版本的 .NET Core 工具预览版 1 中默认情况下不会执行此操作)。其他可以考虑的目录有版本和文档等。(我承认,我更喜欢将我的测试项目随要测试的目标项目一起放置,而不是放置在完全独立的树中,但是默认情况下 Microsoft 不会为解决方案结构选择此操作,根据经验,我们应尽可能使用默认设置,而非尝试与默认设置相对立。)

有关 Project.json 的更多信息

.NET Core 项目结构中最重要的文件可能是 project.json。此文件旨在:

  • 替换 NuGet 文件管理器 package.config 文件,它可标识项目的 NuGet 引用。
  • 指定项目支持的框架,以及有关如何为特定框架构建项目的配置详细信息。
  • 标识独立应用的目标平台,它含有其所有依赖项,包括对应平台所需的特定于平台的 .NET Core 运行时。或者,如果项目是可移植应用,project.json 可标识项目会在目标计算机(将在其上运行程序集)上安装的框架。

这三个任务分布在 project.json 中的四个主要部分(根据项目类型,我将运行时和支持合并为功能重叠):

依赖关系: 此部分列出了你的项目所依赖的各个 NuGet 包,包括所述依赖项的版本号。可以使用通配符指定版本号,从而你可以允许 NuGet 包管理器还原自动下载与通配符相匹配的“最新版本”。版本号的空引号对表示“使用最新可用项”。 此外,不仅可以通过 Visual Studio NuGet 包管理器窗口添加引用,还可以依赖于 Visual Studio 利用已配置包源中可用的包异步加载 IntelliSense 的方式(参见图 5)。IntelliSense 适用于包名称和版本号。

IntelliSense 动态加载可用包和版本列表
图 5 IntelliSense 动态加载可用包和版本列表

框架: 在此部分中,你可识别项目将运行的框架:如 net45、netstandard1.5、net40。此外,你可以提供版本选项、依赖项、框架程序集并将特定应用导入已标识的框架。例如,要允许将不安全代码用于 .NET 45 执行环境,可以在框架元素中进行指定:

"net45": {"buildOptions": {"allowUnsafe": true}}

运行时/支持:project.json 是使用运行时还是使用支持取决于项目是针对可移植应用还是独立应用。对于独立应用,运行时部分指定将支持的 OS,因此可指定要绑定到应用程序的运行时库。在目标计算机上预安装的任何项目上,独立应用程序没有依赖项(至少 .NET 如此)。

相反,支持部分为可移植应用标识启动时应用将查找的运行时依赖项 - 具有其中任何一个即足够。此列表不受限(你可以在任意位置运行),但 supports 元素将导致 NuGet 检查是否所有依赖项均满足。

project.json 在 RC1 和 RC2 中至关重要,但讽刺地是,RC2 发布不久之后,.NET Core 和 ASP.NET 团队确定 project.json 实际上对已良好建立的 MSBuild 项目文件而言是多余的,它已支持非常多的功能,包括配置、生成依赖项、生成目标、编译标记、命令行和环境变量属性设置以及构建命令。团队没有对其进行彻底改造,而是查看是什么首先触发了 project.json 文件生成,并意识到 *.*PROJ 文件通常非常大(如,在项目中单独列出了各个文件),而非使用通配模式(通配符)。实际上文件非常大,开发者很少在运行版本之前打开并查看此文件,即使此文件可能会将一些不需要的命令嵌入其中。团队没有创建全新的生成文件,而是决定修复 *.*PROJ 文件内的膨胀问题,并且甚至提供了命令行实用程序以对其进行编辑。project.json 有而 *.*PROJ 文件没有的唯一一项是 JSON 语法。(但是,毕竟 JSON 只是现代的 XML,如同 XML [在它的时代]也曾是现代的 flat 或 INI 文件一样。) 有关 project.json 潜在消亡的详细信息,请参阅:2016 年 5 月 10 日 Damian Edwards 在 ASP.NET Community Standup 中发布的公告、Alexandre Mutel (bit.ly/1NJ9r31) 发布的相应帖子以及 Willem Meints 在博客 (bit.ly/1sJc2An) 上发布的摘要。

调试包源代码

我最喜欢的一个功能是全新支持调试和单步执行包,甚至可以适时修改包的源代码。假设你有公司范围内的“框架”程序集,可在众多团队之间共享。但是,框架包实际上是开源的,因此公司内(或者,甚至更好,公司外部)的任何人员均可进行完善和更改。现在,想像你如果为此框架引用 NuGet 包,但有时怀疑可能存在需要修复的缺陷或可能存在一个批准的增强功能。通常,这需要独立于项目/解决方案处理组件中的源代码。相反,如果你能够下载源代码并随主开发将其更新为集成式体验 - 甚至单步执行代理,而不依赖于符号服务器或 PDB 文件是否可用,会怎么样? 幸运地是,Visual Studio 2015 支持此关键场景。

例如,想象你想要调试 GitHub 上可用的 Microsoft.Extensions.Logging 包。要在项目中对其进行添加和调试,你需要下载(可能使用 git clone 或 git submodule 命令)源代码。接下来,为了使 Visual Studio 知晓在何处查找源代码,你需要编辑 global.json 项目节点,如将“submodules\Logging”添加到查看的目录列表:

{
  "projects": [ "src", "test", "submodules\Logging" ],
  "sdk": {
    "version": "1.0.0-*"
  }
}

当然,你可以提供完整路径(例如,你未将代码克隆到子目录)。但是,请注意,目录分隔符是两个反斜杠 (\\) 或单个正斜线(如 c:/users/mark/documents/visual studio2015/Projects/Microsoft.Extensions.Logging)。

更新并保存 global.json 后,一旦 Visual Studio 成功找到源代码,它会自动将项目添加到你的解决方案,使你可以调试到源代码。

这里使用了一种非常天真的算法来确定要加载的源代码目录:

  1. 如果 global.json 中指定的任何源代码位置包含的文件夹具有与包相同的名称(如 Microsoft.Extensions.Logging),且此文件夹包含名为 project.json 的文件,调试程序将使用此文件夹及其内部的源文件。
  2. 否则,会加载包文件夹中编译的二进制程序。

有关详细信息,请参阅“使用 Visual Studio 2015 调试 ASP.NET 5 Framework 代码”(bit.ly/22niJ7w)。

总结

如果你尚未开始深入了解 .NET Core,现在是绝佳时机,你可以获取最长时间跨度以在其中分摊学习曲线。这对考虑升级早期版本的用户同样适用。机不可失,请尽早升级,越早升级,越可以尽早利用其新功能。


Mark Michaelis是 IntelliTect 的创始人,担任首席技术架构师和培训师。在近二十年的时间里,他一直是 Microsoft MVP,并且自 2007 年以来一直担任 Microsoft 区域总监。Michaelis 还是多个 Microsoft 软件设计评审团队(包括 C#、Microsoft Azure、SharePoint 和 Visual Studio ALM)的成员。他在开发者会议上发表了演讲,并撰写了大量书籍,包括最新的“必备 C# 6.0(第 5 版)”(itl.tc/EssentialCSharp)。可通过他的 Facebook facebook.com/Mark.Michaelis、博客 IntelliTect.com/Mark、Twitter @markmichaelis 或电子邮件 mark@IntelliTect.com 与他取得联系。

感谢以下 IntelliTect 技术专家对本文的审阅: Kevin Bost、Andrew Scott 和 Michael Stokesbary