練習 - 使用 HttpClient 取用 REST 服務
做為工程師在造訪客戶網站時使用的應用程式一部分,您需要新增可讓工程師查閱電器元件詳細資料的功能。 此資訊會保留在資料庫中,並透過 REST Web 服務存取。 系統也已要求您提供介面,讓管理員可以使用相同的 REST Web 服務,來建立、移除和修改資料庫中所保留部分的詳細資料。
在此練習中,您會將 REST Web 服務部署至 Azure,然後驗證您是否可以使用網頁瀏覽器存取該服務。 接著,您將新增功能至現有應用程式,此應用程式會使用 REST Web 服務來擷取、新增、刪除和更新電器元件的詳細資料。
您將使用 Azure 沙箱來執行此練習。
提示
您可以使用 [複製] 按鈕將命令複製到剪貼簿。 要貼上命令,請在 Cloud Shell 終端中,以滑鼠右鍵按一下新行,然後選取 [貼上],或使用 Shift+Insert 鍵盤快速鍵 (在 macOS 上為 ⌘+V)。
部署 Parts REST Web 服務
在 Cloud Shell 視窗中,執行下列命令以複製存放庫,其中包含此練習的程式碼,包括 Parts REST Web 服務:
git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
移至 Consume-REST-services 資料夾:
cd mslearn-dotnetmaui-consume-rest-services/src
執行下列命令,以使用 Azure Cloud Shell 沙箱部署 Parts Web 服務。 此命令可讓服務透過唯一 URL 使用。 在此 URL 顯示時,請將其記下。 您將設定應用程式,以使用此 URL 連線至 Web 服務。
bash initenvironment.sh
檢查 Web 服務的程式碼
注意
您將在本機開發電腦上執行此練習的其餘部分。
在電腦上,開啟命令提示字元視窗,並複製此練習的存放庫。 程式碼位於 net-maui-learn-consume-rest-services 存放庫中。
git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
注意
最好將練習內容複製或下載至簡短的資料夾路徑,例如 C:\dev,以避免組建產生的檔案超過最大路徑長度。
在您複製的存放庫中,前往 src\webservice\PartsServer 資料夾,然後使用 Visual Studio 或 Visual Studio Code 中的資料夾開啟 PartsServer.sln 解決方案。 此解決方案包含 Web 服務的程式碼複本,而您已在上一個程序中將此 Web 服務部署至 Azure。
在 [方案總管] 視窗中,展開 Models 資料夾。 此資料夾包含兩個檔案:
Part.cs。 Part 類別代表 REST Web 服務提供的組件。 欄位包含組件識別碼、組件名稱、組件類型、可用性日期 (第一次提供組件時),以及供應商清單。 Href 屬性會傳回組件的相對 URI;REST 用戶端可以使用此 URI,在 REST Web 服務中參照此特定組件。 Suppliers 屬性會以字串的形式傳回該組件的供應商清單。
PartsFactory.cs。 PartsFactory 類別會使用小型的一組硬式編碼值,來初始化服務所提供的組件清單。 在現實世界中,系統會從資料庫擷取此資料。
在 [方案總管] 視窗中,展開 Controllers 資料夾。 此資料夾包含下列檔案:
PartsController.cs。 PartsController 類別會實作服務的 Web API。 其包含的方法可讓用戶端應用程式擷取所有組件的清單 (Get)、鑒於組件識別碼尋找特定組件的詳細資料 (Get 的多載版本)、更新組件的詳細資料 (Put)、新增組件至清單 (Post),以及從清單中移除組件 (Delete)。
LoginController.cs。 LoginController 類別會針對 Web 服務實作簡單的驗證形式。 應用程式必須將 HTTP GET 要求傳送至這個控制器,其會傳回授權權杖。 此授權權杖是用來驗證傳送至 PartsController 的要求。
BaseController.cs。 BaseController 類別包含用來驗證要求的邏輯。 PartsController 類別繼承自這個類別。 如果用戶端嘗試呼叫 PartsController 類別中的方法,而未提供有效的驗證權杖,則這些方法會傳回 HTTP 401 (未經授權) 回應。
檢查 .NET MAUI 用戶端應用程式的程式碼
本課程模組使用 .NET 8.0 SDK。 確認您已在慣用的命令終端中執行下列命令來安裝 .NET 8.0:
dotnet --list-sdks
類似下列範例的輸出隨即出現:
6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]
確定已列出開頭為 8
的版本。 如果未列出任何項目或找不到命令,請安裝最新的 .NET 8.0 SDK。
關閉 PartsServer 解決方案,然後在複製的存放庫中,開啟 src\client\PartsClient 資料夾中的 PartsClient 解決方案。 此解決方案包含 .NET MAUI 用戶端應用程式的部分實作,而此應用程式使用了 PartsServer Web 服務。
在 [方案總管] 視窗中,展開 Data 資料夾。 此資料夾包含兩個類別的代碼:
PartsManager.cs。 PartsManager 類別提供用戶端應用程式用來與 REST Web 服務互動的方法。 此類別目前並未完成;您將在此練習期間新增必要的程式碼。 完成時,GetClient 方法會連線至 REST Web 服務。 GetAll 方法會傳回 REST Web 服務的組件清單。 Add 方法會新增組件至 REST Web 服務所管理的組件清單。 Update 方法會修改 REST Web 服務所儲存組件的詳細資料,而 Delete 方法會移除組件。
Part.cs。 Part 類別會將資料庫中儲存的組件製成模型。 其會公開應用程式可以用來存取 PartID、PartName、PartAvailableDate、PartType 和 PartSuppliers 欄位的屬性。 此類別也提供名為 SupplierString 的公用程式方法,應用程式可以將其用來擷取格式化的字串,其中包含供應商名稱。
在 [方案總管] 視窗中,展開 Pages 資料夾。 此資料夾包含兩個頁面的標記和程式碼:
PartsPage.xaml。 此頁面搭配 DataTemplate 使用 CollectionView 配置,將可用組件的詳細資料顯示為清單。 DataTemplate 會使用資料繫結,將顯示的資料連線到從 Web 服務擷取的組件。 您可以在 CollectionView 中選取資料列來編輯 AddPartPage 中的組件,或選取 [新增組件] 按鈕來新增組件。
AddPartPage.xaml。 此頁面可讓使用者輸入並儲存新組件的詳細資料。 使用者可以指定組件名稱、組件型別和初始供應者。 組件識別碼和組件可用日期是自動產生的。
在 [方案總管] 視窗中,展開 ViewModels 資料夾。 此資料夾包含兩個類別:AddPartViewModel.cs 和 PartsViewModel.cs。 這些是各自頁面的檢視模型,並包含該頁面顯示和操作資料所需的屬性和邏輯。
登入服務
REST 服務會要求您先登入,以取得授權權杖。 沒有使用者驗證。 您先呼叫特定端點以取得授權權杖,然後在每一個後續要求中透過 HTTP 標頭將權杖傳回給伺服器。
開啟 Data 資料夾中的 PartsManager.cs 檔案。
將下列程式碼段中所定義的 BaseAddress 和 Url 靜態欄位新增至 PartsManager 類別。 將文字 URL GOES 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 = JsonSerializer.Deserialize<string>(authorizationKey); } client.DefaultRequestHeaders.Add("Authorization", authorizationKey); client.DefaultRequestHeaders.Add("Accept", "application/json"); return client; }
執行 GET 作業以擷取組件的資訊
在 PartsManager.cs 檔案中 ,尋找 GetAll 方法。 這是非同步方法,其會傳回可列舉的組件清單。 此方法尚未實作。
在此方法中,刪除擲回 NotImplementedException 例外狀況的程式碼。
使用類別
Connectivity
查看裝置是否具有網際網路連線能力。 如果網際網路不存在,請傳回空白的List<Part>
。if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return new List<Part>();
呼叫 GetClient 方法來擷取要使用的 HttpClient 物件。 記住 GetClient 是非同步,因此請使用 await 運算子擷取這個方法傳回的物件。
呼叫 HttpClient 物件的 GetStringAsync 方法,並提供要從 REST Web 服務擷取組件陣列的基底 URL。 資料會當作 JSON 字串以非同步方式傳回。
使用 JsonSerializer.Deserialize 方法,將此方法傳回的 JSON 字串還原序列化為 Part 物件的清單。 將此清單傳回給呼叫者。
完整的方法如下所示:
public static async Task<IEnumerable<Part>> GetAll() { if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return new List<Part>(); var client = await GetClient(); string result = await client.GetStringAsync($"{Url}parts"); return JsonSerializer.Deserialize<List<Part>>(result, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, }); }
建置並執行應用程式。 應用程式啟動時,[組件清單] 頁面將會出現,而且 GetAll 方法擷取的組件清單應該會出現。 下圖顯示在 Android 上執行的應用程式:
當您完成資料瀏覽時,請關閉應用程式並返回 Visual Studio 或 Visual Studio Code。
執行 POST 作業以新增組件至資料庫
在 PartManager 類別中 ,找出 Add 方法。 此方法具有組件名稱、供應商和組件類型的參數。 方法是非同步的。 此方法的目的是將新組件插入至資料庫,並傳回 Part 物件,代表新建立的項目。
刪除方法中的現有程式碼。
使用類別
Connectivity
查看裝置是否具有網際網路連線能力。 如果網際網路不存在,請傳回空白的Part
。if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return new Part();
建立新的 Part 物件。 將傳入的資料填入欄位中:
- 將 PartID 欄位設定為空字串。 此識別碼將由 REST Web 服務產生。
- 建立新的清單以保留供應商的名稱。
- 將 PartAvailableDate 欄位設定為 DateTime.Now。
- 從 GetClient 方法取得 HTTP 用戶端。
var part = new Part() { PartName = partName, Suppliers = new List<string>(new[] { supplier }), PartID = string.Empty, PartType = partType, PartAvailableDate = DateTime.Now.Date };
呼叫 GetClient 方法來擷取要使用的 HttpClient 物件。
建立
HttpRequestMessage
物件。 此物件是用來將傳送至 Web 服務的要求製成模型。 使用參數起始此物件,而這些參數指出要使用哪個 Http 指令動詞,以及要與哪個 Web 服務 URL 通訊。var msg = new HttpRequestMessage(HttpMethod.Post, $"{Url}parts");
您必須將承載連同要建立的組件資訊傳送至 WebService。 此承載將會序列化為 JSON。 JSON 承載將會新增至
HttpRequestMessage.Content
屬性,並使用JsonContent.Create
方法進行序列化。msg.Content = JsonContent.Create<Part>(part);
現在,使用
HttpClient.SendAsync
函式將訊息傳送至 Web 服務。 該函式會傳回HttpResponseMessage
物件,其中保留伺服器上作業的相關資訊。 例如 HTTP 回應碼以及從伺服器傳回的資訊。var response = await client.SendAsync(msg); response.EnsureSuccessStatusCode();
請注意,之前是使用
response.EnsureSuccessStatusCode
方法。 如果傳回 2xx HTTP 以外的狀態碼,就會擲回錯誤。如果 Web 服務傳回資訊,例如 JSON 中序列化的物件,您可以從
HttpResponseMessage
中讀取該資訊。 然後,您可以使用JsonSerializer.Deserialize
將 JSON 還原序列化。var returnedJson = await response.Content.ReadAsStringAsync(); var insertedPart = JsonSerializer.Deserialize<Part>(returnedJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, });
最後,傳回新插入的組件。
return insertedPart;
建置並執行應用程式。 選取 [新增組件] 按鈕,然後輸入名稱、類型和供應商以建立新組件。 選取 [儲存]。 系統將會叫用 PartsManager 類別中的 Add 方法,這會在 Web 服務中建立新組件。 如果作業成功,組件清單頁面會重新出現,而清單底部會列出新組件。
當您完成資料瀏覽時,請關閉應用程式並返回 Visual Studio 或 Visual Studio Code。
執行 PUT 作業以更新資料庫中組件的詳細資料
在 PartsManager 類別中,尋找 Update 方法。 這是採取 Part 物件作為參數的非同步方法。 此方法沒有明確的傳回值。 不過,傳回類型是 Task,以便例外狀況能夠適當地傳回給呼叫者。 讓我們實作 PUT 功能。
刪除現有的程式碼。
如同之前一樣,請檢查是否有網際網路連線。
if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return;
建立新的
HttpRequestMessage
,這次指定 PUT 作業和 URL 以更新組件。HttpRequestMessage msg = new(HttpMethod.Put, $"{Url}parts/{part.PartID}");
使用
JsonContent.Create
函式,以及已傳遞至該函式的 part 參數,來設定HttpRequestMessage
的Content
屬性。msg.Content = JsonContent.Create<Part>(part);
從 GetClient 方法取得 HTTP 用戶端。
var client = await GetClient();
傳送具有
HttpClient
的要求,然後確保其成功。var response = await client.SendAsync(msg); response.EnsureSuccessStatusCode();
建置並執行應用程式。 從清單中選取一個組件。 AddPart 頁面即會出現,這一次已填入屬性。 更新您想要的任何項目。
選取 [儲存]。 這會呼叫 PartsManager 類別中的 Update 方法,將變更傳送至 Web 服務。 如果成功,組件清單頁面會重新出現,而您的變更會反映在其中。
注意
您在上一個工作中新增的組件不會出現在 [組件清單] 頁面上。 每次應用程式執行時,應用程式使用的資料就會重設為預先定義元件的清單。 這是為了測試應用程式時提供一致性。
執行 DELETE 作業以從資料庫移除組件的詳細資料
在 PartManager 類別中,尋找 Delete 方法。 這是採取 partId 字串並傳回工作的非同步方法。
刪除現有的程式碼。
檢查是否有網際網路連線。
if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet) return;
建立新的
HttpRequestMessage
物件。 現在只指定 DELETE HTTP 指令動詞和 URL 來刪除組件。HttpRequestMessage msg = new(HttpMethod.Delete, $"{Url}parts/{partID}");
從 GetClient 方法取得 HTTP 用戶端。
var client = await GetClient();
將要求傳送至 Web 服務。 在成功傳回之後檢查是否成功。
var response = await client.SendAsync(msg); response.EnsureSuccessStatusCode();
建置並執行應用程式。 從清單中選取一個組件,然後在 [新增組件] 頁面選取 [刪除]。 如果成功,[組件清單] 頁面將會重新出現,且您刪除的組件將不再顯示。