章涵盖
在本章中,我们将创建MyBGList Web API,这是我们在第1章中介绍的面向服务的体系结构具体方案的基石。更具体地说,我们将穿上负责创建和设置项目的软件开发团队的鞋子。我们必须做出一些高级决策,例如选择要采用的集成开发环境 (IDE),然后切换到更实用的方法,例如首次获取源代码,以及调试和测试它以确保它按预期工作。
在本章结束时,您将能够通过解决有关所涵盖主题和概念的一些总结练习来测试您的知识。主要目标是创建一个工作 ASP.NET Web API 项目,你将在以下章节中扩展和改进该项目。
由于我们已经选择使用 ASP.NET Core 开发 Web API,因此回顾一下系统要求(我们需要安装什么才能开始开发之旅)可能会很有用。
要获取的最重要的工具是 .NET 软件开发工具包(更广为人知的 .NET SDK),其中包含 .NET 命令行界面 (.NET CLI)、.NET 库和三个可用的运行时:
注意.NET SDK 可作为适用于 Windows、Linux 和 macOS 的独立包提供,网址如下:https://dotnet.microsoft.com/download。
从严格的角度来看,安装.NET SDK是我们开始构建任何类型的.NET应用程序所需要做的就是,包括我们的 ASP.NET Core Web API。但是,使用 Windows、Linux 或 macOS 中可用的内置工具(例如默认文本编辑器和命令行终端)编写源代码远非理想。经验丰富的开发人员可以自豪地说他们可以通过使用记事本,Emacs或vim做任何事情的日子早已一去不复返了。事实上,现代 IDE 包含大量有用的功能,这些功能无疑会提高任何愿意学习如何高效利用它们的软件开发人员的生产力。我不只是在谈论语法突出显示、代码完成和其他“外观”功能。现代 IDE 之所以出色,是因为它们能够提供工具和扩展,使开发团队能够标准化和自动化某些流程,从而支持面向 DevOps 的方法:任务运行器、包管理器、代码检查器、集成源代码控制、自动部署系统、安全凭据存储、语法突出显示等等。
出于所有这些原因,因为我们想设身处地为MyBGList软件开发团队着想,我们将使用IDE(或具有高级功能的代码编辑器)构建我们的Web API。Microsoft提供了两种选择:
注意许多非Microsoft替代品值得一提,例如JetBrains的Rider和Adobe的Brackets。但是,为了简单起见,我们将分析限制为Microsoft开发工具。
Visual Studio 和 Visual Studio Code 都可用于创建、配置和维护 ASP.NET Web API 项目。但是,由于我们希望在完成任务时充分探索.NET和 ASP.NET Core框架,因此我们将选择Visual Studio。具体来说,我们将使用 Visual Studio 2022,这是撰写本文时可用的最新版本。
注意如果你想使用Visual Studio Code或其他编辑器,不要担心。本书中的所有代码示例,以及 GitHub 存储库中提供的所有内容,也将在这些编辑器中工作。
Visual Studio 2022 有三个版本,每个版本都有一组特定的受支持功能:
注意就本书而言,您有权通过以下网址下载并安装社区版:https://visualstudio.microsoft.com。
Visual Studio 安装过程分为三个阶段:
图 2.1 将 ASP.NET 和 Web 开发工作负载添加到 Visual Studio 安装
注意如果您是第一次阅读本书,安装英语语言包可能是一个不错的选择,以便 IDE 命令始终与示例和屏幕截图匹配。
当我们在系统上安装了 .NET SDK 和 Visual Studio 2022 时,我们可以开始创建我们的第一个 Web API 项目。执行以下步骤:
图 2.2 在 Visual Studio 中查找 ASP.NET 核心 Web API 项目模板
配置模板相当容易。在我们的场景中,我们给项目命名 MyBGList,并接受其他默认设置,如图 2.3 所示。请务必选择 .NET 6.0 框架,这是撰写本文时可用的最新版本。
图 2.3 配置 ASP.NET 核心 Web API 项目
警告如果要使用其他 .NET 版本,可以自由执行此操作。但请记住,本书中的某些源代码示例可能需要进行一些更改才能使用框架更新和/或重大更改。
单击“创建”按钮后,Visual Studio 将立即为新的 MyBGList 项目生成源代码,将其添加到具有相同名称的解决方案中,然后在 IDE 中打开它。一切就绪!
在继续之前,让我们快速检查一切是否正常。按 F5 键(或单击最上面的工具栏中的“运行”按钮)以在调试模式下启动项目。如果我们正确执行了所有操作,Visual Studio 应该自动启动我们的默认浏览器,指向 https:/ /localhost:<someRandomPort> 并显示图 2.4 中显示的页面。
图2.4 MyBGList项目首次运行
正如我们所看到的,我们用于创建项目的Visual Studio Web API模板提供了一个简洁的起始页,其中提到了Swagger,这是一个描述API结构的便捷工具。我将在本章后面介绍 Swagger。现在,我们已准备好更好地了解我们的项目。
在我们开始编码之前,可能值得讨论项目和解决方案以及它们在Visual Studio生态系统中扮演的角色。简而言之,我们可以说
在以下章节中,我们将向解决方案中添加其他项目。具体来说,我们将创建一些类库,我们希望将其与 Web API 项目分开,以便我们可以在其他地方使用它们。这种方法提高了代码的可重用性,同时让我们有机会在同一 IDE 窗口中对项目进行逻辑分组和访问。
现在我们已经了解了Visual Studio的基础知识,让我们花一些宝贵的时间来回顾我们全新的Web API项目的自动生成源代码。默认的 ASP.NET Core Web API 模板提供了一个最小但方便的样板,可用于理解典型项目的基本结构,这正是我们在开始编写与棋盘游戏相关的 Web API 之前需要做的。
让我们从项目的文件结构开始。在“解决方案资源管理器”窗口中,我们看到项目包含一些重要文件:
在下一节中,我们将简要回顾所有这些文件,以了解它们的用途以及它们在样板文件中扮演的角色。在执行代码审查时,我们还将对一些默认行为进行一些小而重要的更新,以更好地满足我们的需求。最终,我们将用我们自己的棋盘游戏主题类替换与天气预报相关的样板文件。
要查看的第一个文件是 launchSettings.json,位于 /Properties/ 文件夹中。顾名思义,此文件包含一些与项目启动方式相关的配置设置。但是,请务必了解,此文件以及包含的所有设置将仅在本地开发计算机中使用。换句话说,当我们在生产服务器上发布项目时,它不会与我们的应用一起部署。正如我们通过打开它看到的那样,配置设置分为三个主要部分(或 JSON 键):
如果你不知道IIS Express和Kestrel是什么,让我们快速回顾一下背景故事。ASP.NET Core 为两个可用于本地开发的 Web 服务器提供内置支持:
注意在Visual Studio 2010及更早版本中,用于开发目的的默认Web服务器是 ASP.NET 开发服务器,通常称为Cassini。
我们可以通过单击“开始”按钮右侧的箭头处理程序来选择在 Visual Studio 中运行应用时要使用的 Web 服务器。此处理程序是 Visual Studio 顶级工具栏上带有绿色箭头的按钮,如图 2.5 所示。
图 2.5 Visual Studio 的“开始”按钮
应用名称的选项(在我们的方案中为 MyBGList)对应于 Kestrel。如我们所见,我们还可以选择要使用的Web浏览器,以及现在可以跳过的其他一些选项。
launchSettings.json 文件的 iisSettings 和配置文件部分包含 IIS Express 和 Kestrel 的配置设置。对于每个服务器,我们可以选择要使用的 HTTP 和 HTTPS 端口、启动 URL、启动应用程序之前要设置的环境变量等。
如图 2.5 所示,如果我们现在单击“开始”按钮(或选择“调试”>“开始调试”或按 F5),我们将看到 SwaggerUI 页面,该页面处理在两个浏览器的 launchUrl 选项中配置的 swagger 终结点。请注意,无论我们选择哪个 Web 服务器,都会显示图 2.4 中显示的 SwaggerUI 页面,因为浏览器已配置为使用该端点。唯一明显改变的是用于建立HTTPS连接的本地TCP端口,因为Visual Studio在创建项目时随机确定它们。让我们借此机会规范化这些端口。
注意我们将在后面的章节中广泛使用 SwaggerUI 页面及其内容,同时实现我们的示例 Web API。此外,第11章深入讨论了Swagger。
打开 launchSettings.json 文件,并更改其内容,如以下清单所示。更新的行和值以粗体显示。
清单 2.1 修改了 launchSettings.json 文件
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40080", ?
"sslPort": 40443 ?
}
},
"profiles": {
"MyBGList": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger", ?
"applicationUrl": "https://localhost:40443;http://localhost:40080", ?
"environmentVariables": { ?
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger", ?
"environmentVariables": { ?
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
? IIS Express 本地 URL 和 TCP 端口,用于 HTTP 和 HTTPS
? Kestrel 本地 URL 和 TCP 端口,用于 HTTP 和 HTTPS
? 红隼起始页
? 红隼环境变量
? IIS Express 起始页
? IIS 快速环境变量
正如我们所看到的,我们已经为IIS Express和Kestrel设置了40080(HTTP)和40443(HTTPS)TCP端口。这个简单的调整确保了本书中引用的URL在我们的本地代码库中正常工作,无论我们要使用的Web服务器如何。
内置 launchSettings.json 文件中指定的其余设置暂时足够好,因此我们可以保留它们。但是,在关闭文件之前,让我们仔细看看“环境变量”部分,其中包含IIS Express和Kestrel的单个ASPNETCORE_ENVIRONMENT环境变量。
让我们转到 appsettings.json 文件,该文件将应用程序配置设置存储在 JSON 键值对中。如果我们查看MyBGList Web API项目的自动生成代码,我们可以看到Visual Studio创建了该文件的两个实例:
在了解这些文件的工作原理之前,探索 ASP.NET Core 中的运行时环境的概念可能会很有用。
运行时环境
Web 应用程序开发通常至少涉及三个主要阶段:
根据 .NET 约定,这些阶段称为环境,可以使用应用执行上下文中的DOTNET_ENVIRONMENT和/或ASPNETCORE_ENVIRONMENT环境变量进行设置。每当我们启动应用程序时,我们都可以通过相应地设置该环境变量来选择要面向的运行时环境。
提示如果我们还记得 launchSettings.json 文件的 “environmentVariables” 部分,我们已经知道如何在本地开发机器中设置 ASPNETCORE_ENVIRONMENT 变量。我们将在第 12 章部署 Web API 时学习如何在生产服务器中执行此操作。
应用设置文件
现在我们知道了所有这些,我们可以很容易地理解这两个appsettings文件的用途:
警告特定于环境的文件将在通用版本之后读取,从而覆盖其中存在的任何键值对。换句话说,如果我们使用开发环境运行我们的应用程序,则应用程序设置中存在每个键值对。Development.json 将被添加到 appsettings.json 文件中存在的键值对中,如果它们已经设置,则替换它们。
如果我们查看这两个 appsettings 文件,我们会看到一堆与日志相关的设置(在日志记录 JSON 键中),我们现在可以忽略这些设置。我们将有机会在第7章讨论日志记录技术时与他们一起玩。我们现在能做的是添加一个新的键/值对,以后可以帮助我们。打开 appsettings.json 文件,并将以下行(粗体)添加到现有 JSON 中:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"UseDeveloperExceptionPage": false
}
这个新的配置设置将为我们提供一些 appsettings 文件的练习,还允许我们在稍后将实施的实现技术之间切换。
让我们转到程序.cs文件,我们在第 1 章中简要介绍了该文件。我们已经知道,此文件在应用程序开始时执行,以注册和配置所需的服务和中间件来处理 HTTP 请求和响应管道。
事实上,由 ASP.NET Web API 模板创建的默认 Program.cs 文件与我们在第 1 章中看到的相同,因此我们不会在其中找到任何新内容。通过简要回顾一下,我们可以清楚地看到我们的 Web API 要使用的服务和中间件,如以下列表所示。
清单 2.2 Program.cs文件
var builder=WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers(); ?
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); ?
builder.Services.AddSwaggerGen(); ?
var app=builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger(); ?
app.UseSwaggerUI(); ?
}
app.UseHttpsRedirection(); ?
app.UseAuthorization(); ?
app.MapControllers(); ?
app.Run();
? 控制器服务和中间件
? 招摇服务和中间件
? HTTP 到 HTTPS 重定向中间件
? ASP.NET 核心授权中间件
? 控制器服务和中间件
当我们在这里时,让我们借此机会添加一些有用的中间件,以帮助我们更好地处理错误和异常。
异常处理
在Program.cs文件中找到以下代码:
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
将其替换为以下内容(以粗体标记的更改):
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
正如我们所看到的,我们在 HTTP 管道中添加了新的中间件。仅当应用在开发环境中运行时,才会包含第一个添加项;第二个添加将仅存在于过渡和生产环境中。以下是此中间件的详细操作:
现在,尽管 DeveloperExceptionPageMiddleware 开箱即用,不需要任何额外的工作,但 ExceptionHandlingMiddleware 要求我们实现一个专用的处理程序。正如我们通过查看代码所看到的,我们已经传递了 /error string 参数,这意味着我们希望使用我们需要实现的专用 HTTP 路由来处理这些错误。
正如我们在第 1 章中已经知道的,我们有两种方法可以做到这一点:使用控制器或使用最小 API。让我们看看它们,然后选择最有效的一个。
使用控制器
让我们从基于控制器的方法开始。从 Visual Studio 的解决方案资源管理器中,执行以下步骤:
我们将看到新的 ErrorController.cs 文件的内容:一个空类,我们可以用来添加我们的操作方法 — 具体来说,我们需要处理 /error/ 路由的操作方法,我们的 ExceptionHandlingMiddleware 将转发 HTTP 错误。下面是我们需要的操作方法的最小实现:
using Microsoft.AspNetCore.Mvc;
namespace MyBGList.Controllers
{
[ApiController]
public class ErrorController : ControllerBase
{
[Route("/error")] ?
[HttpGet] ?
public IActionResult Error()
{
return Problem(); ?
}
}
}
? 要处理的 HTTP 路由
? 要处理的 HTTP 方法
? 返回给调用方的 HTTP 响应
我们返回的 Problem() 方法是 ControllerBase 类(我们的 ErrorController 扩展)的一种方法,它生成 ProblemDetail 响应 — 一种机器可读的标准化格式,用于基于 RFC 7807 (https://tools.ietf.org/html/rfc7807 指定 HTTP API 响应中的错误).简而言之,它是一个 JSON 文件,其中包含有关错误的一些有用信息:标题、详细信息、状态等。但是,由于我们在未指定任何参数的情况下调用 Problem() 方法,因此这些值将由 ASP.NET Core 使用从已引发的异常中获取的默认值自动设置。
使用最小 API
让我们看看如何使用最小 API 来实现相同的结果。在 Visual Studio 的解决方案资源管理器中,打开 Program.cs 文件,并在应用之前添加以下代码。MapControllers() 方法:
app.MapGet("/error", ()=> Results.Problem());
就是这样。事实上,Minimal API 似乎是这场比赛的明显赢家,因为它允许我们使用单行代码获得与我们的 ErrorController 相同的结果,而无需创建专用文件。这个结果应该不足为奇:此场景是死简单路由操作的完美示例,其中最小 API 大放异彩,而控制器更适合复杂任务。
在接下来的章节中,我们将看到许多基于控制器的方法将报复的场景。目前,我们不妨删除 ErrorController.cs 文件,并将最小 API 单行代码保留在 Program.cs 文件中。不过,首先,让我们花几分钟时间讨论一下,如果我们保持 ErrorController.cs 在原地会发生什么。
路由冲突
控制器和最小 API 可以毫无问题地存在于同一个项目中,因此开发人员可以两全其美。但它们应配置为处理不同的路由。如果他们共享一个终端节点,会发生什么情况?
如果我们记得在第1章中学到的内容,我们已经知道了答案:程序.cs文件中首先出现的中间件首先处理HTTP请求,并可能终止它,从而防止另一个请求发挥作用。这种行为非常好,不会在HTTP生命周期中造成任何重大问题,除了浪费在我们项目的代码库中有一个无用的实现。
在我们当前的方案中,因为我们放置了最小 API 的应用。MapGet() 方法就在应用程序之前。MapControllers() 方法,“死代码”受害者将是我们的 ErrorController.cs 文件。如果一切正常,我们为什么要删除该控制器?我们不能把它留在那里吗?
回答该问题的最佳方法是再次按 F5 并执行我们的应用,然后再删除 ErrorController.cs 文件。图 2.6 显示了我们应该得到什么。
图 2.6 SwaggerUI 错误 500(由于路由冲突)
正如我们所看到的,以前工作的 SwaggerUI 页面显示一个获取错误,因为它的数据源(自动生成的 swagger.json 文件在内部用于构建 UI)返回 HTTP 500 错误。如果我们复制该 URL (https:/ /localhost:40443/ swagger/v1/swagger.json) 并将其粘贴到我们 Web 浏览器的地址栏中,我们可以看到实际错误:
SwaggerGeneratorException: Conflicting method/path combination "GET error"
for actions - MyBGList.Controllers.ErrorController.Error (MyBGList),HTTP:
GET /error. Actions require a unique method/path combination for
Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround.
这条错误消息将我们带到了问题的根源:我们有两个处理程序用于相同的方法/路径组合(GET /error),这会阻止 Swagger 正常工作。要解决此问题,我们可以做以下两件事之一:
在这种情况下,删除 ErrorController.cs 文件或将其从项目中删除是更好的做法,因为我们无论如何都不想保留冗余代码。但是,如果我们出于某种原因想要保留它,我们可以指示 Swagger 通过以下方式更改程序文件中的 SwaggerGeneratorMiddleware 配置来处理这种情况.cs(更新的代码以粗体标记):
builder.Services.AddSwaggerGen(opts=>
opts.ResolveConflictingActions(apiDesc=> apiDesc.First())
);
我们告诉 Swagger 通过始终采用找到的第一个并忽略其他冲突来解决与重复路由处理程序相关的所有冲突。但是,强烈建议不要使用此方法,因为它可以隐藏潜在的路由问题并导致意外结果。难怪错误消息称其为解决方法!
警告更一般地说,始终通过删除冗余(或错误)操作处理程序来解决路由冲突。设置框架(或中间件)以自动“解决”冲突几乎总是不好的做法,除非开发人员有足够的经验知道他们在做什么。
因此,在继续之前,我们能做的最好的事情是删除 ErrorController.cs 文件或将其从项目中排除(右键单击它,然后从解决方案资源管理器的上下文菜单中选择“从项目中排除”),这样 Swagger 就没有机会找到任何重复。
测试它
现在,我们已经为开发环境配置了开发人员例外页面,为生产环境配置了 Error() 操作,我们需要模拟实际错误。最快的方法是添加另一个引发异常的操作方法(或最小 API)。如果我们仍然有错误控制器,我们可以通过以下方式实现操作方法:
[Route("/error/test")]
[HttpGet]
public IActionResult Test()
{
throw new Exception("test");
}
但是,由于我们选择从项目中删除或排除 ErrorController,因此我们可以将以下最小 API 单行代码放在程序.cs文件中,正下方是我们添加的其他 MapGet() 方法:
app.MapGet("/error/test", ()=> { throw new Exception("test"); });
然后单击“开始”按钮(或按 F5 键)并将 Web 浏览器指向 https://localhost:40443/error/test。如果我们正确执行了所有操作,我们应该看到由 DeveloperExceptionPageMiddleware 生成的开发人员异常页面,如图 2.7 所示。
图 2.7 测试开发人员异常页面中间件
此结果是意料之中的,因为我们在开发环境中执行应用,由 launchSettings .json 文件中的 ASPNETCORE_ENVIRONMENT 变量指定。如果我们想测试 ExceptionHandlerMiddleware,我们需要做的就是将变量的值从开发更改为生产。
或者,我们可以充分利用我们添加到appsettings.json文件中的UseDeveloperExceptionPage键。实现此设置将允许我们在开发人员例外页面和 ExceptionHandler 之间切换,而无需更改应用程序的运行时环境。打开程序.cs文件,并替换代码
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
使用此代码:
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
if (app.Configuration.GetValue<bool>("UseDeveloperExceptionPage")) ?
app.UseDeveloperExceptionPage(); ?
else
app.UseExceptionHandler("/error"); ?
? 从 appsettings.json 文件中检索该文本值
? 如果为 TRUE,则使用 DeveloperExceptionPageMiddleware
? 如果为 FALSE,则改用 ExceptionHandlerMiddleware
现在将使用 ExceptionHandlerMiddleware 而不是 DeveloperExceptionPageMiddleware,因为在 appsetting.json 文件中,UseDeveloperExceptionPage 键的值设置为 false。我们可以立即按 F5,导航到 https://localhost:40443/error/test URL,并接收 ProblemDetail JSON 响应:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500
}
注意此 JSON 输出在我们的方案中(目前)足够可行,因为它不会公开有关我们应用的潜在可利用信息。我们可以进一步自定义输出。我们可以使用方法重载支持的可选参数,将通用的“发生错误”标题替换为实际的 Exception 消息,为不同类型的错误提供不同的状态代码,等等。
现在我们已经完成这一系列测试,我们应该为开发环境重新启用 DeveloperExceptionPageMiddleware。我们可以打开appsettings .json文件并将UseDeveloperExceptionPage值从false更改为true,但这不是正确的做法。我们希望确保这样一个潜在的不安全页面只能被开发人员看到,记得吗?因此,重新启用它的正确方法是执行以下步骤:
以下是更新后的文件的外观(粗体换行):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"UseDeveloperExceptionPage": true
}
现在我们放在应用程序设置中的值。每当我们的应用在开发运行时环境中启动时,Development.json 文件都会覆盖 appsettings.json 文件中的值,这正是我们想要的。
下一个要查看的文件是 WeatherForecastController.cs,我们可以在 /Controllers/ 文件夹中找到它。
注意按照 ASP.NET 约定,所有控制器类都必须驻留在项目的根级 /Controllers/ 文件夹中,并从 Microsoft.AspNetCore.Mvc.Controller 基类继承。
正如我们从第 1 章中知道的那样,控制器在 ASP.NET Core 中用于定义和分组处理 HTTP 请求(通过路由映射)并相应地返回 HTTP 响应的操作。如果我们看一下WeatherForecastController的源代码,我们可以看到它也不例外。此示例控制器旨在处理对 /WeatherForecast 路由的 HTTP GET 请求,并返回一个 HTTP 响应,其中包含一个包含五个 JSON 对象的数组,其中包含一些随机生成的日期、温度 C 和摘要属性值:
using Microsoft.AspNetCore.Mvc;
namespace MyBGList.Controllers
{
[ApiController] ?
[Route("[controller]")] ?
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries=new[] {
"Freezing", "Bracing", "Chilly", "Cool",
"Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger; ?
public WeatherForecastController
(ILogger<WeatherForecastController> logger)
{
_logger=logger; ?
}
[HttpGet(Name="GetWeatherForecast")] ?
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5)
.Select(index=> new WeatherForecast
{
Date=DateTime.Now.AddDays(index),
TemperatureC=Random.Shared.Next(-20, 55),
Summary=Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
? 添加特定于 API 的行为
? 默认路由规则
? ILogger 实例(通过依赖注入实例化)
? 处理 HTTP GET 到 /WeatherForecast 的操作
如果我们尝试执行此代码,我们会得到以下结果:
[{
date: "2021-12-03T02:04:31.5766653+01:00",
temperatureC: 0,
temperatureF: 32,
summary: "Warm"
},
{
date: "2021-12-04T02:04:31.5770138+01:00",
temperatureC: 23,
temperatureF: 73,
summary: "Freezing"
},
{
date: "2021-12-05T02:04:31.5770175+01:00",
temperatureC: 40,
temperatureF: 103,
summary: "Freezing"
},
{
date: "2021-12-06T02:04:31.5770178+01:00",
temperatureC: 47,
temperatureF: 116,
summary: "Cool"
},
{
date: "2021-12-07T02:04:31.577018+01:00",
temperatureC: 36,
temperatureF: 96,
summary: "Mild"
}]
返回的对象是 C# WeatherForecast 类的 JSON 表示形式,该类在项目根文件夹的 WeatherForecast.cs 文件中定义。 正如我们通过查看其源代码所看到的,它是一个 POCO 类,其中包含一些可以轻松序列化为 JSON 输出的属性:
namespace MyBGList
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF=> 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}
注意 POCO 代表普通旧 CLR 对象,换句话说,一个没有依赖项、属性、基础结构问题、特殊类型或其他职责的普通类。
WeatherForecastController 和 WeatherForecast 示例类可用于了解 ASP.NET 控制器的工作原理,但它们不适合我们的具体方案。在处理与棋盘游戏相关的 API 时,我们不需要了解任何有关温度或预测的信息。出于这个原因,我们将删除这些文件或将它们从项目中排除,就像我们之前对 ErrorController.cs 文件所做的那样,并将它们替换为更相关的示例。
让我们从POCO类开始,它将取代以前的天气预报。在 Visual Studio 的解决方案资源管理器中,执行以下步骤(清单 2.3):
清单 2.3 BoardGame.cs文件
namespace MyBGList
{
public class BoardGame
{
public int Id { get; set; }
public string? Name { get; set; }
public int? Year { get; set; }
}
}
这个新类仍然是一个示例,但它与我们选择的方案更一致!让我们对控制器执行相同的操作。在 Visual Studio 的解决方案资源管理器中,执行以下步骤(清单 2.4):
清单 2.4 BoardGame.cs文件
using Microsoft.AspNetCore.Mvc;
namespace MyBGList.Controllers
{
[Route("[controller]")] ?
[ApiController]
public class BoardGamesController : ControllerBase
{
private readonly ILogger<BoardGamesController> _logger;
public BoardGamesController(ILogger<BoardGamesController> logger)
{
_logger=logger;
}
[HttpGet(Name="GetBoardGames")] ?
public IEnumerable<BoardGame> Get()
{
return new[] {
new BoardGame() {
Id=1,
Name="Axis & Allies",
Year=1981
},
new BoardGame() {
Id=2,
Name="Citadels",
Year=2000
},
new BoardGame() {
Id=3,
Name="Terraforming Mars",
Year=2016
}
};
}
}
}
? 更新的路线模式
? 新的获取方法
就是这样。我们新的 BoardGamesController 将处理 /BoardGames 路由,并使用一个 JSON 数组进行响应,该数组包含过去 45 年左右发布的三款备受赞誉的棋盘游戏的一些相关示例信息。
我们的BoardGamesController的最小行为可以通过Minimal API通过几行代码轻松处理。下面是一个代码片段,我们可以将其放入 Program.cs 文件中,以从 Get() 操作方法获取相同的输出:
app.MapGet("/BoardGames", ()=> new[] {
new BoardGame() {
Id=1,
Name="Axis & Allies",
Year=1981
},
new BoardGame() {
Id=2,
Name="Citadels",
Year=2000
},
new BoardGame() {
Id=3,
Name="Terraforming Mars",
Year=2016
}
});
此示例只是一个示例 JSON 响应,它模拟了更复杂的行为,其中通常包括重要的数据检索。在接下来的章节中,我们将使用实体框架核心从数据库管理系统 (DBMS) 获取棋盘游戏数据,甚至可能为用户更新它。当我们处理这些类型的操作时,基于控制器的方法变得方便,甚至可能比最小 API 更方便。出于这个原因,这次我们将保留控制器而不是更换它。
建立对 ASP.NET 和Visual Studio的信心的最佳方法是,一旦我们了解了各种工具的工作原理,就立即练习使用它们。本节提供了一些有用的练习,使我们能够使用在本章中学到的技能进一步自定义我们的第一个 Web API 项目。每个练习都旨在修改单个文件,但通过完成所有练习,我们将能够实现一致的总体目标。
假设我们需要为一组选定的内部测试人员配置新的 MyBGList Web API,这些测试人员将能够通过一组给定的 TCP 端口访问我们的开发机器。以下是我们需要确保的细节的完整积压工作:
提示如果您觉得大胆,请停止阅读此处,并在没有进一步帮助的情况下开始练习(困难模式)。如果您对到目前为止所学的内容不太有信心,可以阅读以下部分,这些部分提供了所有相关步骤的一般指导,而不会泄露解决方案(宽松模式)。所有给定练习的解决方案都可以在 GitHub 的 /Chapter_02/Exercises/ 文件夹中找到。若要测试它们,请将 MyBGList 项目中的相关文件替换为该文件夹中的文件,然后运行应用。
我们需要做的第一件事是确保测试人员能够通过给定的TCP端口访问本地机器。明智的做法是设置一个专用的运行时环境供他们使用。暂存环境似乎是完美的选择,因为它允许我们定义一些特定的配置设置,而无需更改生产和开发环境的配置,我们可能需要这些配置。我们可以通过更新launchSettings.json文件并通过以下方式为MyBGList项目配置Kestrel启动设置来执行这些任务:
我们不需要更改 IIS Express 的设置,因为测试人员不会使用它。这些任务完成积压工作中的第 1、2 和 3 项。
接下来要做的是为暂存运行时环境创建设置文件,并定义一些对所有环境都有效的默认行为,我们可以在需要时有条件地覆盖这些行为。以下是我们如何完成所有这些任务:
这些任务还不会影响任何事情,但它们符合我们规范的第 4 项。
提示将暂存环境的 UseDeveloperExceptionPage 设置为 false 可能是多余的,因为该值已在通用 appsettings.json 文件中设置。但是,由于我们谈论的是包含潜在机密信息的页面,因此在给定环境中明确拒绝访问不会造成伤害。
现在我们有了正确的应用设置变量,我们可以根据应用的运行时环境,使用它们有条件地添加(或跳过)相关中间件。我们需要打开 Program.cs 文件并更改 SwaggerMiddleware 和 SwaggerUIMiddleware 的当前初始化策略,以确保仅在 UseSwagger 设置为 True 时使用它们。通过这样做,我们完成了积压的第 4 项。
若要实现积压工作的第 5 项,我们需要向现有的 BoardGame POCO 类添加两个新属性。至于要使用的类型,最合适的选择是可为空的 int,因为我们用于 Year 属性;我们无法确定此类信息是否始终适用于所有棋盘游戏。
将这些属性添加到 BoardGame 类不足以在 JSON 文件中正确显示它们,除非我们希望它们始终为 null。因为我们目前正在处理示例数据,所以我们唯一能做的就是更新我们的 BoardGameController 的 Get() 方法并手动设置固定值。这项任务足以完成积压工作的第 5 项并完成练习。
我们剩下要做的就是选择 Kestrel 作为启动 Web 服务器,单击“开始”按钮(或按 F5)启动我们的 Web API 项目,看看会发生什么。如果我们正确执行了所有操作,我们的 Web 浏览器应该自动调用 https://localhost :55221/boardgames 端点并显示以下 JSON 响应:
[{
"id":1,
"name":"Axis & Allies",
"year":1981,
"minPlayers":2,
"maxPlayers":5
},
{
"id":2,
"name":"Citadels",
"year":2000,
"minPlayers":2,
"maxPlayers":8
},
{
"id":3,
"name":"Terraforming Mars",
"year":2016,
"minPlayers":1,
"maxPlayers":5
}]
如果我们取得了这个结果,我们就准备好继续前进了。
站想要改版,但是以前的技术资料又舍不得丢弃?我公司最近对以往比较旧的asp进行了改版升级,并且把原来的access数据库导入mysql数据库中,实现了数据的无缝衔接。
网站数据无缝对接
因为asp+access的网站静态生成占用服务器较少,并且是目录化结构,所以从野狼SEO团队到永易搜建站团队对于企业网站都是这样做的,但是这几年发现很多客户对于程序的交互性要求越来越高,尤其是现在开放平台的对接等还是PHP程序要更好操作并且更强大,所以最近四五年我们主要就是提升我们的PHP建站系统功能和易用性。在电脑+手机适配方面,我司的建站系统表现突出,受到大家的亲睐,所以怎么把老的ASP+ACCESS数据的内容导入到新的系统里并进行网站改版成为大家的呼声,所以我们就进行了改造。
升级网站数据不丢对SEO非常有帮助
如果您需要我司为您建站,这些问题都交给我们来做,您也可以自己动手来做,实现步骤如下:
第一步:了解老系统和新系统的数据适配关系,比如我司的ASP程序主要是这几个字段:
ID---------ID号不能变
ClassID----栏目ID
Title------标题
Intro------描述
Content----内容
Hits-------点击量
KeyWords---关键词
UpdateTime-发布时间
TemplateUrl-模板地址
FileName----目录名
PicUrl------缩略图
OrderID-----排序
IStop-------置顶
如果你是参考着修改其他系统,可以看看这个字段的适配关系。
第二步,在PHP系统中,通过PHP程序度access数据库,然后存入到mysql数据库。
其中注意要做好转码或者发布时间的格式转化。
例如我司access导入到mysql数据库中就用这样的代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>数据导入</title>
</head>
<body>
<?php
define('IN_yongyisou', true);
require_once 'include/init.php';
$act=isset($_GET['act'])?$_GET['act']:'';
if($act=='yongyisou56789390'){
$conn_mdb=new com("ADODB.Connection");
$connstr_mdb="DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=". realpath("Data_ACT/#YeLangSCF4E9.mdb");
$conn_mdb->Open($connstr_mdb);
$rs=new com("ADODB.RecordSet");
$rs->Open("select ID,ClassID,Title,Intro,Content,Hits,KeyWords,UpdateTime,TemplateUrl,FileName,PicUrl,OrderID,IStop from Article_ACT where 1",$conn_mdb,1,1);
while(!$rs->eof)
{
$ID=$rs->Fields('ID')->value;
$ClassID=$rs->Fields('ClassID')->value;
$Title=iconv('GB2312','UTF-8',$rs->Fields('Title')->value);
$Intro=iconv('GB2312','UTF-8',$rs->Fields('Intro')->value);
$Content=iconv('GBK','UTF-8',$rs->Fields('Content')->value);
$Hits=iconv('GB2312','UTF-8',$rs->Fields('Hits')->value);
$KeyWords=iconv('GB2312','UTF-8',$rs->Fields('KeyWords')->value);
$UpdateTime=iconv('GB2312','UTF-8',$rs->Fields('UpdateTime')->value);
$TemplateUrl=iconv('GB2312','UTF-8',$rs->Fields('TemplateUrl')->value);
$FileName=iconv('GB2312','UTF-8',$rs->Fields('FileName')->value);
$PicUrl=iconv('GB2312','UTF-8',$rs->Fields('PicUrl')->value);
$OrderID=iconv('GB2312','UTF-8',$rs->Fields('OrderID')->value);
$IStop=iconv('GB2312','UTF-8',$rs->Fields('IStop')->value);
$Content=htmlentities($Content,ENT_COMPAT,'UTF-8');//html进行转义
$UpdateTime=strtotime($UpdateTime);//发布时间变成时间戳
if($ClassID==5734002122){
//新闻中心
$sql="INSERT INTO ".table("article")." (id,count,cat_id,title ,body ,intro,pic,keywords, description,click,pub_time,sort,recommend,hot,pub)" .
" VALUES ('$ID','0','2','$Title','$Content','$Intro','$PicUrl', '$KeyWords','$Intro','$Hits','$UpdateTime','$OrderID','$IStop','0','1')";
if($yys->query($sql)){
echo("ID为".$ID."的文章导入成功<br/>");
}else{
echo("ID为".$ID."的文章导入失败<br/>");
}
}
$rs->MoveNext();
}
echo('导入成功');
}else{
die('参数不正确');
}
?>
</body>
</html>
最新版本的 ASP.NET 叫做 ASP.NET Core (也被称为 ASP.NET 5) 它颠覆了过去的 ASP.NET。
ASP.NET Core 1.0是一个开源跨平台的开发框架,用于构建基于云的现代 Web 应用 。它是从底层开始重新构建来提供性能优良的Web应用开发框架,可以部署在云上或者本地服务器上。另外,它使得 ASP.NET 应用更加精简和模块化(可以根据你的应用需要向里面添加其他模块),跨平台(你可以很容易的在 Windows, Mac or Linux 上开发和部署你的应用),云优化(你可以在云上在云上部署和调试你的应用)。
对于使用 ASP.NET 旧版本的我们来说,这意味着什么?
如果你正在使用旧版本的 ASP.NET 或者你有 WebForms 的开发背景,那么你将会认识到 ASP.NET Core 有多完美,这感觉起来就像从古典的 ASP 时代来到全新的 ASP.NET 的世界。
下面列出 ASP.NET Core 1.0 的核心变化.
你可以在 OSX 和 Linux上运行 ASP.NET Core 应用,这对于 ASP.NET 来说,这具有跨时代的意义,也给 ASP.NET 开发者和设计师们带来了全新的体验。ASP.NET Core 具有两个运行时,这意味着你可以选择不同的运行环境来部署你的应用,使得你的应用将更加灵活。
ASP.NET Core 1.0是一个 ASP.NET 的重构版本,它运行于最新的 .NET Core。它是模块化的,允许开发者以插件的形式添加应用所需要的模块,大多数的功能都将作为插件提供并通过 NuGet 程序包管理。这样做的一个好处就是你可以升级应用的一个模块,但丝毫不会影响其他模块;另外,.NET Core 是一个跨平台的运行时,因此你可以在 OSX 或 Linux 操作系统上部署你的应用;它也是一个云优化的运行时,用于在云上部署和调试应用;.NET Core 可以和你的应用程序一起被部署,当服务器上有多个 .NET Core 版本时, 你依旧可以运行 ASP.NET Core 应用。
你也可以创建只运行在 windows 下完整 .NET 框架的 ASP.NET Core 应用。
ASP.NET 4.6 是最新的完整 .NET Framework 的发布版本,它允许你可以利用所有的 .NET 组件并且具备向后兼容能力。如果你计划将应用迁移到 .NET core,那么你需要做适量的修改,因为 .NET Core 相对于完整 .NET Framework 来说有所限制。
需要明确的是,ASP.NET 4.6 更加成熟。它如今久经考验并且现已发布并可使用。ASP.NET Core 1.0 是1.0 发布版本,包含 Web API 和 MVC,但是现在还没有 SignalR 和 Web Pages。,它也不支持VB 和 F# 语言。
ASP.NET Core的跨平台,让它不再只依赖 Visual Studio,开发者和设计师们可以在自己喜欢的环境上工作。比如 Sublime Text,WebStorm ,这真是太棒了!
如果你使用 Visual Studio 创建了一个空的 ASP.NET Core 工程,那么你将会看到下面的惊喜。(除非你没有使用之前的 ASP.NET 创建过任何项目)
你感觉到惊喜了吗?新的工程结构完全不一样了, 工程模板焕然一新,包含以下的新文件:
· global.json: 你可以在这里放置解决方案的配置信息和工程之间的引用。
· Program.cs: 这个文件包含了 ASP.NET Core RC2 应用的 Main 方法,负责配置和启动应用程序。
· src folder: 包含组成你应用程序的全部项目代码。
· wwwroot:你的静态文件将被放置在这个文件夹,它们都将作为资源直接提供给客户端,包含 HTML,CSS 和 JavaScript 文件。
· project.json: 包含项目设置。在 ASP.NET Core中,你可以通过使用 NuGet 程序包管理工具(NPM)添加 NuGet 包或者编辑这个文件来管理从属。你可以通过任何文本编辑器来编辑这个文件,如果你使用 Visual Studio 2015,,这将会更加 轻松,因为它的智能提示会帮助你找到合适的 NuGet 包作为从属。project.json 就像下面这样。
· startup.cs这个主要放置你 ASP.NET Core 的 stratup 和 configuration 代码,下面就是 stratup 类的样子。
ConfigureServices 方法定义了你应用程序使用的服务,Configure 方法用来定义组成请求管道的中间件。
· References: 它包含了 .NETCoreApp 第一个版本运行时的引用。
是的,WebForms 不再是 ASP.NET 5 的一部分,这真令人悲伤。你可以继续使用 VS2015 的 .NET 4.6 来构建 Web Forms 应用,但是却不能体会 ASP.NET 5 的新特性了。
我已经开发了很多年从小型到大型的企业级 Web Forms 应用。 我很喜欢 Web Forms,,事实上我还会继续支持在各种论坛使用 WebForms 的社区,比如 http://forums.asp.net。但是我们是时候进步了,去学习一些新东西。这是学习 ASP.NET MVC 最后的时间了,就像过去的许多事物,你要么去适应,要么被淘汰。
除了 WebForms, the .NET Core 也没有包含 Windows Forms, WCF, WPF, Silverlight 等等。
目前,在当前 ASP.NET Core 1.0 RC2版本中, VB.NET 和 F# 也不被支持。
ASP.NET Core 将见证 MVC, Web API 和 Web Pages(可能包含)组合在一个架构中,它被称为 ASP.NET MVC Core。尽管当前发布版本中,还不支持 Web Pages and SignalR。
在之前的 ASP.NET MVC 中, MVC 控制器和 Web API 控制器是不同的。 一个 MVC 控制器使用基类 System.Web.MVC.Controller,一个 Web API 控制器使用基类System.Web.Http.ApiController。 在 MVC Core 中,会为它们提供一个共同的基类,就是Microsoft.AspNetCore.Mvc.Controller。
对于 HTML Helpers 来说,MVC 和 Web Pages 的合并是非常有可能的。 Web Pages 编程模型对当前版本来说还不适用,所以我们还不能负责任地说下一步计划合并哪些特性。 但是我们可以预测到,传统的 MVC 模型绑定将会出现。
在之前 ASP.NET MVC 中,, Html.Action 帮助方法一般用于调用一个 sub-controller。ASP.NET MVC Core 将会使用新的 View Components 用来代替使用Html.Action 的部件。
View Components 支持完全异步,这允许你创建异步的视图组件。
下面是一个简单的视图组件的例子,根据身份会返回个人介绍。
using Microsoft.AspNetCore.Mvc; using MVC6Demo.Models; using System.Threading.Tasks; using System.Collections.Generic; namespace MVC6Demo.ViewComponents { public class PersonListViewComponent : ViewComponent { public async Task<iviewcomponentresult> InvokeAsync(string status) { string viewToUse="Default"; bool isFiltered=false; PersonModel model=new PersonModel; if (status.ToLower.Equals("registered")) { viewToUse="Registered"; isFiltered=true; } var p=await GetPersonAsync(status, isFiltered); return View(viewToUse,p); } private Task<ienumerable<person>> GetPersonAsync(string status, bool isFiltered) { return Task.FromResult(GetPerson(status,isFiltered)); } private IEnumerable<person> GetPerson(string status, bool isFiltered) { PersonModel model=new PersonModel; if (isFiltered) return model.GetPersonsByStatus(status); else return model.GetAll; } } } </person>
下面是 View Component 的视图:
<h3>Person List</h3> <ul> @foreach (var p in Model) { <li>@string.Format("{0} {1}",p.FirstName,p.LastName)</li> } </ul>
这里展示了如何在主视图中调用 View Components
<div> @await Component.InvokeAsync("PersonList", new { type="Registered" }) </div>
ASP.NET MVC Core 提供了少量新指令。 下面我们来看看如何使用 @inject。 @inject 指令允许你注入一个类中的方法到你的视图中。
这是一个简单的类,来展示一些异步的方法。
using System.Threading.Tasks; using System.Linq; namespace MVC6Demo.Models { public class Stats { private PersonModel _persons=new PersonModel; public async Task<int> GetPersonCount { return await Task.FromResult(_persons.GetAll.Count); } public async Task<int> GetRegisteredPersonCount { return await Task.FromResult( _persons.GetAll.Where(o=> o.Status.ToLower.Equals("registered")).Count); } public async Task<int> GetUnRegisteredPersonCount { return await Task.FromResult( _persons.GetAll.Where(o=> o.Status.ToLower.Equals("")).Count); } } }
现在我们就可以在视图中使用 @inject 指令来调用那些方法:
@inject MVC6Demo.Models.Stats Stats @{ ViewBag.Title="Stats"; } <div>
这是不是很酷?
查看我关于 ASP.NET MVC 新指令详细例子的文章: Getting Started with ASP.NET MVC Core
ASP.NET MVC Core 另外一个非常酷的东西就是 Tag Helpers。对于之前的 HTML Helpers,Tag Helpers 是可选的替代语法。
所以相比于以下代码:
@using (Html.BeginForm("Login", "Account", FormMethod.Post, new { @class="form-horizontal", role="form" })) { @Html.AntiForgeryToken <h4>Use a local account to log in.</h4> <hr /> @Html.ValidationSummary(true, "", new { @class="text-danger" }) <div class="form-group"> @Html.LabelFor(m=> m.UserName, new { @class="col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m=> m.UserName, new { @class="form-control" }) @Html.ValidationMessageFor(m=> m.UserName, "", new { @class="text-danger" }) </div> </div> }
你可以使用这些代码:
<form asp-controller="Account" asp-action="Login" method="post" class="form-horizontal" role="form"> <h4>Use a local account to log in.</h4> <hr /> <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="UserName" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="UserName" class="col-md-2 control-label" /> <span asp-validation-for="UserName" class="text-danger"></span> </div> </div> </form>
14年前,ASP.NET 平台基本只能部署在一种服务器上,那就是 IIS。几年之后,Visual Studio Development Web Server(也叫作“Cassini”)作为一种开发服务被使用,但是它们最终都是调用 System.Web 作为应用程序和 Web 服务器中间的主机层。System.Web 主机与 IIS 耦合度很高,所以要想运行在另一台主机上会非常困难。
后来 OWIN作为应用程序和 Web 服务器中间的接口出现。 Microsoft 开发了Katana作为一个 OWIN 的实现,可以部署 ASP.NET Web API, SignalR 和其他第三方框架,这些框架可以在 IIS 和 IIS Express, Katana's 自托管主机和自定义主机。
ASP.NET Core 是不强调主机的,它在 Katana 和 OWIN 上行为一致。ASP.NET Core 也可以部署在 IIS, IIS Express 或者自托管在你自己的进程里。另外,ASP.NET Core 也会包含一个叫做 Kestrel的 Web 服务器,它建立在 libuv 上,主要用于 iOS 和 Linux 操作系统。
ASP.NET Core 提供了一种更加模块化的 HTTP 请求管道, 你可以只添加你需要的组件。这个管道不再依赖 System.Web,通过降低管道中的开销,你的 app 性能更加优良,更好的调谐 HTTP 协议栈。新的管道基于 Katana 项目经验,同时支持 OWIN。
Visual Studio 2015 中另一个非常酷的特性就是支持动态编译。在过去的 ASP.NET 中,当我们修改了应用的后台代码,我们需要重新编译并且运行才能看到页面的变化。 在新版本的 Visual Studio 中,你不需要再做这些额外的步骤,仅仅是保存你的修改和刷新浏览器即可。
这是在刷新页面之后的输出:
在过去的 MVC 和 Web API 中,使用路由属性可能会导致一些问题,尤其是你正在做一些代码重构。这是因为路由必须设定为字符串类型,当你修改了控制器的名字,你就必须修改路由属性的字符串
MVC Core 提供了新的 [controller] 和 [action] 标记,它们可以解决这个问题。下面这篇文章重点说明了这些新标记的用法。 : ASP.NET MVC 6 Attribute Routing.
ASP.NET Core 内嵌了对依赖注入和 Service Locator 模式的支持,这意味着你不在需要通过第三方依赖注入框架 Ninject 或 AutoFac。
Visual Studio 2015 内嵌了对流行开源 Web 开发工具的支持。 Grunt 和 Gulp 可以帮你自动化构建 Web 开发工作流, 你可以使用它们来编译和压缩 JavaScript 文件。Bower 是一个用于客户端库的管理工具,包含 CSS 和 JavaScript 库。
AngularJs 是当前最流行的前端框架之一,用于构建单页面应用程序(SPAs)。Visual Studio 包含了用于创建 AngularJs 模块,控制器,指令和工厂。
对 GruntJS 的支持使得 ASP.NET 成为一个用于构建客户端 AngularJs 应用的优秀服务器端框架。 当完成一个版本,你可以自动合并和压缩全部 AngularJs 文件。查看我的关于开始在 ASP.NET 中使用 Angular 和 Angular2 的文章 。
ASP.NET Core 也是以 SignalR 3 为基础,这使得你可以向云连接的应用程序添加实时功能。查看我之前的 SignalR 例子: ASP.Net SignalR: Building a Simple Real-Time Chat Application
在 ASP.NET Core 中,混乱的 web.config 文件被新的云就绪配置文件代替,它称作 “config.json”。微软希望开发人员更容易地在云中部署应用程序,并使得应用能够根据特殊环境自动的读取正确的配置参数。
这是一个新的配置文件的样子:
由于 ASP.NET Core 都是插件化的,你需要配置 Stratup 类的源代码,就像下面这样:
public Startup(IHostingEnvironment env) { var builder=new ConfigurationBuilder .SetBasePath(env.ContentRootPath); builder.AddEnvironmentVariables; Configuration=builder.Build; } public IConfigurationRoot Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddMvc; services.AddTransient<MVC6Demo.Models.HeroStats>; } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage; app.UseMvc(m=> { m.MapRoute( name: "default", template: "{controller}/{action}/{id?}", defaults: new { controller="Home", action="Index"}); }); }
在之前的 ASP.NET MVC 中,默认的测试框架是 Visual Studio 单元测试框架(有时候也叫作mstest),这个框架使用 [TestClass] 和 [TestMethod] 特性来描述一个单元测试。
ASP.NET Core 使用 xUnit.net作为它的单元测试框架。这个框架使用 [Fact] 特性来代替 [TestMethod] 特性,也消除了对 [TestClass] 属性的依赖。
是的,ASP.NET Core 被作为一个开源项目托管到 GitHub上, 你可以查看源代码,并下载并提交你的更改。
我认同开源的 .NET 会产生重大的意义,它产生了积极的商业意义和社区意义,十分感谢微软所做出的工作。
文章来源:By Vincent Maverick Durano, 10 Jun 2016
*请认真填写需求信息,我们会在24小时内与您取得联系。