表示性狀態轉移(Representational State Transfer,簡稱 REST)是一種用於建置網路服務的架構風格。 REST 請求通常透過 HTTPS 進行,使用與網頁瀏覽器用來擷取網頁及傳送資料至伺服器相同的 HTTP 動詞。 動詞如下:
- GET – 此操作用於從網路服務中擷取資料。
- POST – 此操作用於在網路服務中建立新的資料項目。
- PUT ——此操作用於更新網路服務中的一項資料。
- PATCH – 此操作用於更新網路服務中的資料項目,描述一組指示該項目應如何修改。
- DELETE – 此操作用於刪除網路服務中的資料項目。
遵循 REST 的 Web Service API 定義如下:
- 一個基礎的URI。
- HTTP 方法,如 GET、POST、PUT、PATCH 或 DELETE。
- 資料的媒體類型,例如 JavaScript 物件符號(JSON)。
基於 REST 的網路服務通常使用 JSON 訊息來回傳資料給用戶端。 JSON 是一種基於文字的資料交換格式,能產生緊湊的有效載荷,因此在傳送資料時減少了頻寬需求。 REST 的簡單性使其成為行動應用程式中存取網路服務的主要方式。
備註
存取網路服務通常需要非同步程式設計。 欲了解更多關於非同步程式設計的資訊,請參閱 使用 async 和 await 的非同步程式設計。
網路服務運作
範例 REST 服務使用 ASP.NET Core 撰寫,並提供以下操作:
| 行動 | HTTP 方法 | 相對 URI | 參數 |
|---|---|---|---|
| 取得待辦事項清單 | GET | /api/待辦事項/ | |
| 新增一項待辦事項 | 郵件 | /api/待辦事項/ | 一個 JSON 格式的 TodoItem |
| 更新待辦事項 | PUT | /api/待辦事項/ | 一個 JSON 格式的 TodoItem |
| 刪除待辦事項 | 刪除 | /api/todoitems/{id} |
.NET MAUI 應用程式與網路服務使用 該 TodoItem 類別來建模顯示並傳送至網路服務以供儲存的資料:
public class TodoItem
{
public string ID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}
該 ID 屬性用來唯一識別每個 TodoItem 物件,並被網路服務用來識別需要更新或刪除的資料。 例如,為了刪除 ID 為 aaaabbbb-0000-cccc-1111-dddd2222eeee 的 TodoItem,.NET MAUI 應用程式會向 https://hostname/api/todoitems/aaaabbbb-0000-cccc-1111-dddd2222eeee 發送 DELETE 請求。
當 Web API 框架收到請求時,會將請求路由到一個動作。 這些動作是類別中的 TodoItemsController 公開方法。 Web API 框架利用路由中介軟體來匹配收到的請求 URL,並將其映射到動作。 REST API 應使用屬性路由來模擬應用程式的功能,將其視為一組以 HTTP 動詞表示操作的資源集合。 屬性路由使用一組屬性,將動作直接對應至路由範本。 欲了解更多屬性路由資訊,請參閱 REST API 的屬性路由。 欲了解更多使用 ASP.NET Core 建置 REST 服務的資訊,請參閱 「為原生行動應用程式建立後端服務」。
建立 HTTPClient 物件
.NET 多平台應用程式介面(.NET MAUI)應用程式可以使用 HttpClient 類別,通過向基於 REST 的網路服務發送請求來使用該服務。 此類別提供傳送 HTTP 請求及接收來自 URI 識別資源的 HTTP 回應的功能。 每個請求都是以非同步操作方式發送。
HttpClient物件應在類別層級宣告,使其在應用程式需要發出 HTTP 請求期間持續存在:
public class RestService
{
HttpClient _client;
JsonSerializerOptions _serializerOptions;
public List<TodoItem> Items { get; private set; }
public RestService()
{
_client = new HttpClient();
_serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
}
...
}
這個 JsonSerializerOptions 物件用來配置從網路服務接收和傳送的 JSON 有效載荷的格式化。 欲了解更多資訊,請參閱 如何使用 System.Text.Json 實例化 JsonSerializerOptions 實例。
取出資料
此 HttpClient.GetAsync 方法用於向 URI 指定的網路服務發送 GET 請求,然後接收來自網路服務的回應:
public async Task<List<TodoItem>> RefreshDataAsync()
{
Items = new List<TodoItem>();
Uri uri = new Uri(string.Format(Constants.RestUrl, string.Empty));
try
{
HttpResponseMessage response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
Items = JsonSerializer.Deserialize<List<TodoItem>>(content, _serializerOptions);
}
}
catch (Exception ex)
{
Debug.WriteLine(@"\tERROR {0}", ex.Message);
}
return Items;
}
資料是以物件的形式從網路服務 HttpResponseMessage 接收的。 它包含回應的資訊,包括狀態碼、標頭及任何正文。 REST 服務會在回應中傳送一個 HTTP 狀態碼,該狀態碼可從屬性 HttpResponseMessage.IsSuccessStatusCode 中取得,以指示 HTTP 請求是否成功或失敗。 在此操作中,REST 服務會在回應中傳送 HTTP 狀態碼 200(OK),表示請求已成功,且請求的資訊已包含在回應中。
如果 HTTP 操作成功,則會讀取回應的內容。 屬性 HttpResponseMessage.Content 代表回應的內容,且型別 HttpContent為 。 該 HttpContent 類別代表 HTTP 正文與內容標頭,例如 Content-Type 和 Content-Encoding。 然後,內容會使用HttpContent.ReadAsStringAsync方法讀入string。
string接著會將 JSON 反序列化成包含TodoItem物件的List。
警告
使用此 ReadAsStringAsync 方法擷取大型回應可能會對效能產生負面影響。 在這種情況下,回應應直接反序列化,以避免必須完全緩衝。
建立資料
此 HttpClient.PostAsync 方法用於向 URI 指定的網路服務發送 POST 請求,然後接收來自網路服務的回應:
public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)
{
Uri uri = new Uri(string.Format(Constants.RestUrl, string.Empty));
try
{
string json = JsonSerializer.Serialize<TodoItem>(item, _serializerOptions);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
if (isNewItem)
response = await _client.PostAsync(uri, content);
else
response = await _client.PutAsync(uri, content);
if (response.IsSuccessStatusCode)
Debug.WriteLine(@"\tTodoItem successfully saved.");
}
catch (Exception ex)
{
Debug.WriteLine(@"\tERROR {0}", ex.Message);
}
}
在此範例中,實 TodoItem 例被序列化成 JSON 有效載荷,傳送給網路服務。 這個有效載荷會嵌入在將傳送給網路服務的 HTTP 內容中,然後再用該 PostAsync 方法發出請求。
REST 服務會在回應中傳送一個 HTTP 狀態碼,該狀態碼可從屬性 HttpResponseMessage.IsSuccessStatusCode 中取得,以指示 HTTP 請求是否成功或失敗。 此操作的典型回應如下:
- 201(已建立) – 請求在回應發送前已建立新資源。
- 400(惡意請求) – 伺服器無法理解該請求。
- 409(衝突) – 因伺服器衝突無法執行請求。
更新資料
此 HttpClient.PutAsync 方法用於向 URI 指定的網路服務發送 PUT 請求,然後接收來自該網路服務的回應:
public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)
{
...
response = await _client.PutAsync(uri, content);
...
}
此 PutAsync 方法的運作方式與 PostAsync 網路服務中建立資料的方法相同。 然而,網路服務可能發送的回應有所不同。
REST 服務會在回應中傳送一個 HTTP 狀態碼,該狀態碼可從屬性 HttpResponseMessage.IsSuccessStatusCode 中取得,以指示 HTTP 請求是否成功或失敗。 此操作的典型回應如下:
- 204(無內容) – 請求已成功處理,回應為故意空白。
- 400(惡意請求) – 伺服器無法理解該請求。
- 404(未找到) – 伺服器上不存在請求的資源。
刪除資料
此 HttpClient.DeleteAsync 方法用於向 URI 指定的網路服務發送 DELETE 請求,然後接收來自該網路服務的回應:
public async Task DeleteTodoItemAsync(string id)
{
Uri uri = new Uri(string.Format(Constants.RestUrl, id));
try
{
HttpResponseMessage response = await _client.DeleteAsync(uri);
if (response.IsSuccessStatusCode)
Debug.WriteLine(@"\tTodoItem successfully deleted.");
}
catch (Exception ex)
{
Debug.WriteLine(@"\tERROR {0}", ex.Message);
}
}
REST 服務會在回應中傳送一個 HTTP 狀態碼,該狀態碼可從屬性 HttpResponseMessage.IsSuccessStatusCode 中取得,以指示 HTTP 請求是否成功或失敗。 此操作的典型回應如下:
- 204(無內容) – 請求已成功處理,回應為故意空白。
- 400(惡意請求) – 伺服器無法理解該請求。
- 404(未找到) – 伺服器上不存在請求的資源。
本地開發
如果你在本地開發 REST 網頁服務,使用像 ASP.NET Core Web API 這樣的框架,你可以同時除錯網頁服務和 .NET MAUI 應用程式。 在這種情況下,若要透過 Android 模擬器和 iOS 模擬器使用你的 HTTP 網路服務,必須在 .NET MAUI 應用程式中啟用明文 HTTP 流量。 欲了解更多資訊,請參閱 從 Android 模擬器與 iOS 模擬器連接本地網路服務。
瀏覽範例