65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Core Web API:你需要知道的一切(第一部分,共两部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (15投票s)

2020年5月20日

CPOL

15分钟阅读

viewsIcon

16085

downloadIcon

190

一篇快速文章,带你了解如何构建 .NET Web API 并通过 AJAX(使用 JSON)向其发送数据。

背景

最近,在尝试使用 .NET Core Web API 时,我发现自己不确定通过 XMLHttpRequest (XHR) 对象将数据发布到 Web API 的正确方法。

我不确定

  1. 如何将数据添加到 XHR 对象中,使其显示在 post body 中。
  2. 如何确保 Web API 能自动将发布的 JSON 转换为我目标域对象。

我收到了各种错误,而且无法判断是客户端出了问题,还是 Web API 端出了问题,或者两者都有。我发现两者都有问题,但我还发现,即使你认为这是一个常见的组合(纯 JavaScript XHR 发布到 Web API),也很难找到一个确切的答案。

本文涵盖的内容

  1. 创建 .NET Core Web API 项目(通过命令行)- 我在 Ubuntu Linux 上使用 Visual Studio Code。
  2. 添加一个可以被发布的 Web API 方法。
  3. 修改 Web API 应用程序,使其能够提供一个 *index.htm* 文件(用于测试我们的 Web API)。
  4. 设置一个简单的 *index.htm* 和 *main.js* 文件,用于向 Web API 发送数据。
  5. 配置 XMLHttpRequest (XHR) 以将 JSON 发布到 Web API。

引言

我假设您已经在机器上安装了最新版本的 Visual Studio 或 Visual Studio Code。

当然,您还需要确保已安装最新版本的 .NET Core。如果您需要,可以访问 https://dotnet.microsoft.com/download^

我在 Ubuntu Linux 上运行 Visual Studio Code,所以一切都通过命令行操作,但如果您在 Windows 上使用 Visual Studio,则可以使用向导来创建 .NET Core Web API。不过,使用 .NET Core 进行命令行操作并不困难,而且您可能会觉得相当令人满意。

创建新项目

开始之前,请执行以下步骤:

  1. 打开控制台(或终端)。
  2. 导航到您想要创建新项目的目录。
  3. 键入以下命令:dotnet new webapi --name MainWebAPI

将创建一个新文件夹

当您键入该命令并按 **<ENTER>** 后,它将创建一个名为 `MainWebAPI` 的新子文件夹,并将所有项目文件添加到该目录中。

如果成功,您将看到类似以下内容:

create .net web api project

如果您收到“命令未识别”之类的错误,那么您可能尚未安装 .NET Core SDK。要确定已安装的 .NET 版本,可以尝试以下命令:

dotnet --version

我的回复是 3.1.202。

如果一切顺利,那么您就拥有了一个基于 .NET Core 的非常基本的 Web API。

运行 Web API 项目

让我们确保项目可以编译并运行。这非常简单。

首先,只需切换目录到新创建的项目目录:cd MainWebAPI

接下来,键入:dotnet run

.NET 将构建并启动 Web API。

它看起来将与以下内容类似:

get dotnet version

仅构建项目

顺便说一句,如果您只想构建项目,可以键入:dotnet build

查看 Web API 的运行效果

要查看 Web API 的运行效果,您可以按住 **CTRL** 键并单击控制台窗口中显示的链接 (https://:5001)。这样做后,您的默认浏览器将打开该链接。

但这并不怎么神奇,因为您还没有调用任何 Web API 方法。

您只会看到一个空白网页。

通过 GET 请求调用一个 Web API 方法

然而,有一个方法可以通过 `GET` 请求调用。请尝试以下 URL:https://:5001/WeatherForecast/^

这会调用 `WeatherForecastController`**\* ** 类中的默认 `Get` 方法。该方法仅生成一些随机的 `WeatherForecast`**\* ** 域对象,然后将它们作为 JSON 发送给客户端。

**\* ** 在我们查看代码时,我将很快向您展示这两个类。

您将在浏览器中看到以下两张图片中的一张(取决于您的浏览器如何渲染 JSON)。

web api json formatted

web api raw JSON

现在您已经看到了代码的运行情况,让我们来看看代码,并开始修改 `WeatherForecastController`,以便我们可以向其发布 JSON,并让它自动将 JSON 转换为域对象。

Visual Studio Code

我将在本文中全程使用 Visual Studio Code (VSC),但如果您愿意,仍然可以使用 Visual Studio。

请启动 Visual Studio Code (VSC),然后我们将打开项目。

打开文件夹

要在 VSC 中加载项目,您需要:

  1. 转到主菜单
  2. 选择 [File...] 菜单项
  3. 选择 [Open Folder...]
  4. 导航到创建项目时创建的文件夹,然后选择它。

完成这些步骤后,您将看到类似以下内容:

visual studio code

高亮区域

我在 VSC 中高亮显示了几个区域,以便我们可以讨论它们。

工具栏

第一部分是工具栏,其中包含几个图标。

文件视图

当前选中的图标以白色高亮显示,表示文件视图已显示。您可以看到第二部分中有一个文件列表。但是,如果您选择其他图标,这一部分将会改变。

调试视图

在本文中,我们还将使用调试项向您展示如何在 VSC 中逐步调试 Web API 代码。调试项由 debug icon 表示。

但是,要在 VSC 中使用调试器,您必须确保已安装并运行 C# 扩展插件。

插件视图

插件视图由 plugins icon 表示。

您可以看到,我在上面提供的 VSC 概览图中,第四部分实际上是 VSC 警告我需要将 C# 扩展插件添加到项目中才能调试代码。如果您看到此提示并单击 **[Yes]** 按钮,它将将其添加到项目中。但是,如果该扩展尚未添加到您的系统中,您可能不会看到此提示。

另外,该弹出窗口通常会很快消失。不过没关系,因为您可以随时单击插件图标将插件添加到您的系统和项目中。

安装并激活后,它的外观如下:

plugin view with C# extensions

主编辑器区域

最后,您可以看到主编辑器区域(上面 VSC 图片中的区域 3)当前显示有关 VSC 最新版本的信息。这是当您从文件查看器区域选择文件时,每个文件将在此处显示的区域。

现在您对 VSC 更加熟悉了,让我们开始查看 `WeatherForecastController`。

检查 WeatherForecastController

打开子目录中的文件

请确保您处于文件视图。接下来,在文件视图中,找到 `Controllers` 目录。它会有一个指向 Controllers 名称的向下右箭头(大于号)。这表示一个当前折叠的文件夹。单击 _Controllers_ 文件夹并选择出现的 _WeatherForecaseController.cs_,它将在编辑器区域中显示。

Controller:应用程序逻辑层

我不会解释 Controller 代码的每一个方面。您可以将 Controller 总体看作是应用程序逻辑层。以下是基本工作原理。

用户通过向服务器上的命名 Controller(由 URL 描述)发送 HTTP 命令(GET、POST、PUT 等^)来请求 Controller 上的操作(函数或方法)。
**注意**:在本文中,我们只处理 `POST` 命令。

作为开发人员,我们可以在 `Controller` 方法中编写代码来运行应用程序逻辑,从而提供特定的功能。就这么简单。

项目模板包含在 `Controller` 中的 `Get` 方法如下所示:

       [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            Console.WriteLine("in get...");
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }

这可能很明显,但 `[HttpGet]` 方法装饰器告诉编译器通过 HTTP `Get` 使此方法可用。

此方法仅生成五个 `WeatherForecast` 对象(域对象)的数组并返回它们。它们将被自动序列化为 JSON,这就是我们之前在浏览器中看到的。

我们的主要挑战

这里的挑战是如何将数据发布到 `WeatherForecast` Controller,以便它能自动反序列化为 `WeatherForecast` 对象。

首先,让我们在 Controller 中添加最基本的 `Post` 方法。

[HttpPost]
public String Post(){
    Console.WriteLine("in post...");
    return "It worked!";
}

首先,请注意我们将装饰器更改为 `[HttpPost]`,这样当用户发布到 URL https://:5001/WeatherForecast 时,此方法就会触发。

默认 Post 方法

这个内部方法名是 `Post()`,但外部没有显示动作(方法名),这意味着当用户直接发布到 `Controller` 时,这是默认的动作(方法)将会发生。

有一种方法可以提供一个外部名称,然后该名称可以包含在 `WeatherForecast` Controller URL 中,我稍后会向您展示。

次要挑战:客户端 Post 创建

现在,我们面临着测试 `WeatherForecast` Controller 上的 `Post()` 方法的挑战。由于我们不能再仅通过浏览器访问 URL(简单的 HTTP `Get`),我们需要其他方法来从客户端调用 HTTP `Post`。

第一个最简单的 Post 测试

执行 `Post` 到 Controller 的第一个也是可能是最简单的方法是下载 `PostMan` 并进行设置。还有其他工具,但 PostMan 可能是最简单的,而且是免费的。

访问 https://www.postman.com/downloads/^,获取免费工具并为您当前的系统安装它。

完成安装并启动后,我们可以尝试发布到我们的 Controller。

PostMan 请求演练

PostMan 的用户界面有点混乱,但创建新请求很容易,我将引导您完成。

创建新请求

您要做的第一件事是创建一个新请求。为此,您可以选择 [**New**] 按钮,然后在菜单出现时选择 [**Request**]。或者,您可以单击 [**Create a Request**] 选项。这两者都在下一张图片中以红色高亮显示。

postman main UI

选择其中一个选项后,您将看到一个新表单。在图片中,您可以看到我也展开了 HTTP Actions 列表,向您展示了在哪里可以选择在提交请求时使用的操作。首先,我们将尝试简单的 `Get`。

new postman request

PostMan:配置更改

但是,在发送第一个请求之前,您需要对 PostMan 的默认设置进行一项更改。如果您不这样做,那么您所有的请求都将失败,因为 PostMan 不支持自签名证书。

如果您不更改设置,您将看到类似以下的错误(请注意错误中的蓝色高亮文本)。

HTTPS:不支持自签名证书

postman error on certificate

要解决此问题,只需在 PostMan 中转到 **File**...**Settings**... 并关闭此处高亮显示的选项(此处仍显示为开启)- SSL certificate verification。

turn off certificate verification

完成此操作并关闭 **Settings** 窗口后,您可以继续操作,它将正常工作。

继续从下拉列表中选择 `Get` 命令。

接下来,添加以下 URL,然后按 **<ENTER>** 或单击 [**Send**] 按钮。

完成此操作后,您将看到与之前在浏览器中看到的结果类似的结果,只是格式化方式不同,符合 PostMan 的格式。

postman get results

请记住,这是调用 `WeatherForecast` Controller 上默认 `Get()` 操作的结果。我提到这一点是为了提醒您,我们没有在 URL 中添加任何(特定的)动作名称。

Post 到 WeatherForecastController

现在,让我们在 PostMan 中将 HTTP Verb 更改为 `Post`,然后再次尝试。

这是新的、非常基础的结果:

Post result via PostMan

这都很好,但我们想要做的是将一些 JSON 发布到 Controller,并让它自动将 JSON 转换为我们的域对象(`WeatherForecast`)。

发布 JSON:尝试 1

首先,我们需要了解目标域对象是什么样子的。它有哪些属性?

我们可以在 VSC 中查看 `WeatherForecast` 类。

WeatherForecast 类分析

这是一个非常简单的类。这是该类的完整代码列表。

using System;
 
namespace MainWebAPI
{
    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; }
    }
}

它基本上只由四个属性组成(尽管其中一个属性会运行一个函数来获取其值)。

  1. 日期
  2. TemperatureC // (摄氏温度)
  3. TemperatureF // (计算出的华氏温度)
  4. Summary // 天气文字摘要

JSON:名称/值对

既然我们知道 JSON(JavaScript Object Notation)只是定义对象的名称值对,我们就可以非常轻松地创建自己的 `WeatherForecast`(带数据)。以下是我们将在测试中使用的:

{"Date":"2015-05-03", "TemperatureC":37,"Summary":"Our weather data"}

请注意,由于 `TemperatureF` 是从 `TemperatureC` 计算出来的,我甚至没有在我们的 JSON 中包含该属性。

括号:代表对象 - 快速 JSON 摘要

以下是一种快速思考 JSON 内容的方式:花括号表示对象的开始和结束。冒号前面的每个值表示属性名,冒号后面的每个值表示属性值。每个名称/值对都用逗号分隔。每个属性名必须与目标类中的属性匹配。

就是这样,让我们在 PostMan 中尝试一下。

更改 WeatherForecastController Post 方法

我们必须对 `WeatherForecastController` 中的默认 `Post()` 方法进行一项更改。我们必须确保它能够接收一个 `WeatherForecast` 对象。

让我们在 VSC 中打开 `WeatherForecastController` 并进行更改。

我们还将方法更改为返回一个 `Int32`,并返回 `TemperatureF`,这样您就可以看到该值已生成。这也为我们提供了一个稍微可用的 Web API 方法(尽管有点牵强),因为您可以发送一个 `WeatherForecast` 对象,其中您知道摄氏温度,该方法将返回华氏温度。

以下是修改后的默认 `Post()` 方法:

[HttpPost]
public Int32 Post(WeatherForecast wf){
    Console.WriteLine("in post...");
    return wf.TemperatureF;
}

进行更改并运行

进行这些更改后,请返回控制台并:

  1. 如果程序已在运行,请关闭它(按 **CTRL-C** 结束会话)。
  2. 再次构建并运行应用程序 -- `dotnet run` 将重新构建并运行应用程序。
  3. 复制上面创建的 JSON。
  4. 回到 PostMan。
  5. 单击 [**body**] 选项卡(参见下一张图片)。
  6. 选择 [**raw**](下一张图片)单选按钮。
  7. 将 JSON 粘贴到编辑器区域。
  8. 单击 [**Send**] 按钮。

完成所有这些步骤后,您将看到以下结果(错误)。
**注意**:我使用了一张图片来显示多个步骤和结果。

postman setup and error result

错误解释

有点令人困惑,但底部部分是将 JSON 发布到 Controller 后的结果。我们没有收到预期的响应(`TemperatureF`),而是收到了一些描述问题的 JSON。
很难判断是否发生了错误以及错误发生在何处。

Post() 方法的 Console.WriteLine 没有运行

请记住,我们的默认 `WeatherForecastController` 有一个 `Console.WriteLine()` 调用,它会尝试输出一条消息。这应该会在运行应用程序的控制台窗口中输出一些文本,但如果您查看,却没有输出。这为我们提供了一个线索,说明我们的方法从未运行。

不支持的媒体类型

真正提示我们发生了什么的是错误 415 和消息“unsupported media type”。但这仍然有些晦涩,如果您刚开始学习,您会wonder这到底意味着什么。经过大量搜索和阅读后,您会发现这意味着服务器不知道我们正在向它发布什么类型的数据,它不喜欢这样。

通过 HTTP Header 修复问题

我们可以通过向我们的 `Post` 操作添加一个 HTTP Header 来告诉服务器我们发送的数据类型。

服务器希望知道您正在发送的数据类型,以便它可以正确使用这些数据。让我们将正确的 HTTP Header 添加到我们的 PostMan Post 操作中,然后再次尝试。

HTTP Headers:名称/值对

HTTP Headers 是元数据(与实际数据一起发送的数据,用于描述数据),它们与数据一起发送。要在 PostMan 的 headers 中添加一个名称/值对,我们只需要:

  1. 选择 Headers 选项卡(参见下一张图片)。
  2. 添加一个新的 header,名为:`Content-Type`(在 Key(与 Name 相同)下键入此内容)。
  3. 为添加的 Key 添加一个新值:`application/json`

这个 Key 和 Value 都是 HTTP 规范预定义的,服务器将能够理解。

adding header to PostMan

现在,当您再次发布时,服务器将理解传入的内容是 JSON,并应将其作为 JSON 处理。

进行这些更改后,请再次单击 PostMan 中的 [**Send**] 按钮,这次您将获得有效的结果。98 华氏度与 37 摄氏度(我们在 JSON 中发送到 `WeatherForecastController` 的值)是相同的温度。

TemperatureF returned successfully

您还可以看到 `WeatherForecastController` 的 `Post()` 方法确实运行了,因为在您的控制台窗口中,有来自 `Console.WriteLine()` 调用的输出。

console output

自动转换为域对象:太棒了!

另外,请思考一下 .NET Core Web API 自动将我们的 JSON 转换为我们的域对象(`WeatherForecast`)是多么的神奇。

您可以通过以下事实来判断它是自动完成的:我们的默认 `Post()` 方法只是接受一个 `WeatherForecast` 类型的参数,并且我们在 `return` 语句中引用了该对象的属性。

return wf.TemperatureF;

第一部分总结

我希望您觉得本系列文章的第一部分很有启发性,并以清晰的方式揭示了一些棘手的元素(HTTP Headers、HTTP Post 和使用 PostMan)。

但是,由于本文已经很长了,我决定将文章的其余部分放在 第二部分

现在我们明白了我们需要:

  1. JSON 数据添加到 `Post` body 中。
  2. 特殊的 `Content-Type` header 添加到 `Post` 操作中。

......这将使我们更容易理解如何使用 JavaScript 通过 AJAX(`XMLHttpRequest` 对象)将数据发布到我们的 Web API Controller。

Using the Code

  1. 下载 zip 文件。
  2. 将文件解压到您的 _Dev_ 目录(有一个名为 _MainWebAPI_ 的外层文件夹,其中包含所有文件和子文件夹)。
  3. 打开控制台并将目录更改为 _\MainWebAPI_。
  4. 运行命令 `/> dotnet run`。
  5. 应用程序将构建并启动 Web 服务器。

历史

  • 2020年5月20日:提交第一部分
© . All rights reserved.