使用 ASP.NET Core 為本機(jī)移動(dòng)應(yīng)用創(chuàng)建后端服務(wù)

2019-04-17 08:57 更新

移動(dòng)應(yīng)用可與 ASP.NET Core 后端服務(wù)通信。 有關(guān)從 iOS 模擬器和 Android 仿真程序連接本地 Web 服務(wù)的說明,請(qǐng)參閱從 iOS 模擬器和 Android 仿真程序連接到本地 Web 服務(wù)

查看或下載后端服務(wù)代碼示例

本機(jī)移動(dòng)應(yīng)用示例

本教程演示如何創(chuàng)建使用 ASP.NET Core MVC 支持本機(jī)移動(dòng)應(yīng)用的后端服務(wù)。 它使用 Xamarin Forms ToDoRest 應(yīng)用 作為其本機(jī)客戶端,其中包括 Android、 iOS、 Windows Universal 和 Window Phone 設(shè)備的單獨(dú)本機(jī)客戶端。 你可以遵循鏈接中的教程來創(chuàng)建本機(jī)應(yīng)用程序(并安裝需要的免費(fèi) Xamarin 工具),以及下載 Xamarin 示例解決方案。 Xamarin 示例包含一個(gè) ASP.NET Web API 2 服務(wù)項(xiàng)目,使用本文中的 ASP.NET Core 應(yīng)用替換(客戶端無需進(jìn)行任何更改)。

在 Android 智能手機(jī)上運(yùn)行的 ToDoRest 應(yīng)用程序

功能

ToDoRest 應(yīng)用支持列出、 添加、刪除和更新待辦事項(xiàng)。 每個(gè)項(xiàng)都有一個(gè) ID、 Name(名稱)、Notes(說明)以及一個(gè)指示該項(xiàng)是否已完成的屬性 Done。

待辦事項(xiàng)的主視圖如上所示,列出每個(gè)項(xiàng)的名稱,并使用復(fù)選標(biāo)記指示它是否已完成。

點(diǎn)擊 + 圖標(biāo)打開“添加項(xiàng)”對(duì)話框:

“添加項(xiàng)”對(duì)話框

點(diǎn)擊主列表屏幕上的項(xiàng)將打開一個(gè)編輯對(duì)話框,在其中可以修改項(xiàng)的名稱、 說明以及是否完成,或刪除項(xiàng)目:

“編輯項(xiàng)”對(duì)話框

此示例默認(rèn)配置為使用托管在 developer.xamarin.com上的后端服務(wù),允許只讀操作。 若要使用在你計(jì)算機(jī)上運(yùn)行的下一節(jié)創(chuàng)建的 ASP.NET Core 應(yīng)用對(duì)其進(jìn)行測(cè)試,你需要更新應(yīng)用程序的 RestUrl 常量。 導(dǎo)航到 ToDoREST 項(xiàng)目,然后打開 Constants.cs 文件。 使用包含計(jì)算機(jī) IP 的 URL 地址替換 RestUrl(不是 localhost 或 127.0.0.1,因?yàn)榇说刂酚糜趶脑O(shè)備模擬器中,而不是從你的計(jì)算機(jī)中訪問)。 請(qǐng)包括端口號(hào) (5000)。 為了測(cè)試你的服務(wù)能否在設(shè)備上正常運(yùn)行,請(qǐng)確保沒有活動(dòng)的防火墻阻止訪問此端口。

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}";

創(chuàng)建 ASP.NET Core 項(xiàng)目

在 Visual Studio 中創(chuàng)建一個(gè)新的 ASP.NET Core Web 應(yīng)用程序。 選擇 Web API 模板和 No Authentication(無身份驗(yàn)證)。 將項(xiàng)目命名為 ToDoApi。

“新建 ASP.NET Web 應(yīng)用程序”對(duì)話框,其中已選中 Web API 項(xiàng)目模板

對(duì)于向端口 5000 進(jìn)行的請(qǐng)求,應(yīng)用程序均需作出響應(yīng)。 更新 Program.cs,使其包含 .UseUrls("http://*:5000"),以便實(shí)現(xiàn)以下操作:

C#

var host = new WebHostBuilder()
    .UseKestrel()
    .UseUrls("http://*:5000")
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

 備注

請(qǐng)確保直接運(yùn)行應(yīng)用程序,而不是在 IIS Express 后運(yùn)行,因?yàn)樵谀J(rèn)情況下,后者會(huì)忽略非本地請(qǐng)求。 從命令提示符處運(yùn)行 dotnet run,或從 Visual Studio 工具欄中的“調(diào)試目標(biāo)”下拉列表中選擇應(yīng)用程序名稱配置文件。

添加一個(gè)模型類來表示待辦事項(xiàng)。 使用 [Required] 屬性標(biāo)記必需字段:

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 方法需要通過某種方式處理數(shù)據(jù)。 使用原始 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);
    }
}

在此示例中,該實(shí)現(xiàn)僅使用一個(gè)專用項(xiàng)集合:

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 中配置該實(shí)現(xiàn):

C#

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddSingleton<IToDoRepository,ToDoRepository>();
}

現(xiàn)可創(chuàng)建 ToDoItemsController。

 提示

有關(guān)創(chuàng)建 Web API 的詳細(xì)信息,請(qǐng)參閱使用 ASP.NET Core MVC 和 Visual Studio 生成首個(gè) Web API

創(chuàng)建控制器

在項(xiàng)目中添加新控制器 ToDoItemsController。 它應(yīng)繼承 Microsoft.AspNetCore.Mvc.Controller。 添加 Route 屬性以指示控制器將處理路徑以 api/todoitems 開始的請(qǐng)求。 路由中的 [controller] 標(biāo)記會(huì)被控制器的名稱代替(省略 Controller 后綴),這對(duì)全局路由特別有用。 詳細(xì)了解 路由

控制器需要 IToDoRepository 才能正常運(yùn)行;通過控制器的構(gòu)造函數(shù)請(qǐng)求該類型的實(shí)例。 在運(yùn)行時(shí),此實(shí)例將使用框架對(duì) 依賴關(guān)系注入 的支持來提供。

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 支持四個(gè)不同的 HTTP 謂詞來執(zhí)行對(duì)數(shù)據(jù)源的 CRUD(創(chuàng)建、讀取、更新、刪除)操作。 最簡(jiǎn)單的是讀取操作,它對(duì)應(yīng)于 HTTP GET 請(qǐng)求。

讀取項(xiàng)目

要請(qǐng)求項(xiàng)列表,可對(duì) List 方法使用 GET 請(qǐng)求。 [HttpGet] 方法的 List 屬性指示此操作應(yīng)僅處理 GET 請(qǐng)求。 此操作的路由是在控制器上指定的路由。 你不一定必須將操作名稱用作路由的一部分。 你只需確保每個(gè)操作都有唯一的和明確的路由。 路由屬性可以分別應(yīng)用在控制器和方法級(jí)別,以此生成特定的路由。

C#

[HttpGet]
public IActionResult List()
{
    return Ok(_toDoRepository.All);
}

List 方法返回 200 OK 響應(yīng)代碼和所有 ToDo 項(xiàng),并序列化為 JSON 。

你可以使用多種工具測(cè)試新的 API 方法,如 Postman,如此處所示:

Postman 控制臺(tái),其中顯示一個(gè) todoitem 的 GET 請(qǐng)求,以及顯示所返回的三個(gè)項(xiàng)目的 JSON 的響應(yīng)正文

創(chuàng)建項(xiàng)目

按照約定,創(chuàng)建新數(shù)據(jù)項(xiàng)映射到 HTTP POST 謂詞。 Create 方法具有應(yīng)用于該對(duì)象的 [HttpPost]屬性,并接受 ToDoItem 實(shí)例。 由于 item 參數(shù)將在 POST 的正文中傳遞,因此該參數(shù)用 [FromBody] 屬性修飾。

在該方法中,會(huì)檢查項(xiàng)的有效性和之前是否存在于數(shù)據(jù)存儲(chǔ),并且如果沒有任何問題,則使用存儲(chǔ)庫(kù)添加。 檢查 ModelState.IsValid 將執(zhí)行 模型驗(yàn)證,應(yīng)該在每個(gè)接受用戶輸入的 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);
}

示例中使用一個(gè)枚舉,后者包含傳遞到移動(dòng)客戶端的錯(cuò)誤代碼:

C#

public enum ErrorCode
{
    TodoItemNameAndNotesRequired,
    TodoItemIDInUse,
    RecordNotFound,
    CouldNotCreateItem,
    CouldNotUpdateItem,
    CouldNotDeleteItem
}

使用 Postman 測(cè)試添加新項(xiàng),選擇 POST 謂詞并在請(qǐng)求正文中以 JSON 格式提供新對(duì)象。 你還應(yīng)添加一個(gè)請(qǐng)求標(biāo)頭指定 Content-Type 為 application/json。

顯示 POST 和響應(yīng)的 Postman 控制臺(tái)

該方法返回在響應(yīng)中新建的項(xiàng)。

更新項(xiàng)目

通過使用 HTTP PUT 請(qǐng)求來修改記錄。 除了此更改之外,Edit 方法幾乎與 Create 完全相同。 請(qǐng)注意,如果未找到記錄,則 Edit 操作將返回 NotFound(404) 響應(yīng)。

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 進(jìn)行測(cè)試,將謂詞更改為 PUT。 在請(qǐng)求正文中指定要更新的對(duì)象數(shù)據(jù)。

顯示 PUT 和響應(yīng)的 Postman 控制臺(tái)

為了與預(yù)先存在的 API 保持一致,此方法在成功時(shí)返回 NoContent (204) 響應(yīng)。

刪除項(xiàng)目

刪除記錄可以通過向服務(wù)發(fā)出 DELETE 請(qǐng)求并傳遞要?jiǎng)h除項(xiàng)的 ID 來完成。 與更新一樣,請(qǐng)求的項(xiàng)不存在時(shí)會(huì)收到 NotFound 響應(yīng)。 請(qǐng)求成功會(huì)得到 NoContent (204) 響應(yīng)。

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();
}

請(qǐng)注意,在測(cè)試刪除功能時(shí),請(qǐng)求正文中不需要任何內(nèi)容。

顯示 DELETE 和響應(yīng)的 Postman 控制臺(tái)

常見的 Web API 約定

開發(fā)應(yīng)用程序的后端服務(wù)時(shí),你將想要使用一組一致的約定或策略來處理橫切關(guān)注點(diǎn)。 例如,在上面所示服務(wù)中,針對(duì)不存在的特定記錄的請(qǐng)求會(huì)收到 NotFound 響應(yīng),而不是BadRequest 響應(yīng)。 同樣,對(duì)于此服務(wù),傳遞模型綁定類型的命令始終檢查 ModelState.IsValid 并為無效的模型類型返回 BadRequest。

一旦為 Api 指定通用策略,一般可以將其封裝在 Filter(篩選器)。 詳細(xì)了解 如何封裝 ASP.NET Core MVC 應(yīng)用程序中的通用 API 策略


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)