本篇將介紹 Angular 4 跟 ASP.NET Core Web API 透過 AJAX 的互動,範例是做一個簡單的通訊錄。功能包含新增(Create)、查詢(Read)、修改(Update)跟刪除(Delete),簡稱CRUD。
程式碼延續前兩篇的範例:ASP.NET Core + Angular 4 教學 - 從無到有 ASP.NET Core + Angular 4 教學 - Webpack打包
1. 安裝 NuGet 套件 過往 ASP.NET MVC 是把 MVC 及 Web API 的套件分開,但在 ASP.NET Core 中 MVC 及 Web API 用的套件是相同的,在 NuGet 管理可以找到 Microsoft.AspNetCore.Mvc 並安裝。
2. 建立 Web API 2.1 註冊 Mvc 服務 Startup.cs AddJsonOptions 的 SerializerSettings 可以參考 ASP.NET Core - Web API JSON 序列化設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.DependencyInjection;using Newtonsoft.Json.Serialization;namespace MyWebsite { public class Startup { public void ConfigureServices (IServiceCollection services ) { services.AddMvc() .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver() ); } public void Configure (IApplicationBuilder app ) { app.UseDefaultFiles(); app.UseStaticFiles(); app.UseMvc(); } } }
2.2 Models 我習慣用一個 Result Model 來包裝每個 Service 的回傳內容,不論調用 Web API 成功失敗都用此物件包裝,避免直接 throw exception 到 client,產生 http status 200 以外的狀態。
Models\ResultModel.cs
1 2 3 4 5 6 7 8 9 10 11 namespace MyWebsite.Models { public class ResultModel { public bool IsSuccess { get ; set ; } public string Message { get ; set ; } public object Data { get ; set ; } } }
Models\ContactModel.cs ContactModel是接下來範例主要用到的物件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 namespace MyWebsite.Models { public class ContactModel { public int Id { get ; set ; } public string FirstName { get ; set ; } public string LastName { get ; set ; } public string Email { get ; set ; } public string PhoneNumber { get ; set ; } public string Address { get ; set ; } } }
2.3 Controllers 建立一支符合 RESTful 的 CRUD Controller Controllers\ContactController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 using Microsoft.AspNetCore.Mvc;using MyWebsite.Models;using System.Collections.Generic;using System.Linq;namespace MyWebsite.Controllers { [Route("api/[controller]" ) ] public class ContactController : Controller { private static List<ContactModel> _contacts = new List<ContactModel>(); [HttpGet("{id}" ) ] public ResultModel Get (int id ) { var result = new ResultModel(); result.Data = _contacts.SingleOrDefault(c => c.Id == id); result.IsSuccess = result.Data != null ; return result; } [HttpPost ] public ResultModel Post ([FromBody]ContactModel contact ) { var result = new ResultModel(); contact.Id = _contacts.Count() == 0 ? 1 : _contacts.Max(c => c.Id) + 1 ; _contacts.Add(contact); result.Data = contact.Id; result.IsSuccess = true ; return result; } [HttpPut ] public ResultModel Put ([FromBody]ContactModel contact ) { var result = new ResultModel(); int index; if ((index = _contacts.FindIndex(c => c.Id == contact.Id)) != -1 ) { _contacts[index] = contact; result.IsSuccess = true ; } return result; } [HttpDelete("{id}" ) ] public ResultModel Delete (int id ) { var result = new ResultModel(); int index; if ((index = _contacts.FindIndex(c => c.Id == id)) != -1 ) { _contacts.RemoveAt(index); result.IsSuccess = true ; } return result; } } }
2.4 執行結果 直接用瀏覽器打開 /api/contact/1,就可以看到回傳畫面如下:
如果有安裝 Postman 或類似工具的話可以測測看其他的 methods:
3. 建立 Angular 4 3.1 NgModule 這個範例會用到兩個模組:
Web API 用到的 AJAX 需要 HttpModule。 Form 的 ngModel 互動需要 FormsModule。 wwwroot\app\main.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { NgModule } from "@angular/core" ;import { BrowserModule } from "@angular/platform-browser" ;import { platformBrowserDynamic } from "@angular/platform-browser-dynamic" ;import { HttpModule } from "@angular/http" ;import { FormsModule } from "@angular/forms" ;import { AppComponent } from "./app.component" ;@NgModule({ imports: [ BrowserModule, HttpModule, FormsModule ], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { }platformBrowserDynamic().bootstrapModule(AppModule);
3.2 Component wwwroot\app\app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 import { Component } from "@angular/core" ;import { Http } from "@angular/http" ;import * as models from "./models" @Component({ selector: "my-app" , template: require ("./app.component.html" ) }) export class AppComponent { private api: string = "/api/contact" ; model: models.ContactModel; contactId: number; message: string; constructor (private http: Http) { this .clear(); } find(): void { this .clearMessage(); if (Number (this .contactId) > 0 ) { this .http.get(`${this .api} /${this .contactId} ` ).subscribe( (response) => { let result: models.ResultModel = response.json(); if (!result.IsSuccess) { this .showMessage(`Id: ${this .contactId} not found` ); this .clear(); } else { this .model = result.Data; } }); } else { this .showMessage("Contact Id incorrect!" ); this .clear(); } } add(): void { this .clearMessage(); this .http.post(this .api, this .model).subscribe( (response) => { let result: models.ResultModel = response.json(); if (!result.IsSuccess) { this .showMessage(result.Message); } else { this .showMessage(`Added successfully, Id: ${result.Data} ` ); this .clear(); } }); } save(): void { this .clearMessage(); this .http.put(this .api, this .model).subscribe( (response) => { let result: models.ResultModel = response.json(); if (!result.IsSuccess) { this .showMessage(result.Message); } else { this .showMessage(`Saved successfully, Id: ${this .model.Id} ` ); this .clear(); } }); } delete (): void { this .clearMessage(); this .http.delete(`${this .api} /${this .contactId} ` ).subscribe( (response) => { let result: models.ResultModel = response.json(); if (!result.IsSuccess) { this .showMessage(`Id: ${this .contactId} not found` ); } else { this .showMessage(`Delete successfully, Id: ${this .contactId} ` ); this .clear(); } }); } clear(): void { this .contactId = null ; this .model = new models.ContactModel(); } clearMessage(): void { this .message = "" ; } showMessage(message: string): void { this .message = message; } }
3.3 Models 新增 wwwroot\app\models.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export class ResultModel { public IsSuccess: boolean; public Message: string; public Data: any; } export class ContactModel { public Id: number; public FirstName: string; public LastName: string; public PhoneNumber: string; public Email: string; public Address: string; }
3.4 Views wwwroot\app\app.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <h2 > Contact Card</h2 > <div > <label > Find by Id</label > <input type ="text" name ="contactId" [(ngModel )]="contactId" /> <input type ="button" (click )="find()" value ="Find" /> </div > <br /> <div > {{message}}</div > <br /> <form > <input type ="hidden" name ="Id" [(ngModel )]="model.Id" /> <div > <label > First Name</label > <div > <input type ="text" name ="FirstName" [(ngModel )]="model.FirstName" /> </div > </div > <div > <label > Last Name</label > <div > <input type ="text" name ="LastName" [(ngModel )]="model.LastName" /> </div > </div > <div > <label > Phone Number</label > <div > <input type ="text" name ="PhoneNumber" [(ngModel )]="model.PhoneNumber" /> </div > </div > <div > <label > Email</label > <div > <input type ="text" name ="Email" [(ngModel )]="model.Email" /> </div > </div > <div > <label > Address</label > <div > <input type ="text" name ="Address" [(ngModel )]="model.Address" /> </div > </div > <div > <input *ngIf ="!model.Id" type ="button" (click )="add()" value ="Add" /> <input *ngIf ="model.Id" type ="button" (click )="save()" value ="Save" /> <input *ngIf ="model.Id" type ="button" (click )="delete()" value ="Delete" /> <input type ="button" (click )="clear()" value ="Clear" /> </div > </form >
3.5 執行結果
程式碼下載 asp-net-core-angular-web-api-crud