使用ASP.NET Core建立Web API服務

使用 ASP.NET Core 建立 Web API 服務

.NET Core(ASP.NET Core)與之前的 ASP.NET MVC / ASP.NET Web API 兩套不同的 Framework 不同,ASP.NET Core 中的 MVC 整合了 Web API,現在要建立 API 或 Web 都將更為簡單,因為整合後的 ASP.NET Core MVC 基於相同的程式碼與管線(pipeline)。

開發環境

ASP.NET Core 的跨平台特性,使用開發工具與開發環境的選擇相當多元。

.NET Core SDK 安裝:

安裝頁面有各平台(Windows, Linux, Mac, Docker)的安裝指南,照步驟安裝即可。

開發工具方面:

  • Visual Studio 2015 Update 3 + .NET Core Tooling Preview 2 for Visual Studio 2015
  • Visual Studio Code + C# for Visual Studio Code(Extensions)

使用 Windows 的開發者,地表最強的 Visual Studio 當然是最好的選擇,如果使用 MAC(Windows) 那 VS Code + C# 擴充套件後也不差。如果 Visual Studio 2015 Update 3 並安裝了最新的 .NET Core Tooling Preview 2 for Visual Studio 2015 ,那麼已包含 .NET Core SDK 的安裝。

如果 VS Code + C# 擴充套件,使用起來不是很順(例如,IntelliSense、提示加 using 等),看一下 OmniSharp Log (檢視 → 切換輸出)是否正常。重開幾次 VS Code 看看。

測試工具:

  • POSTMAN
  • Fiddler

兩套測試工具都行,挑喜歡的用即可。

範本工具:

安裝指令:

npm install -g yo 
npm install -g generator-aspnet
    

這是延伸自 yeoman 的範本產生器,在不使用 Visual Studio 的情況下,它會很有幫助。

以下範例,讓我們使用 VS Code 來走一次建立 ASP.NET Core - Web API 的過程。相同的過程,使用 Visual Studio 的體驗與以前沒有太大差異,更重要的是,使用 VS Code 可以讓我們更瞭解 .NET Core 運作流程(因為要下指令),所以選擇使用指令與 VS Code 來進行實作。

ASP.NET Core - Web API 專案

我們透過 cmd.exe 下使用 yo aspnet 指令來建立 ASP.NET Core - Web API 專案。

yo aspnet

Data Models

使用 VS Code 開啟專案資料夾,新增 Models 資料夾,新增 TodoItem 類別。

vs code - add folder and file

透過 VS Code 新增的檔案內容都是空白,這對記憶力是個不小的考驗。建立檔案這件事,generator-aspnet 也有想到。

yo aspnet:Class TodoItem

yo add Class
namespace corewebapi.Models
{
    public class TodoItem
    {
        public string Key { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

加入 Repository 類別

此範例沒有使用資料庫,我們使用 Repository 來進行資料層的封裝。

yo aspnet:Interface ITodoRepository

加前 CURD 對應的方法介面:

namespace corewebapi.Models
{
    public interface ITodoRepository
    {
        void Add(TodoItem item);
        IEnumerable<TodoItem> GetAll();
        TodoItem Find(string key);
        TodoItem Remove(string key);
        void Update(TodoItem item);
    }
}

新增 TodoRepository 類別以實作介面:

yo aspnet:Class TodoRepository

TodoRepository 類別:

namespace corewebapi.Models
{
    public class TodoRepository : ITodoRepository
    {
        private static ConcurrentDictionary<string, TodoItem> _todos = 
            new ConcurrentDictionary<string, TodoItem>();

        public TodoRepository()
        {
            Add(new TodoItem { Name = "Item1"});
        }
        public void Add(TodoItem item)
        {
            item.Key = Guid.NewGuid().ToString();
            _todos[item.Key] = item;
        }

        public TodoItem Find(string key)
        {
            TodoItem item;
            _todos.TryGetValue(key, out item);
            return item;
        }

        public IEnumerable<TodoItem> GetAll()
        {
            return _todos.Values;
        }

        public TodoItem Remove(string key)
        {
            TodoItem item;
            _todos.TryGetValue(key, out item);
            _todos.TryRemove(key, out item);
            return item;
        }

        public void Update(TodoItem item)
        {
            _todos[item.Key] = item;
        }
    }
}

註冊 Repository

ASP.NET Core 內建 DI (dependency injection) 機制,讓我們能在 Controller 被初始化時進行注入作業,使用 DI 之後,可大幅提升應用程式的可測試性。

我們要註冊 Repository 到 DI 容器中。開啟 Startup.cs ,先 Models 的參考:

using corewebapi.Models;

ConfigureServices 方法加入以下程式碼:

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

    // 註冊 repository 型別
    services.AddSingleton<ITodoRepository, TodoRepository>();
}

dotnet 指令

.NET Core SDK 新增 dotnet 指令,讓我們可以新增專案、套件還原、專案建置、發行專案、執行專案、測試專案,封裝為NuGet套件等。

dotnet 的新增專案會新增一個 Console - Hello World 專案,要改到能執行 ASP.NET Core 需要一些設置,所以我們選擇 yeoman 來快速建立範本。

dotnet -h 可以查詢指令相關參數。

.NET Command Line Tools (1.0.0-preview2-003121)
Usage: dotnet [host-options] [command] [arguments] [common-options]

Arguments:
  [command]             The command to execute
  [arguments]           Arguments to pass to the command
  [host-options]        Options specific to dotnet (host)
  [common-options]      Options common to all commands

Common options:
  -v|--verbose          Enable verbose output
  -h|--help             Show help

Host options (passed before the command):
  -v|--verbose          Enable verbose output
  --version             Display .NET CLI Version Number
  --info                Display .NET CLI Info

Common Commands:
  new           Initialize a basic .NET project
  restore       Restore dependencies specified in the .NET project
  build         Builds a .NET project
  publish       Publishes a .NET project for deployment (including the runtime)
  run           Compiles and immediately executes a .NET project
  test          Runs unit tests using the test runner specified in the project
  pack          Creates a NuGet package

依下面順序輸入執行:

  1. dotnet restore
  2. dotnet build

建置過程如果有錯誤,請依錯誤訊息進行排除。

dotnet build

記得在執行 dotnet build 之前,確定所有檔案已經存檔,筆者有好幾次都忘了存檔,然後跑不出正確結果,查程式碼查了半天又查不出來。想要怪東怪西時才發現自己是豬頭。

新增 Controller

在 Controllers 目錄下新增 TodoController:

yo aspnet:WebApiController TodoController

移除預設 API Action 程式碼,替換為下列程式碼:

namespace corewebapi.Controllers
{
    [Route("api/[controller]")]
    public class TodoController : Controller
    {
        public TodoController(ITodoRepository todoItems)
        {
            TodoItems = todoItems;
        }
        public ITodoRepository TodoItems { get; set; }
    }
}

這裡先定義一個空的 Controller,TodoItems 會透過前面定義的 DI 進行注入作業。

取得 Todo 清單

依照下列程式碼,可以取得 Todo 清單:

public IEnumerable<TodoItem> GetAll()
{
    return TodoItems.GetAll();
}

[HttpGet("{id}", Name = "GetTodo")]
public IActionResult GetById(string id)
{
    var item = TodoItems.Find(id);
    if (item == null)
    {
        return NotFound();
    }
    return new ObjectResult(item);
}

由屬性 [HttpGet] 與命名 GetXXX 可以得知,這些方法實作 HTTP Get 方法,透過 dotnet run 可以把 ASP.NET Core 專案執行起來,預設位置是 http://localhost:5000,進行 Get 方法測試:

Test asp.net core - getall method
test asp.net core - getbyid method
dotnet run message

ObjectResult

GetAll 回傳一個 CLR 物件,ASP.NET Core MVC 自動序列化物件為 JSON 並將 JSON 寫入回應訊息的 Body 之中。

GetById 需回傳一個 IActionResult 型別,因為 GetById 有兩種不同的回傳型別的選擇。

  • 如果找不到對應的 id,方法會回傳 404 狀態(NotFound).
  • 如果成功,ObjectResult 回傳 200 狀態並回 JSON 寫入 Body 回傳。

ObjectResult 的繼承關係:

public class ObjectResult : ActionResult, IActionResult

完成CUD實作

前面我們完成 Read 的實作,現在往下進行 Create、Update、Delete 相關實作。

Create

[HttpPost]
public IActionResult Create([FromBody] TodoItem item)
{
    if (item == null)
    {
        return BadRequest();
    }
    TodoItems.Add(item);
    return CreatedAtRoute("GetTodo", new { controller = "Todo", id = item.Key }, item);
}

CreatedAtRoute 會建立一個狀態 201 的回應,這是為了符合 HTTP 的標準,也就為通知 Client 端新增資源位於那個位置。

test asp.net core - post method
post - location header

Update

[HttpPut("{id}")]
public IActionResult Update(string id, [FromBody] TodoItem item)
{
    if (item == null || item.Key != id)
    {
        return BadRequest();
    }

    var todo = TodoItems.Find(id);
    if (todo == null)
    {
        return NotFound();
    }

    TodoItems.Update(item);
    return new NoContentResult();
}

Update 類似 Create,但它使用 HTTP PUT 方法,如果成功,依照 HTTP 標準要回傳狀態 204(No Content)。PUT 方法需要傳遞完整的 Update 實體,如果是部分更新,使用 HTTP PATCH。

test asp.net core - put method

Delete

[HttpDelete("{id}")]
public void Delete(string id)
{
    TodoItems.Remove(id);
}

void 回傳 狀態 204(No Content),意思是,Client 收到 204 事件代表資源已經刪除或不存在。

所以有二個方向來思考:

  • Delete 意思是"刪除已存在的資源",如果不存在,回傳狀態 404。
  • Delete 意思是"確定 item 不在集合裡",如果 item 不存在集合,回傳狀態 204。
test asp.net core - delete method

小結

以上的實例,故意沒有使用 Visual Studio / IIS Express 等常用的開發工具,使用 VS Code + C# + yo + dotnet 一樣可以開發與執行 ASP.NET Core Web API 服務。如果你覺得打 dotnet 指令太麻煩,VS Code 的偵錯,一樣可下中斷點,可以啟動 ASP.NET Core 都沒問題。


2 則留言:

  1. K大您好,請問一下,我是MAC使用者
    npm install -g yo
    npm install -g generator-aspnet
    這兩行指令我應該下在哪裡才會執行??

    回覆刪除
  2. 首先你要先安裝 nodejs, 然後在 terminal 下那些指令即可。

    回覆刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。