ASP.NET Core: Hướng dẫn gọi ASP.NET Core Web API với JavaScript
Bài viết này hướng dẫn cách gọi ASP.NET Core Web API bằng JavaScript, sử dụng Fetch API.
Điều kiện tiên quyết
- Hướng dẫn đầy đủ : Tạo Web API
- Làm quen với CSS, HTML và JavaScript
Gọi Web API bằng JavaScript
Trong phần này, bạn sẽ thêm một trang HTML chứa các form để tạo và quản lý các mục việc cần làm. Trình xử lý sự kiện được gắn vào các phần tử trên trang. Trình xử lý sự kiện tạo ra các yêu cầu HTTP tới các phương thức action của Web API. Hàm fetch
của Fetch API sẽ khởi tạo từng yêu cầu HTTP.
Hàm fetch
trả về một đối tượng Promise, chứa phản hồi HTTP được biểu thị dưới dạng một đối tượng Response
. Một mẫu phổ biến là trích xuất nội dung phản hồi JSON bằng cách gọi hàm json
trên đối tượng Response
. JavaScript cập nhật trang với các chi tiết từ phản hồi của Web API.
Lời gọi fetch
đơn giản nhất chấp nhận một tham số duy nhất đại diện cho route. Tham số thứ hai, được gọi là đối tượng init
, đây là tùy chọn. init
được sử dụng để định cấu hình yêu cầu HTTP.
Định cấu hình ứng dụng để phân phát các file tĩnh và bật ánh xạ file mặc định. Code được đánh dấu sau đây là cần thiết trong Program.cs
:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
1. Tạo thư mục wwwroot trong thư mục gốc của dự án.
2. Tạo một thư mục css bên trong thư mục wwwroot.
3. Tạo một thư mục js bên trong thư mục wwwroot.
4. Thêm một file HTML có tên index.html
vào thư mục wwwroot. Thay thế nội dung index.html
bằng nội dung sau:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>To-do CRUD</title>
<link rel="stylesheet" href="css/site.css" />
</head>
<body>
<h1>To-do CRUD</h1>
<h3>Add</h3>
<form action="javascript:void(0);" method="POST" onsubmit="addItem()">
<input type="text" id="add-name" placeholder="New to-do">
<input type="submit" value="Add">
</form>
<div id="editForm">
<h3>Edit</h3>
<form action="javascript:void(0);" onsubmit="updateItem()">
<input type="hidden" id="edit-id">
<input type="checkbox" id="edit-isComplete">
<input type="text" id="edit-name">
<input type="submit" value="Save">
<a onclick="closeInput()" aria-label="Close">✖</a>
</form>
</div>
<p id="counter"></p>
<table>
<tr>
<th>Is Complete?</th>
<th>Name</th>
<th></th>
<th></th>
</tr>
<tbody id="todos"></tbody>
</table>
<script src="js/site.js" asp-append-version="true"></script>
<script type="text/javascript">
getItems();
</script>
</body>
</html>
5. Thêm file CSS có tên site.css
vào thư mục wwwroot/css. Thay thế nội dung site.css
bằng nội dung sau:
input[type='submit'], button, [aria-label] {
cursor: pointer;
}
#editForm {
display: none;
}
table {
font-family: Arial, sans-serif;
border: 1px solid;
border-collapse: collapse;
}
th {
background-color: #f8f8f8;
padding: 5px;
}
td {
border: 1px solid;
padding: 5px;
}
6. Thêm file JavaScript có tên site.js
vào thư mục wwwroot/js. Thay thế nội dung của site.js
bằng nội dung sau:
const uri = 'api/todoitems';
let todos = [];
function getItems() {
fetch(uri)
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get items.', error));
}
function addItem() {
const addNameTextbox = document.getElementById('add-name');
const item = {
isComplete: false,
name: addNameTextbox.value.trim()
};
fetch(uri, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(response => response.json())
.then(() => {
getItems();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add item.', error));
}
function deleteItem(id) {
fetch(`${uri}/${id}`, {
method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));
}
function displayEditForm(id) {
const item = todos.find(item => item.id === id);
document.getElementById('edit-name').value = item.name;
document.getElementById('edit-id').value = item.id;
document.getElementById('edit-isComplete').checked = item.isComplete;
document.getElementById('editForm').style.display = 'block';
}
function updateItem() {
const itemId = document.getElementById('edit-id').value;
const item = {
id: parseInt(itemId, 10),
isComplete: document.getElementById('edit-isComplete').checked,
name: document.getElementById('edit-name').value.trim()
};
fetch(`${uri}/${itemId}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));
closeInput();
return false;
}
function closeInput() {
document.getElementById('editForm').style.display = 'none';
}
function _displayCount(itemCount) {
const name = (itemCount === 1) ? 'to-do' : 'to-dos';
document.getElementById('counter').innerText = `${itemCount} ${name}`;
}
function _displayItems(data) {
const tBody = document.getElementById('todos');
tBody.innerHTML = '';
_displayCount(data.length);
const button = document.createElement('button');
data.forEach(item => {
let isCompleteCheckbox = document.createElement('input');
isCompleteCheckbox.type = 'checkbox';
isCompleteCheckbox.disabled = true;
isCompleteCheckbox.checked = item.isComplete;
let editButton = button.cloneNode(false);
editButton.innerText = 'Edit';
editButton.setAttribute('onclick', `displayEditForm(${item.id})`);
let deleteButton = button.cloneNode(false);
deleteButton.innerText = 'Delete';
deleteButton.setAttribute('onclick', `deleteItem(${item.id})`);
let tr = tBody.insertRow();
let td1 = tr.insertCell(0);
td1.appendChild(isCompleteCheckbox);
let td2 = tr.insertCell(1);
let textNode = document.createTextNode(item.name);
td2.appendChild(textNode);
let td3 = tr.insertCell(2);
td3.appendChild(editButton);
let td4 = tr.insertCell(3);
td4.appendChild(deleteButton);
});
todos = data;
}
Có thể cần phải thay đổi cài đặt khởi chạy của dự án ASP.NET Core để kiểm tra trang HTML cục bộ:
- Mở Properties\launchSettings.json.
- Xóa property
launchUrl
để buộc ứng dụng mở tạiindex.html
—file mặc định của dự án.
Mẫu này gọi tất cả các phương thức CRUD của Web API. Sau đây là giải thích về các yêu cầu Web API.
Nhận danh sách các việc cần làm
Trong đoạn code sau, một yêu cầu HTTP GET được gửi đến route api/todoitems:
fetch(uri)
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get items.', error));
Khi Web API trả về mã trạng thái thành công, thì hàm _displayItems
sẽ được gọi. Mỗi mục việc cần làm trong tham số mảng được chấp nhận bởi _displayItems
sẽ được thêm vào bảng bằng các nút Edit và Delete. Nếu yêu cầu Web API không thành công thì lỗi sẽ được ghi vào bảng điều khiển của trình duyệt.
Thêm mục việc cần làm
Trong đoạn code sau đây:
- Một biến
item
được khai báo để xây dựng một biểu diễn nghĩa đen đối tượng của mục việc cần làm. - Yêu cầu tìm nạp được định cấu hình với các tùy chọn sau:
method
—chỉ định verb action POST HTTP.body
—chỉ định cách biểu diễn JSON của nội dung yêu cầu. JSON được tạo bằng cách truyền đối tượng bằng chữ được lưu trữ trongitem
vào hàm JSON.stringify.headers
—chỉ định các header yêu cầu HTTPAccept
vàContent-Type
. Cả hai header đều được đặt đểapplication/json
chỉ định loại phương tiện được nhận và gửi tương ứng.
- Yêu cầu HTTP POST được gửi đến route api/todoitems.
function addItem() {
const addNameTextbox = document.getElementById('add-name');
const item = {
isComplete: false,
name: addNameTextbox.value.trim()
};
fetch(uri, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(response => response.json())
.then(() => {
getItems();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add item.', error));
}
Khi Web API trả về mã trạng thái thành công, thì hàm getItems
sẽ được gọi để cập nhật bảng HTML. Nếu yêu cầu Web API không thành công thì lỗi sẽ được ghi vào bảng điều khiển (console) của trình duyệt.
Cập nhật một mục việc cần làm
Cập nhật một mục việc cần làm cũng tương tự như việc thêm một mục; tuy nhiên, có hai điểm khác biệt đáng kể:
- Route được gắn với mã định danh duy nhất của mục cần cập nhật. Ví dụ: api/todoitems/1.
- Verb action HTTP là PUT, như được biểu thị bằng tùy chọn
method
.
fetch(`${uri}/${itemId}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));
Xóa một mục việc cần làm
Để xóa một mục việc cần làm, hãy đặt tùy chọn method
của yêu cầu thành DELETE
và chỉ định mã định danh duy nhất của mục đó trong URL.
fetch(`${uri}/${id}`, {
method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));
Chuyển sang hướng dẫn tiếp theo để tìm hiểu cách tạo trang trợ giúp Web API:
Bắt đầu với Swashbuckle và ASP.NET Core