移動應用可與 ASP.NET Core 后端服務通信。 有關從 iOS 模擬器和 Android 仿真程序連接本地 Web 服務的說明,請參閱從 iOS 模擬器和 Android 仿真程序連接到本地 Web 服務。
本教程演示如何創(chuàng)建使用 ASP.NET Core MVC 支持本機移動應用的后端服務。 它使用 Xamarin Forms ToDoRest 應用 作為其本機客戶端,其中包括 Android、 iOS、 Windows Universal 和 Window Phone 設備的單獨本機客戶端。 你可以遵循鏈接中的教程來創(chuàng)建本機應用程序(并安裝需要的免費 Xamarin 工具),以及下載 Xamarin 示例解決方案。 Xamarin 示例包含一個 ASP.NET Web API 2 服務項目,使用本文中的 ASP.NET Core 應用替換(客戶端無需進行任何更改)。
ToDoRest 應用支持列出、 添加、刪除和更新待辦事項。 每個項都有一個 ID、 Name(名稱)、Notes(說明)以及一個指示該項是否已完成的屬性 Done。
待辦事項的主視圖如上所示,列出每個項的名稱,并使用復選標記指示它是否已完成。
點擊 + 圖標打開“添加項”對話框:
點擊主列表屏幕上的項將打開一個編輯對話框,在其中可以修改項的名稱、 說明以及是否完成,或刪除項目:
此示例默認配置為使用托管在 developer.xamarin.com上的后端服務,允許只讀操作。 若要使用在你計算機上運行的下一節(jié)創(chuàng)建的 ASP.NET Core 應用對其進行測試,你需要更新應用程序的 RestUrl 常量。 導航到 ToDoREST 項目,然后打開 Constants.cs 文件。 使用包含計算機 IP 的 URL 地址替換 RestUrl(不是 localhost 或 127.0.0.1,因為此地址用于從設備模擬器中,而不是從你的計算機中訪問)。 請包括端口號 (5000)。 為了測試你的服務能否在設備上正常運行,請確保沒有活動的防火墻阻止訪問此端口。
C#
// URL of REST service (Xamarin ReadOnly Service)
//public static string RestUrl = "http://developer.xamarin.com:8081/api/todoitems{0}";
// use your machine's IP address
public static string RestUrl = "http://192.168.1.207:5000/api/todoitems/{0}";
在 Visual Studio 中創(chuàng)建一個新的 ASP.NET Core Web 應用程序。 選擇 Web API 模板和 No Authentication(無身份驗證)。 將項目命名為 ToDoApi。
對于向端口 5000 進行的請求,應用程序均需作出響應。 更新 Program.cs,使其包含 .UseUrls("http://*:5000"),以便實現以下操作:
C#
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
備注
請確保直接運行應用程序,而不是在 IIS Express 后運行,因為在默認情況下,后者會忽略非本地請求。 從命令提示符處運行 dotnet run,或從 Visual Studio 工具欄中的“調試目標”下拉列表中選擇應用程序名稱配置文件。
添加一個模型類來表示待辦事項。 使用 [Required] 屬性標記必需字段:
C#
using System.ComponentModel.DataAnnotations;
namespace ToDoApi.Models
{
public class ToDoItem
{
[Required]
public string ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Notes { get; set; }
public bool Done { get; set; }
}
}
API 方法需要通過某種方式處理數據。 使用原始 Xamarin 示例所用的 IToDoRepository 接口:
C#
using System.Collections.Generic;
using ToDoApi.Models;
namespace ToDoApi.Interfaces
{
public interface IToDoRepository
{
bool DoesItemExist(string id);
IEnumerable<ToDoItem> All { get; }
ToDoItem Find(string id);
void Insert(ToDoItem item);
void Update(ToDoItem item);
void Delete(string id);
}
}
在此示例中,該實現僅使用一個專用項集合:
C#
using System.Collections.Generic;
using System.Linq;
using ToDoApi.Interfaces;
using ToDoApi.Models;
namespace ToDoApi.Services
{
public class ToDoRepository : IToDoRepository
{
private List<ToDoItem> _toDoList;
public ToDoRepository()
{
InitializeData();
}
public IEnumerable<ToDoItem> All
{
get { return _toDoList; }
}
public bool DoesItemExist(string id)
{
return _toDoList.Any(item => item.ID == id);
}
public ToDoItem Find(string id)
{
return _toDoList.FirstOrDefault(item => item.ID == id);
}
public void Insert(ToDoItem item)
{
_toDoList.Add(item);
}
public void Update(ToDoItem item)
{
var todoItem = this.Find(item.ID);
var index = _toDoList.IndexOf(todoItem);
_toDoList.RemoveAt(index);
_toDoList.Insert(index, item);
}
public void Delete(string id)
{
_toDoList.Remove(this.Find(id));
}
private void InitializeData()
{
_toDoList = new List<ToDoItem>();
var todoItem1 = new ToDoItem
{
ID = "6bb8a868-dba1-4f1a-93b7-24ebce87e243",
Name = "Learn app development",
Notes = "Attend Xamarin University",
Done = true
};
var todoItem2 = new ToDoItem
{
ID = "b94afb54-a1cb-4313-8af3-b7511551b33b",
Name = "Develop apps",
Notes = "Use Xamarin Studio/Visual Studio",
Done = false
};
var todoItem3 = new ToDoItem
{
ID = "ecfa6f80-3671-4911-aabe-63cc442c1ecf",
Name = "Publish apps",
Notes = "All app stores",
Done = false,
};
_toDoList.Add(todoItem1);
_toDoList.Add(todoItem2);
_toDoList.Add(todoItem3);
}
}
}
在 Startup.cs 中配置該實現:
C#
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSingleton<IToDoRepository,ToDoRepository>();
}
現可創(chuàng)建 ToDoItemsController。
提示
有關創(chuàng)建 Web API 的詳細信息,請參閱使用 ASP.NET Core MVC 和 Visual Studio 生成首個 Web API。
在項目中添加新控制器 ToDoItemsController。 它應繼承 Microsoft.AspNetCore.Mvc.Controller。 添加 Route 屬性以指示控制器將處理路徑以 api/todoitems 開始的請求。 路由中的 [controller] 標記會被控制器的名稱代替(省略 Controller 后綴),這對全局路由特別有用。 詳細了解 路由。
控制器需要 IToDoRepository 才能正常運行;通過控制器的構造函數請求該類型的實例。 在運行時,此實例將使用框架對 依賴關系注入 的支持來提供。
C#
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ToDoApi.Interfaces;
using ToDoApi.Models;
namespace ToDoApi.Controllers
{
[Route("api/[controller]")]
public class ToDoItemsController : Controller
{
private readonly IToDoRepository _toDoRepository;
public ToDoItemsController(IToDoRepository toDoRepository)
{
_toDoRepository = toDoRepository;
}
此 API 支持四個不同的 HTTP 謂詞來執(zhí)行對數據源的 CRUD(創(chuàng)建、讀取、更新、刪除)操作。 最簡單的是讀取操作,它對應于 HTTP GET 請求。
要請求項列表,可對 List 方法使用 GET 請求。 [HttpGet] 方法的 List 屬性指示此操作應僅處理 GET 請求。 此操作的路由是在控制器上指定的路由。 你不一定必須將操作名稱用作路由的一部分。 你只需確保每個操作都有唯一的和明確的路由。 路由屬性可以分別應用在控制器和方法級別,以此生成特定的路由。
C#
[HttpGet]
public IActionResult List()
{
return Ok(_toDoRepository.All);
}
List 方法返回 200 OK 響應代碼和所有 ToDo 項,并序列化為 JSON 。
你可以使用多種工具測試新的 API 方法,如 Postman,如此處所示:
按照約定,創(chuàng)建新數據項映射到 HTTP POST 謂詞。 Create 方法具有應用于該對象的 [HttpPost]屬性,并接受 ToDoItem 實例。 由于 item 參數將在 POST 的正文中傳遞,因此該參數用 [FromBody] 屬性修飾。
在該方法中,會檢查項的有效性和之前是否存在于數據存儲,并且如果沒有任何問題,則使用存儲庫添加。 檢查 ModelState.IsValid 將執(zhí)行 模型驗證,應該在每個接受用戶輸入的 API 方法中執(zhí)行此步驟。
C#
[HttpPost]
public IActionResult Create([FromBody] ToDoItem item)
{
try
{
if (item == null || !ModelState.IsValid)
{
return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
}
bool itemExists = _toDoRepository.DoesItemExist(item.ID);
if (itemExists)
{
return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
}
_toDoRepository.Insert(item);
}
catch (Exception)
{
return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
}
return Ok(item);
}
示例中使用一個枚舉,后者包含傳遞到移動客戶端的錯誤代碼:
C#
public enum ErrorCode
{
TodoItemNameAndNotesRequired,
TodoItemIDInUse,
RecordNotFound,
CouldNotCreateItem,
CouldNotUpdateItem,
CouldNotDeleteItem
}
使用 Postman 測試添加新項,選擇 POST 謂詞并在請求正文中以 JSON 格式提供新對象。 你還應添加一個請求標頭指定 Content-Type 為 application/json。
該方法返回在響應中新建的項。
通過使用 HTTP PUT 請求來修改記錄。 除了此更改之外,Edit 方法幾乎與 Create 完全相同。 請注意,如果未找到記錄,則 Edit 操作將返回 NotFound(404) 響應。
C#
[HttpPut]
public IActionResult Edit([FromBody] ToDoItem item)
{
try
{
if (item == null || !ModelState.IsValid)
{
return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
}
var existingItem = _toDoRepository.Find(item.ID);
if (existingItem == null)
{
return NotFound(ErrorCode.RecordNotFound.ToString());
}
_toDoRepository.Update(item);
}
catch (Exception)
{
return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
}
return NoContent();
}
若要使用 Postman 進行測試,將謂詞更改為 PUT。 在請求正文中指定要更新的對象數據。
為了與預先存在的 API 保持一致,此方法在成功時返回 NoContent (204) 響應。
刪除記錄可以通過向服務發(fā)出 DELETE 請求并傳遞要刪除項的 ID 來完成。 與更新一樣,請求的項不存在時會收到 NotFound 響應。 請求成功會得到 NoContent (204) 響應。
C#
[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
try
{
var item = _toDoRepository.Find(id);
if (item == null)
{
return NotFound(ErrorCode.RecordNotFound.ToString());
}
_toDoRepository.Delete(id);
}
catch (Exception)
{
return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
}
return NoContent();
}
請注意,在測試刪除功能時,請求正文中不需要任何內容。
開發(fā)應用程序的后端服務時,你將想要使用一組一致的約定或策略來處理橫切關注點。 例如,在上面所示服務中,針對不存在的特定記錄的請求會收到 NotFound 響應,而不是BadRequest 響應。 同樣,對于此服務,傳遞模型綁定類型的命令始終檢查 ModelState.IsValid 并為無效的模型類型返回 BadRequest。
一旦為 Api 指定通用策略,一般可以將其封裝在 Filter(篩選器)。 詳細了解 如何封裝 ASP.NET Core MVC 應用程序中的通用 API 策略。
更多建議: