ASP.NET Core: Hướng dẫn gọi ASP.NET Core Web API với JavaScript


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

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

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">&#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>

    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ộ:

  1. Mở Properties\launchSettings.json.
  2. Xóa property 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. 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 EditDelete. 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ữ trong item vào hàm JSON.stringify.
    • headers—chỉ định các header yêu cầu HTTP Accept 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

Nguồn: learn.microsoft.com
» Tiếp: Tổng quan về gRPC trên .NET
« Trước: Định tuyến trong ASP.NET Web API
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!