Nguon: Microsoft Learn · .NET 8.0

Hướng dẫn: Gọi Web API ASP.NET Core bằng JavaScript

Nguồn: Tutorial: Call an ASP.NET Core web API with JavaScript

Bởi Rick Anderson

Hướng dẫn này trình bày cách gọi web API ASP.NET Core bằng JavaScript, sử dụng Fetch API.

Yêu cầu tiên quyết

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 to-do. Các event handler (trình xử lý sự kiện) được gắn vào các phần tử trên trang. Các event handler tạo ra các HTTP request đến các action method của web API. Hàm fetch của Fetch API khởi tạo mỗi HTTP request.

Hàm fetch trả về một đối tượng Promise, chứa một HTTP response được biểu diễn dưới dạng đối tượng Response. Một pattern (mẫu) phổ biến là trích xuất response body 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ừ response 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, gọi là đối tượng init, là tùy chọn. init được dùng để cấu hình HTTP request.

  1. Cấu hình ứng dụng để phục vụ file tĩnh (serve static files) và bật default file mapping. Code cần thêm trong Program.cs:
csharp
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 thư mục css bên trong thư mục wwwroot.
  3. Tạo thư mục js bên trong thư mục wwwroot.
  4. Thêm file HTML tên index.html vào thư mục wwwroot. Thay thế nội dung index.html bằng markup sau:

```html <!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">&#10006;</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> ```

  1. Thêm file CSS tên site.css vào thư mục wwwroot/css. Thay thế nội dung site.css bằng các style sau:

```css 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; } ```

  1. Thêm file JavaScript tên site.js vào thư mục wwwroot/js. Thay thế nội dung site.js bằng code sau:

```javascript 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 thay đổi cài đặt launch settings của dự án ASP.NET Core để kiểm thử trang HTML cục bộ:

  1. Mở Properties\launchSettings.json.
  2. Xóa thuộc tính launchUrl để buộc ứng dụng mở tại index.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. Dưới đây là giải thích các request web API.

Lấy danh sách các mục to-do

Trong code sau, một HTTP GET request được gửi đến route api/todoitems:

javascript
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, hàm _displayItems được gọi. Mỗi mục to-do trong tham số mảng được chấp nhận bởi _displayItems được thêm vào một bảng với các nút EditDelete. Nếu request web API thất bại, một lỗi được ghi vào console của trình duyệt.

Thêm một mục to-do

Trong code sau:

javascript
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, hàm getItems được gọi để cập nhật bảng HTML. Nếu request web API thất bại, một lỗi được ghi vào console của trình duyệt.

Cập nhật một mục to-do

Cập nhật mục to-do tương tự như thêm mục; tuy nhiên, có hai điểm khác biệt đáng kể:

javascript
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 to-do

Để xóa một mục to-do, đặt tùy chọn method của request thành DELETE và chỉ định định danh duy nhất của mục trong URL.

javascript
fetch(`${uri}/${id}`, {
  method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));

Tiến đến hướng dẫn tiếp theo để học cách tạo trang trợ giúp web API.