在 .NET MAUI 应用中使用 REST Web 服务

内容纲要

介绍

许多现代应用程序利用 REST Web 服务来提供对数据或其他功能(如云存储)的访问。对于在手机和平板电脑设备上运行的移动应用程序尤其如此。大多数包含社交方面和共享媒体的应用都依赖于与这些服务的连接。如果没有连接,许多应用的功能会受到限制。它们可能仅限于在设备上本地缓存的要素。设计良好的应用可以透明地检测网络连接是否可用,并相应地调整其功能集。

想象一下,您是一家电力公用事业公司的开发人员。您正在创建一个应用程序,工程师在访问客户站点以执行日常维护时可以使用该应用程序。在现场访问期间,工程师可能需要订购更换部件。该应用程序的一部分应该使工程师能够快速查找零件的详细信息。您的公司以前构建了一个 REST Web 服务,该服务提供有关电气组件和部件的信息。此 Web 服务在 Azure 中运行。应用必须能够连接到此 Web 服务才能检索有关部件的信息。

在本模块中,您将构建一个使用 REST Web 服务中的数据的 .NET MAUI 应用程序。您将首先确定您的设备是否已连接到互联网,并且仅在您具有活动连接时才尝试与 Web 服务进行通信。然后,您将使用 HttpClient 在托管的 REST Web 服务上执行基本的 CRUD 操作。最后,您将在每台设备上配置本机网络堆栈,以实现应用程序和 Web 服务之间的安全通信。

学习目标

在本模块中,您将学习如何:

  • 检测您的设备是否已连接到互联网
  • 使用 HttpClient 使用 REST Web 服务
  • 使用平台的本机网络功能配置客户端网络安全

先决条件

  • Visual Studio 2022 with .NET MAUI workload
  • 熟悉 C# 和 .NET
  • REST 基础知识

检测网络连接

移动设备使用 Wi-Fi 和蜂窝技术连接到互联网。这种依赖关系意味着您的用户在使用您的应用程序时可能会失去其互联网连接。如果你不添加代码来防止这种可能性,你的应用可能会停止响应,并为用户提供糟糕的体验。

在本单元中,您将通过检测用户何时失去互联网连接来保护您的应用程序。当我们开始使用 REST Web 服务时,此信息变得很重要。

为什么要在移动应用程序上检测网络连接?

检测您在移动应用程序上是否有 Internet 连接非常重要,因为移动设备经常会失去连接。这可能是由于网络服务提供商的覆盖范围较差,或者处于接收有限或没有接收的环境中,例如隧道,深谷或高山。还有不同类型的网络连接。如果您位于提供 WiFi 连接的环境中,则通常比依赖蜂窝网络访问时具有更高的带宽。您可能仍然可以连接到互联网,但与WiFi连接相比,某些操作(例如流式传输视频内容)通过蜂窝链路可能会非常慢(且昂贵)。

由于移动设备具有这些挑战,因此必须编写代码来防范这些挑战。如果不这样做,并且您的应用程序尝试执行使用 Internet 的操作,则应用程序可能会停止响应。

您还希望在应用程序无法连接到 Internet 时提供良好的用户体验。如果您的应用程序因没有 Internet 服务而停止工作,您的用户可能会感到困惑。最好的办法是向用户提供信息。告诉他们您没有 Internet 连接,并且没有 Internet 连接,您的应用程序可能无法完全执行。下图显示了一个示例:

在此示例中,应用程序开发人员通知用户他们没有 Internet 连接,他们应该尝试连接到 Wi-Fi。

检测网络连接

若要检查 .NET MAUI 应用中的网络连接,请使用该类。此类公开一个名为 的属性和一个名为 的事件。您可以使用这些成员来检测网络中的更改。ConnectivityNetworkAccessConnectivityChanged

您可以通过另一个名为 的属性访问该属性。这是访问特定于平台的实现所需的机制。NetworkAccessCurrentConnectivity

该属性从枚举中返回一个值。枚举有五个值:、、、和 。如果该属性返回值 ,则您知道您没有连接到 Internet,并且不应运行网络代码。此机制可跨平台移植。以下代码显示了一个示例:NetworkAccessNetworkAccessConstrainedInternetInternetLocalNoneUnknownNetworkAccessNetworkAccess.None

if (Connectivity.Current.NetworkAccess == NetworkAccess.None)
{
    ...
}

该事件还使您能够确定设备是否已连接到互联网。当网络状态更改时,将自动触发该事件。例如,如果从活动网络连接开始,但最终丢失了该网络连接,则会引发该事件以通知您有关更改的信息。传递给事件处理程序的参数之一是对象。此对象包含一个名为 的属性。您可以使用该属性来确定您是否已连接到互联网。下面是一个示例:ConnectivityChangedConnectivityChangedConnectivityChangedConnectivityChangedConnectivityChangedEventArgsIsConnectedIsConnected

Connectivity.Current.ConnectivityChanged += Connectivity_ConnectivityChanged;
...
void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs  e)
{
    bool stillConnected = e.IsConnected;
}

该事件使你能够编写可检测网络状态更改的应用,并根据不同的环境无缝调整可用的功能。ConnectivityChanged

使用 HttpClient 的 REST 服务

许多现代 Web 服务都实现了 REST 体系结构。此结构使 Web 服务能够通过一系列明确定义的终结点公开操作和数据。客户端应用发送到 REST Web 服务以检索、修改、创建或删除数据的请求使用一组预定义的谓词。REST Web 服务以标准方式响应这些请求。此方法使构造客户端应用变得更加容易。

REST 模型构建在 HTTP 协议之上。.NET MAUI 应用程序可以使用该类向 REST Web 服务发送请求。在本单元中,您将了解 ,以及如何使用它与 REST Web 服务进行交互。HttpClientHttpClient

什么是 HttpClient 类?

HttpClient是一个 .NET 类,应用可以使用该类发送 HTTP 请求并从 REST Web 服务接收 HTTP 响应。Web 服务公开的资源由一组 URI 标识。URI 将 Web 服务的地址与该地址上可用资源的名称相结合。

该类使用基于任务的 API 来提高性能,并允许您访问请求消息中的信息,例如 HTTP 标头、状态代码以及包含正在发送和接收的实际数据的消息正文。HttpClient

该类在命名空间中可用。应用可以使用默认构造函数创建对象:HttpClientSystem.Net.HttpHttpClient

using System.Net.Http;
...

var client = new HttpClient();

使用 HttpClient 对象执行 CRUD 操作

REST Web 服务使客户端能够通过一组 HTTP 谓词对数据执行操作。HTTP 谓词的工作是指示要对资源执行的所需操作。有许多 HTTP 动词,但最常见的四个是 、 、 和 。服务可以实现这些谓词,使客户端应用程序能够通过执行创建、读取、更新和删除 (CRUD) 操作来管理对象的生命周期,如下所示:POSTGETPUTDELETE

  • 谓词指示您要创建新资源。POST
  • 谓词指示您要检索资源。GET
  • 谓词指示您要更新资源。PUT
  • 谓词指示您要删除资源。DELETE

使用 HttpClient 创建新资源

若要使用 创建新资源,可以使用向其传递对象的方法。HttpClientSendAsyncHttpRequestMessage

旨在对发送到 Web 服务的请求进行建模。指定 HTTP 谓词(Web 服务的 URL),并填充要通过该属性发送的任何负载。HttpRequestMessageHttpRequestMessage.Content

HttpClient client = new HttpClient();

HttpRequestMessage message = new HttpMessage(HttpMethod.Post, url);
message.Content = JsonContent.Create<Part>(part);

HttpResponseMessage response = await client.SendAsync(message);

此代码段执行以下任务:

  • 它创建用于发送消息的被调用客户端的实例。HttpClient
  • 它创建一个用于对消息进行建模的被调用消息的实例。该消息具有 HTTP 谓词和 URL。HttpMessage
  • 它使用函数设置 的属性。该函数会自动将部件变量序列化为适合发送到 Web 服务的 JSON。ContentHttpMessageJsonContent.Create
  • 它使用对象发送消息。返回的 包含诸如状态代码和 Web 服务返回的信息之类的信息。HttpClientHttpResponseMessage

使用 HttpClient 读取资源

您可以使用与上面相同的技术从 Web 服务读取资源,除了使用 .但是,'HttpClient有几种提供快捷方式的便捷方法。HttpRequestMessageHttpMethod.Get

要使用 读取资源,请使用下一个示例中所示的方法:HTTPClientGetStringAsync

HttpClient client = new HttpClient();

string text = await client.GetStringAsync("https://...");

该方法采用引用资源的 URI,并以字符串形式返回响应。字符串响应是应用请求的资源。响应数据的格式将是所请求服务的默认格式,例如 JSON 或 XML。应用可以通过添加标头来告知 Web 服务它需要以特定格式返回数据。例如,如果应用请求以 JSON 格式发回数据,则可以使用以下代码:GetStringAsyncMediaTypeWithQualityHeaderValue

HttpClient client = new HttpClient();

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

在此示例中,结果以字符串形式返回,并且仅包含响应消息正文。若要获取整个响应(包括标头、正文和状态代码),请调用该方法。数据作为对象返回。GetAsyncHttpResponseMessage

使用 HttpClient 更新资源

要使用 更新资源,请使用带有 PUT 谓词的初始化。以下代码类似于创建新资源所需的代码:HttpClientHttpRequestMessage

HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Put, url);

message.Content = JsonContent.Create<Part>(part);

HttpResponseMessage response = await client.SendAsync(message);

备注

和 之间的根本区别是幂等性。如果多次重复同一请求,则将使用相同的数据更新同一资源,并且效果与仅发送一次请求时相同。如果多次发出同一请求,则结果将是 REST 服务创建的资源的多个副本。POSTPUTPUTPOST

使用 HttpClient 删除资源

要使用 删除资源,请使用 DELETE 谓词初始化的HttpClientSendAsyncHttpRequestMessage

HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Delete, url);

HttpResponseMessage response = await client.SendAsync(url);

响应包含标头、状态代码和已删除的对象。

处理来自请求的响应

所有 HTTP 请求都返回响应消息。响应中的数据取决于应用发送的谓词。例如,HTTP 请求的响应正文包含所请求资源的数据。GET

响应正文请求返回已创建资源的副本,但请求的响应正文应为空。POSTPUT

应始终检查并处理响应消息中的状态代码。如果此状态代码在 200 范围内(200、201、202 等),则操作被视为已成功,尽管以后可能需要进一步的信息。

300 范围内的状态代码表示请求可能已被 Web 服务重定向到其他地址,这可能是由于资源移动到其他位置的结果。

400 范围内的状态代码表示客户端或应用程序错误。例如,状态代码 403 表示 Web 服务要求用户进行身份验证,但应用尚未执行此操作。当应用尝试访问不存在的资源时,将发生状态代码 404。

500 范围内的状态代码表示服务器端错误,例如服务不可用或太忙而无法处理请求。

通过对象提交的请求返回的对象可以抽象出处理不同状态代码的大部分复杂性。此代码段演示如何验证响应消息中的状态代码是否指示成功,并处理指示某种失败的状态代码。HttpResponseMessageHttpClient

static readonly HttpClient client = new HttpClient();

...
// Call asynchronous network methods in a try/catch block to handle exceptions.
try
{
    //... Initiate the HttpRequest

    HttpResponseMessage response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode(); // Check that the status code is in the 200 range. Throw an HttpRequestException if not
    
    string responseBody = await response.Content.ReadAsStringAsync();
    
    ... // Handle the response
}
catch(HttpRequestException e)
{
    ... // Handle any status codes that indicate an error. 
        // The status code is available in the field e.StatusCode
}

使用特定于平台的网络功能

提供与网络的连接的抽象。使用此类的应用独立于本机平台网络堆栈。.NET MAUI 模板将 HttpClient 类映射到利用每个平台的本机网络堆栈的代码。这使应用程序能够利用特定于平台的网络配置和优化功能。当您需要将客户端应用程序配置为安全地连接到 REST Web 服务时,这一点尤其重要。

在本单元中,你将了解如何配置 HTTP 客户端应用程序以使用基础平台提供的网络保护功能。

在 iOS 上配置应用程序传输安全性

应用传输安全 (ATS) 是一项 iOS 功能,它要求通过本机 HTTP 网络堆栈完成的每个网络通信都使用 TLS 1.2 或更高版本。如果其中一个长期密钥泄露,现代加密算法不会泄露信息。

如果你的应用不遵守这些规则,它将被拒绝访问网络。要解决此问题,您有两种选择;你可以更改终结点以符合应用传输安全策略,也可以选择退出应用传输安全。

若要选择退出应用传输安全,请向 Info.plist 文件添加一个名为 的新密钥。您将在解决方案资源管理器中项目的“平台”文件夹中的 iOS 文件夹下找到 Info.plist 文件。这个键实际上是一个字典。将调用的另一个键添加到此字典中。此密钥包含要作为目标的每个终结点的子项。每个终结点都可以有自己的配置,指定允许或禁止哪些功能。可以使用 Visual Studio 中的通用 plist 编辑器添加此注册表项,也可以将其作为 XML 文件打开。NSAppTransportSecurityNSExceptionDomains

下面是一个以 XML 形式显示的终结点的示例配置:

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSExceptionDomains</key>
      <dict>
      <key>dotnet.microsoft.com</key>
      <dict>
        <key>NSExceptionMinimumTLSVersion</key>
        <string>TLSv1.0</string>
        <key>NSExceptionAllowsInsecureHTTPLoads</key>
        <true/>
      </dict>
   </dict>
</dict>

此示例在 dotnet.microsoft.com 向终结点添加一个异常。如果要在开发计算机上本地调试服务,则可以使用密钥为本地流量选择退出应用传输安全,如下所示:NSAllowsLocalNetworking

<key>NSAppTransportSecurity</key>    
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

如果无法识别所有终结点,请使用以下项为所有未指定的终结点禁用应用传输安全:NSAllowsArbitraryLoads

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSAllowsArbitraryLoads</key>
   <true/>
</dict>

您还可以添加其他选项,以更具体地说明您希望如何选择退出。进一步的指导不在本模块的范围之内。

配置安卓网络安全

与iOS一样,Android在网络通信方面也有类似的安全模型。此模型是在 Android 9(API 级别 28)中引入的。默认情况下,当您的应用定位到 Android 9(API 级别 28)或更高版本时,明文(非 HTTPS)流量处于停用状态。如果你的应用需要在尚未针对 HTTPS 配置的服务器上下载映像或文件,则此策略可能会影响你的开发周期。此外,您可能只是尝试在本地调试应用程序,而不想安装开发证书。您可能有强烈的业务需求,即所有版本的Android上的所有网络流量始终是HTTPS。借助 Android 的网络安全配置功能,您可以微调应用中的网络流量安全性。

允许明文流量

若要允许明文通信,请在 Resources/xml 文件夹下创建一个名为 network_security_config.xml 的新 AML 文件(您可能还需要创建 xml 文件夹)。“资源”文件夹位于“解决方案资源管理器”中的“Android 平台”文件夹下。在此文件中,添加一个包含子元素的元素。以下配置为特定域和 IP 地址启用明文流量:network-security-configdomain-config

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain> <!-- Debug port -->
    <domain includeSubdomains="true">microsoft.com</domain>
  </domain-config>
</network-security-config>

您可以通过限制所有版本的 Android 上的明文流量来增强应用的安全性,而不管目标框架如何。这是通过将元素的属性设置为 来实现的。此配置设置会阻止所有非 HTTPS 流量。cleartextTrafficPermitteddomain-configfalse

要使应用识别network_security_config.xml文件,请为位于“属性”文件夹中的 AndroidManifest.xml中的节点配置属性:networkSecurityConfigapplication

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application android:networkSecurityConfig="@xml/network_security_config" ...></application>
</manifest>

如果需要更具体地说明如何选择退出传输安全,则可以指定其他选项。

在本地调试应用

使用Visual Studio构建移动应用程序的一个重要好处是能够使用iOS模拟器或Android模拟器运行和调试移动应用程序。这些应用可以使用在本地运行并通过 HTTP 公开 ASP.NET 核心 Web 服务。

在 iOS 模拟器中运行的应用程序可以使用计算机的 IP 地址或通过本地主机主机名连接到本地 HTTP Web 服务。应用程序必须选择退出 ATS,并指定最小值 。例如,给定一个通过 /api/todoitems/ 相对 URI 公开操作的本地 HTTP Web 服务,在 iOS 模拟器中运行的应用程序可以通过向 http://localhost:<port>/api/todoitems/ 发送请求来使用该操作。NSAllowsLocalNetworkingGETGET

在 Android 模拟器中运行的应用程序可以通过 10.0.2.2 地址连接到本地 HTTP Web 服务。此地址是主机环回接口的别名(在开发计算机上为 127.0.0.1)。还必须为此特定 IP 地址设置网络安全配置。例如,给定一个通过 /api/todoitems/ 相对 URI 公开操作的本地 HTTP Web 服务,在 Android 模拟器中运行的应用程序可以通过向 http://10.0.2.2:/api/todoitems/ 发送请求来使用该操作。GETGET

备注

ASP.NET 在本地主机上运行的受测核心 Web 服务必须通过注释掉 Startup.cs 文件中的语句来禁用 HTTPS 重定向。app.UseHttpsRedirection();

检测操作系统

应用可以使用该类确定它在哪个平台上运行。在以下示例中,应用程序将 BaseAddress 变量设置为其他值,具体取决于它是否在 Android 上运行:DeviceInfo

public static string BaseAddress = DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

练习 - 使用 HttpClient 的 REST 服务

必须使用沙盒,才能完成此模块。通过使用沙盒,可访问免费资源。个人订阅将不会收费。沙盒仅限用于在 Microsoft Learn 上完成培训。禁止将沙盒用于任何其他目的,否则可能会导致永远无法使用沙盒。

Microsoft 出于教育目的提供此实验室体验和相关内容。提供的所有信息均归 Microsoft 所有,仅用于学习本 Microsoft Learn 模块中涵盖的产品和服务。

登录以激活沙盒

作为工程师在客户现场访问时使用的应用程序的一部分,您需要添加一项功能,使工程师能够查找电气元件的详细信息。此信息将保存在数据库中,并通过 REST Web 服务进行访问。还要求您提供一个界面,使管理员能够使用相同的 REST Web 服务创建、删除和修改数据库中保存的部件的详细信息。

在本练习中,你将把 REST Web 服务部署到 Azure,然后验证是否可以使用 Web 浏览器访问它。然后,您将向使用 REST Web 服务检索、添加、删除和更新电气元件详细信息的现有应用程序添加功能。

你将使用 Azure 沙盒执行本练习。

提示

可以使用“复制”按钮将命令复制到剪贴板。要粘贴,请右键单击 Cloud Shell 窗口中的新行,然后选择“粘贴”,或使用键盘快捷键(在 macOS 上)。Shift+Insert⌘+V

部署部件 REST Web 服务

在 Cloud Shell 窗口中,运行以下命令以克隆包含本练习代码的存储库,包括部件 REST Web 服务:

git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services

移动到“使用-REST-服务”文件夹

cd mslearn-dotnetmaui-consume-rest-services/src

运行所示的命令,使用 Azure 云外壳沙盒部署部件 Web 服务。此命令使服务通过唯一的 URL 可用。在显示此 URL 时记下它。你将应用配置为使用此 URL 连接到 Web 服务。

bash initenvironment.sh

检查 Web 服务的代码

备注

你将在本地开发计算机上执行本练习的其余部分。

  1. 在台式计算机上,打开命令提示符窗口并克隆存储库以进行本练习。代码位于 net-maui-learn-consume-rest-services 存储库中。git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
  2. 移动到存储库克隆中的 Webservice\PartsServer 文件夹,然后使用 Visual Studio 打开 PartsServer.sln解决方案。此解决方案包含上一过程中部署到 Azure 的 Web 服务的代码副本。
  3. 在“解决方案资源管理器”窗口中,展开“模型”文件夹。此文件夹包含两个文件:
    • 部件.cs。 部件类表示 REST Web 服务提供的部件。这些字段包括部件 ID、部件名称、部件类型、供货日期(首次供应部件的时间)和供应商列表。Href 属性返回部件的相对 URI;REST 客户端可以使用此 URI 在 REST Web 服务中引用此特定部分。Supplier 属性以字符串形式返回部件的供应商列表。
    • PartsFactory.cs。 PartsFactory 类使用一小组硬编码值初始化服务提供的部分列表。在现实世界中,这些数据将从数据库中检索。
  4. 在“解决方案资源管理器”窗口中,展开“控制器”文件夹。此文件夹包含以下文件:
    • 部件控制器.cs。 部件控制器类实现服务的 Web API。它包括使客户端应用程序能够检索所有部件的列表 (Get)、在给定部件 ID 的情况下查找特定部件的详细信息(Get 的重载版本)、更新部件的详细信息(Put)、将新部件添加到列表 (Post) 以及从列表中删除部件 (Delete) 的方法。
    • LoginController.cs。 LoginController 类为 Web 服务实现一种简单形式的身份验证。应用必须向此控制器发送 HTTP GET 请求,该控制器返回授权令牌。此授权令牌用于对发送到部件控制器的请求进行身份验证。
    • BaseController.csBaseController 类包含用于对请求进行身份验证的逻辑。从此类继承。如果客户端尝试在不提供有效身份验证令牌的情况下调用 PartsController 类中的方法,则这些方法将返回 HTTP 401(未经授权)响应。

检查 .NET MAUI 客户端应用的代码

  1. 在 Visual Studio 中,关闭 PartsServer 解决方案,然后在克隆的存储库中的 src\client 文件夹下打开 PartsClient 解决方案。此解决方案包含使用部件服务器 Web 服务的 .NET MAUI 客户端应用的部分实现。
  2. 在“解决方案资源管理器”窗口中,展开“数据”。此文件夹包含两个类的代码:
    • PartsManager.cs。 PartsManager 类提供客户端应用程序用于与 REST Web 服务交互的方法。此类当前不完整。在本练习中,您将添加必要的代码。完成后,GetClient 方法将连接到 REST Web 服务。方法从 REST Web 服务返回部件列表。Add 方法将新部件添加到由 REST Web 服务管理的部件列表中。Update 方法修改了 REST Web 服务存储的部件的详细信息,Delete 方法删除了部件。
    • 部件.cs。 部件类对存储在数据库中的部件进行建模。它公开了应用程序可用于访问 PartID、PartNamePartAvailableDatePartType 和 PartSuppliers 字段的属性。 该类还提供了一个名为 SupplierString 的实用工具方法,应用程序可以使用该方法检索包含供应商名称的格式化字符串。
  3. 在“解决方案资源管理器”窗口中,展开“页面”文件夹。此文件夹包含两个页面的标记和代码:
    • PartsPage.xaml。此页面使用带有数据模板的 CollectionView 布局来显示可用部件的详细信息作为列表。数据模板使用数据绑定将显示的数据连接到从 Web 服务检索到的部分。您可以在“集合视图”中选择一行,以编辑“添加部分”页面中的部件。或者,您可以选择“添加新部件”按钮以添加新部件。
    • AddPartPage.xaml。使用此页,用户可以输入和保存新部件的详细信息。用户可以指定部件名称、部件类型和初始供应商。将自动生成部件 ID 和部件可用日期。
  4. 在“解决方案资源管理器”窗口中,展开“ViewModels”文件夹。此文件夹包含 2 个类 AddPartViewModel.cs 和 PartsViewModel.cs。这些是其各自页面的视图模型,包含页面显示和操作数据所需的属性和逻辑。

登录到服务

REST 服务要求您先登录才能获取授权令牌。没有用户身份验证。首先调用特定终结点以获取授权令牌。然后,在 HTTP 标头中的每个后续请求中将令牌发送回服务器。

打开“数据”文件夹中的“部件管理器.cs”文件。

将以下代码段中定义的 BaseAddress 和 Url 静态字段添加到 PartsManager 类中。将文本 URL GO HERE 替换为您之前记下的 REST Web 服务的 URL:

public class PartsManager { static readonly string BaseAddress = "URL GOES HERE"; static readonly string Url = $"{BaseAddress}/api/"; ...

将以下字段添加到类中,位于 Url 字段之后。此字段将保存用户登录时返回的授权令牌:

private static string authorizationKey;

找到 GetClient 方法。此方法当前引发 NotImplementedException 异常。将此方法中的现有代码替换为以下代码。此代码创建一个 HttpClient 对象,然后将请求发送到 REST Web 服务的登录终结点。服务应使用包含授权令牌的消息进行响应。反序列化此令牌,并将其添加为使用 HttpClient 对象发送的后续请求的默认授权请求标头:

private static async Task<HttpClient> GetClient()
{
    if (client != null)
        return client;

    client = new HttpClient();

    if (string.IsNullOrEmpty(authorizationKey))
    {                
        authorizationKey = await client.GetStringAsync($"{Url}login");
        authorizationKey = JsonConvert.DeserializeObject<string>(authorizationKey);
    }

    client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
    client.DefaultRequestHeaders.Add("Accept", "application/json");

    return client;
}

执行 GET 操作以检索部件信息

在 PartsManager.cs 文件中,找到 GetAll 方法。这是一个异步方法,它返回可枚举的部件列表。此方法尚未实现。

在此方法中,删除引发 NotImplementedException 异常的代码。

使用该类检查设备是否具有 Internet 连接。如果互联网不存在,请返回空的 .ConnectivityList<Part>

if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return new List<Part>();

调用 GetClient 方法以检索要使用的 HttpClient 对象。请记住,GetClient 是异步的,因此请使用 await 运算符来捕获此方法返回的对象。

调用 HttpClient 对象的 GetStringAsync 方法,并提供基 URL 以从 REST Web 服务中检索部件数组。数据以 JSON 字符串的形式异步返回。

使用 JsonConvert.Deserialize 方法将此方法返回的 JSON 字符串反序列化为部件对象列表。将此列表返回给调用方。完成的方法应如下所示:

public static async Task<IEnumerable<Part>> GetAll()
{
    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new List<Part>();

    HttpClient client = await GetClient();
    string result = await client.GetStringAsync($"{Url}parts");

    return JsonConvert.DeserializeObject<List<Part>>(result);                       
}

生成并运行应用。当应用程序启动时,将出现“部件列表”页面,并且应显示 GetAll 方法检索到的部件列表。您可以在列表中上下滚动。下图显示了在 Android 上运行的应用:

浏览完数据后,关闭应用并返回到 Visual Studio。

执行 POST 操作以将新部件添加到数据库中

在 PartManager 类中,找到 Add 方法。此方法具有部件名称、供应商和部件类型的参数。该方法是异步的。此方法的目的是将新部件插入到数据库中,并返回表示新创建的项的 Part 对象。

删除方法中的现有代码。

使用该类检查设备是否具有 Internet 连接。如果互联网不存在,请返回空的 .ConnectivityPart

if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return new Part();

创建新的部件对象。使用传入的数据填充字段:

将 PartID 字段设置为空字符串。此 ID 将由 REST Web 服务生成。

创建一个新列表以保存供应商的名称。

将“PartAvailableDate”字段设置为 DateTime.Now

从 GetClient 方法获取 HTTP 客户端。

Part part = new Part() { PartName = partName, Suppliers = new List<string>(new[] { supplier }), PartID = string.Empty, PartType = partType, PartAvailableDate = DateTime.Now.Date };

调用 GetClient 方法以检索要使用的 HttpClient 对象。

创建对象。此对象用于对发送到 Web 服务的请求进行建模。使用指示要使用的 HTTP 谓词和要与之通信的 Web 服务的 URL 的参数启动它。HttpRequestMessage

var msg = new HttpRequestMessage(HttpMethod.Post, $"{Url}parts");

您需要将有效负载发送到 Web 服务,其中包含要创建的部件信息。此负载将序列化为 JSON。JSON 负载将添加到属性中,并使用该方法进行序列化。HttpRequestMessage.ContentJsonContent.Create

msg.Content = JsonContent.Create<Part>(part);

现在,将消息发送到具有该函数的 Web 服务。该函数将返回一个对象,该对象保存有关服务器上的操作的信息。例如,HTTP 响应代码和从服务器传回的信息。HttpClient.SendAsyncHttpResponseMessage

var response = await client.SendAsync(msg); 
response.EnsureSuccessStatusCode(); 

请注意,上述内容使用该方法。如果返回 2xx HTTP 状态代码以外的任何内容,这将引发错误。response.EnsureSuccessStatusCode

如果 Web 服务返回信息(如 JSON 中序列化的对象),则可以从 中读取该信息。然后,您可以使用 反序列化 JSON。HttpResponseMessageJsonConvert.DeserializeObject

var returnedJson = await response.Content.ReadAsStringAsync(); 
var insertedPart = JsonConvert.DeserializeObject<Part>(returnedJson);

最后,返回新插入的零件

生成并运行应用。选择“添加新部件”按钮,然后输入名称、类型和供应商以创建新部件。选择“保存”。将调用 PartsManager 类中的 Add 方法,这将在 Web 服务中创建新部件。如果操作成功,部件列表页面将重新出现,新部件位于列表底部。

浏览完数据后,关闭应用并返回到 Visual Studio。

执行 PUT 操作以更新数据库中部件的详细信息

部件管理器类中,找到 Update 方法。这是一个将 Part 对象作为参数的异步方法。该方法没有显式返回值。但是,返回类型为 Task,以便将异常正确返回给调用方。让我们实现 PUT 功能。

删除现有代码。

和以前一样,检查互联网连接。

if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return;

创建一个新的 ,这次指定一个 PUT 操作和用于更新部件的 URL。HttpRequestMessage

HttpRequestMessage msg = new(HttpMethod.Put, $"{Url}parts/{part.PartID}");

设置 using 函数的属性和传递到函数中的 part 参数。ContentHttpRequestMessageJsonContent.Create

msg.Content = JsonContent.Create<Part>(part);

从 GetClient 方法获取 HTTP 客户端。

HttpClient client = await GetClient();

将请求与 一起发送,然后确保它已成功。HttpClient

var response = await client.SendAsync(msg); response.EnsureSuccessStatusCode();

生成并运行应用。点击或单击列表中的某个部件。将出现“添加部件”页面,这次将填充属性。更新您想要的任何内容。

选择“保存”。这将调用部件管理器类中的 Update 方法,以将更改发送到 Web 服务。如果成功,部件列表页面将重新出现,您的更改将反映出来。

 

备注

在上一个任务中添加的部件将不会显示在“部件列表”页面上。每次运行应用时,应用使用的数据都会重置为预定义部件的列表。这是为了提供测试应用的一致性。

执行 DELETE 操作以从数据库中删除部件的详细信息

在 PartManager 类中,找到 Delete 方法。这是一个异步方法,它采用 partId 字符串并返回 Task

删除现有代码。

检查互联网连接。

if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return;

创建一个新对象。现在才指定 DELETE HTTP 谓词和 URL 以删除部件。HttpRequestMessage

HttpRequestMessage msg = new(HttpMethod.Delete, $"{Url}parts/{partID}");

从 GetClient 方法获取 HTTP 客户端。

HttpClient client = await GetClient();

将请求发送到 Web 服务。返回后检查是否成功。

var response = await client.SendAsync(msg); 
response.EnsureSuccessStatusCode();

生成并运行应用。从列表中选择一个部件,然后在“添加部件”页面中,选择“删除”。如果成功,“部件列表”页面将重新出现,并且您删除的部件将不再可见。

总结

许多现代应用程序利用 REST Web 服务来提供对数据或其他功能(如云存储)的访问。

在 .NET MAUI 中,您可以使用 HttpClient 使用 REST Web 服务并执行 CRUD 操作。.NET MAUI 还具有 API,可用于检测您是否具有有效的 Internet 连接。此信息非常重要,因为如果您运行在没有网络连接的情况下使用 Internet 的代码,则应用程序可能会停止响应。最后,iOS 和 Android 都有本机网络堆栈,您可以配置这些堆栈,以确保您的应用以安全的方式连接。

在本模块中,您了解了如何使用从 .NET MAUI 应用连接到互联网并使用 REST Web 服务。具体而言,您学习了如何:

  • 检测您的设备是否已连接到互联网
  • 使用 HttpClient 使用 REST Web 服务
  • 使用平台的本机网络功能配置客户端网络安全

给TA打赏
共{{data.count}}人
人已打赏
.NET MAUI

使用 .NET MAUI 创建跨平台应用

2022-6-23 19:03:31

.NET MAUI

在 .NET MAUI 应用中使用 SQLite 存储本地数据

2022-6-27 19:58:19

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索