ASP.NET Core: Kích hoạt các hoạt động CRUD trong ASP.NET Web API


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

Tải xuống dự án đã hoàn thành

Hướng dẫn này cho thấy cách hỗ trợ các hoạt động CRUD trong dịch vụ HTTP bằng API Web ASP.NET cho ASP.NET 4.x.

Các phiên bản phần mềm được sử dụng trong hướng dẫn

  • Visual Studio 2012
  • API Web 1 (cũng hoạt động với API Web 2)

CRUD là viết tắt của "Create, Read, Update và Delete", là bốn thao tác cơ sở dữ liệu cơ bản. Nhiều dịch vụ HTTP cũng mô hình hóa các hoạt động CRUD thông qua các API tương tự REST hoặc API REST.

Trong hướng dẫn này, bạn sẽ xây dựng một API web rất đơn giản để quản lý danh sách sản phẩm (product). Mỗi sản phẩm sẽ chứa tên (name), giá (price) và danh mục (category) (chẳng hạn như "toys" hoặc "hardware"), cùng với ID sản phẩm.

API sản phẩm sẽ hiển thị các phương thức sau.

Action Phương thức HTTP URI tương đối
Nhận danh sách tất cả các sản phẩm GET /api/products
Nhận sản phẩm theo ID GET /api/products/id
Nhận sản phẩm theo danh mục GET /api/products?category=category
Tạo một sản phẩm mới POST /api/products
Cập nhật một sản phẩm PUT /api/products/id
Xóa một sản phẩm DELETE /api/products/id

Lưu ý rằng một số URI bao gồm cả ID sản phẩm trong đường dẫn. Ví dụ: để nhận sản phẩm có ID là 28, khách hàng sẽ gửi yêu cầu GET cho http://hostname/api/products/28.

Tài nguyên

API sản phẩm định nghĩa các URI cho hai loại tài nguyên:

Resource URI
Danh sách tất cả các sản phẩm. /api/products
Một sản phẩm riêng lẻ. /api/products/id

Các phương thức

Bốn phương thức HTTP chính (GET, PUT, POST và DELETE) có thể được ánh xạ tới các hoạt động CRUD như sau:

  • GET truy xuất biểu diễn của tài nguyên tại một URI được chỉ định. GET sẽ không có tác dụng phụ trên máy chủ.
  • PUT cập nhật tài nguyên tại một URI được chỉ định. PUT cũng có thể được sử dụng để tạo tài nguyên mới tại một URI được chỉ định, nếu máy chủ cho phép khách hàng chỉ định các URI mới. Đối với hướng dẫn này, API sẽ không hỗ trợ tạo (creation) thông qua PUT.
  • POST tạo một tài nguyên mới. Máy chủ gán URI cho đối tượng mới và trả về URI này như một phần của thông báo phản hồi.
  • DELETE xóa tài nguyên tại một URI được chỉ định.

Lưu ý: Phương thức PUT thay thế toàn bộ thực thể product. Nghĩa là, khách hàng phải gửi bản trình bày đầy đủ về sản phẩm được cập nhật. Nếu bạn muốn hỗ trợ cập nhật một phần, phương thức PATCH được ưu tiên. Hướng dẫn này không triển khai PATCH.

Tạo một dự án API Web mới

Bắt đầu bằng cách chạy Visual Studio và chọn New Project từ trang Start. Hoặc từ menu File, chọn New rồi chọn Project.

Trong ngăn Templates, chọn Installed Templates và mở rộng nút Visual C#. Trong Visual C#, chọn Web. Trong danh sách mẫu dự án, chọn ASP.NET MVC 4 Web Application. Đặt tên cho dự án là "ProductStore" và nhấp vào OK.

Ảnh chụp màn hình cửa sổ dự án mới, hiển thị các tùy chọn menu và tô sáng đường dẫn để tạo Ứng dụng web ASP dot NET MVC 4.

Trong hộp thoại New ASP.NET MVC 4 Project, chọn Web API và nhấp vào OK.

Ảnh chụp màn hình của dự án ASP dot NET mới, hiển thị hình ảnh đóng hộp của các mẫu có sẵn và làm nổi bật mẫu API Web, có màu xanh lam.

Thêm model

Model là một đối tượng đại diện cho dữ liệu trong ứng dụng của bạn. Trong ASP.NET Web API, bạn có thể sử dụng các đối tượng CLR được định kiểu mạnh làm mô hình và chúng sẽ tự động được tuần tự hóa thành XML hoặc JSON cho máy khách.

Đối với API ProductStore, dữ liệu của ta bao gồm các sản phẩm, vì vậy ta sẽ tạo một lớp mới có tên Product.

Nếu Solution Explorer chưa hiển thị, hãy nhấp vào menu View và chọn Solution Explorer. Trong Solution Explorer, bấm chuột phải vào thư mục Models. Từ menu ngữ cảnh, chọn Add, sau đó chọn Class. Đặt tên cho class là "Product".

Ảnh chụp màn hình menu trình khám phá giải pháp, đánh dấu lựa chọn dành cho mô hình để hiển thị menu bổ sung nhằm chọn tùy chọn thêm lớp.

Thêm các property sau vào lớp Product.

namespace ProductStore.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

Thêm một Repository

Chúng ta cần lưu trữ một collection các sản phẩm. Bạn nên tách collection khỏi việc triển khai dịch vụ. Bằng cách đó, ta có thể thay đổi kho dự phòng mà không cần viết lại lớp dịch vụ. Kiểu thiết kế này được gọi là mẫu repository. Bắt đầu bằng cách định nghĩa generic interface cho repository.

Trong Solution Explorer, bấm chuột phải vào thư mục Models. Chọn Add, sau đó chọn New Item.

Ảnh chụp màn hình menu trình khám phá giải pháp, trong đó làm nổi bật tùy chọn mô hình và hiển thị menu để thêm mục mới.

Trong ngăn Templates, chọn Installed Templates và mở rộng nút C#. Trong C#, chọn Code. Trong danh sách code template, chọn Interface. Đặt tên cho interface là "INProductRepository".

Ảnh chụp màn hình ngăn mẫu, hiển thị menu mẫu đã cài đặt, trong đó làm nổi bật các tùy chọn mã và giao diện bằng màu xám.

Thêm cách thực hiện sau:

namespace ProductStore.Models
{
    public interface IProductRepository
    {
        IEnumerable<Product> GetAll();
        Product Get(int id);
        Product Add(Product item);
        void Remove(int id);
        bool Update(Product item);
    }
}

Bây giờ hãy thêm một lớp khác vào thư mục Models, có tên là "ProductRepository". Lớp này sẽ thực thi interface IProductRepository. Thêm cách thực hiện sau:

namespace ProductStore.Models
{
    public class ProductRepository : IProductRepository
    {
        private List<Product> products = new List<Product>();
        private int _nextId = 1;

        public ProductRepository()
        {
            Add(new Product { Name = "Tomato soup", Category = "Groceries", Price = 1.39M });
            Add(new Product { Name = "Yo-yo", Category = "Toys", Price = 3.75M });
            Add(new Product { Name = "Hammer", Category = "Hardware", Price = 16.99M });
        }

        public IEnumerable<Product> GetAll()
        {
            return products;
        }

        public Product Get(int id)
        {
            return products.Find(p => p.Id == id);
        }

        public Product Add(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            item.Id = _nextId++;
            products.Add(item);
            return item;
        }

        public void Remove(int id)
        {
            products.RemoveAll(p => p.Id == id);
        }

        public bool Update(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            int index = products.FindIndex(p => p.Id == item.Id);
            if (index == -1)
            {
                return false;
            }
            products.RemoveAt(index);
            products.Add(item);
            return true;
        }
    }
}

Repository sẽ lưu giữ list trong bộ nhớ cục bộ. Điều này là ổn đối với hướng dẫn này, nhưng trong ứng dụng thực, bạn sẽ lưu trữ dữ liệu bên ngoài, cơ sở dữ liệu hoặc trong bộ lưu trữ đám mây. Mẫu repository sẽ giúp việc thay đổi triển khai sau này dễ dàng hơn.

Thêm Controller API Web

Nếu bạn đã làm việc với ASP.NET MVC thì bạn đã quen với controller. Trong ASP.NET Web API, controller là lớp xử lý các yêu cầu HTTP từ máy khách. Trình hướng dẫn New Project đã tạo hai controller cho bạn khi tạo dự án. Để xem chúng, hãy mở rộng thư mục Controllers trong Solution Explorer.

  • HomeController là controller ASP.NET MVC truyền thống. Nó chịu trách nhiệm phục vụ các trang HTML cho trang web và không liên quan trực tiếp đến API web của ta.
  • ValuesController là một controller WebAPI mẫu.

Hãy tiếp tục và xóa ValuesController bằng cách nhấp chuột phải vào tệp trong Solution Explorer và chọn Delete. Bây giờ thêm một controller mới, như sau:

Trong Solution Explorer, bấm chuột phải vào thư mục Controllers. Chọn Add rồi chọn Controller.

Ảnh chụp màn hình menu trình khám phá giải pháp, làm nổi bật danh mục bộ điều khiển, sau đó đưa ra một menu khác, đánh dấu đường dẫn để thêm bộ điều khiển.

Trong trình hướng dẫn Add Controller, hãy đặt tên cho controller là "ProductsController". Trong danh sách thả xuống Template, chọn Empty API Controller. Sau đó nhấp vào Add.

Ảnh chụp màn hình cửa sổ thêm bộ điều khiển, hiển thị trường tên bộ điều khiển để nhập tên và danh sách mẫu thả xuống, bên dưới các tùy chọn khung.

Ghi chú

Không cần thiết phải đặt controller của bạn vào thư mục có tên Controllers. Tên thư mục không quan trọng; nó chỉ đơn giản là một cách thuận tiện để sắp xếp các tập tin nguồn của bạn.

Trình hướng dẫn Add Controller sẽ tạo một tệp có tên ProductsController.cs trong thư mục Controllers. Nếu tệp này chưa được mở, hãy bấm đúp vào tệp để mở. Thêm câu lệnh using sau:

using ProductStore.Models;

Thêm trường chứa thể hiện IProductRepository.

public class ProductsController : ApiController
{
    static readonly IProductRepository repository = new ProductRepository();
}

Ghi chú

Gọi new ProductRepository() trong controller không phải là thiết kế tốt nhất vì nó liên kết controller với việc triển khai cụ thể của IProductRepository. Để có cách tiếp cận tốt hơn, hãy xem Sử dụng Trình giải quyết phụ thuộc API Web.

Nhận tài nguyên

API ProductStore sẽ hiển thị một số hành động "read" dưới dạng phương thức HTTP GET. Mỗi hành động sẽ tương ứng với một phương thức trong lớp ProductsController.

Action Phương thức HTTP URI tương đối
Nhận danh sách tất cả các sản phẩm GET /api/products
Nhận sản phẩm theo ID GET /api/products/id
Nhận sản phẩm theo danh mục GET /api/products?category=category

Để có được danh sách tất cả các sản phẩm, hãy thêm phương thức sau vào lớp ProductsController:

public class ProductsController : ApiController
{
    public IEnumerable<Product> GetAllProducts()
    {
        return repository.GetAll();
    }
    // ....
}

Tên phương thức bắt đầu bằng "Get", do đó, theo quy ước, nó ánh xạ tới các yêu cầu GET. Ngoài ra, còn một lý do nữa vì phương thức này không có tham số nên nó ánh xạ tới một URI không chứa phân đoạn "id" trong đường dẫn.

Để lấy sản phẩm theo ID, hãy thêm phương thức này vào lớp ProductsController:

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound); 
    }
    return item;
}

Tên phương thức này cũng bắt đầu bằng "Get", nhưng phương thức này có tham số có tên id. Tham số này được ánh xạ tới phân đoạn "id" của đường dẫn URI. Framework API Web ASP.NET tự động chuyển đổi ID thành kiểu dữ liệu chính xác (int) cho tham số.

Phương thức GetProduct đưa ra một ngoại lệ thuộc loại HttpResponseException nếu id không hợp lệ. Ngoại lệ này sẽ được framework dịch thành lỗi 404 (Không tìm thấy).

Cuối cùng, thêm phương thức tìm sản phẩm theo danh mục:

public IEnumerable<Product> GetProductsByCategory(string category)
{
    return repository.GetAll().Where(
        p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}

Nếu URI yêu cầu có chuỗi truy vấn, API Web sẽ cố gắng khớp các tham số truy vấn với các tham số trên phương thức controller. Do đó, URI có dạng "api/products?category=category" sẽ ánh xạ tới phương thức này.

Tạo tài nguyên

Tiếp theo, chúng ta sẽ thêm một phương thức vào lớp ProductsController để tạo một sản phẩm mới. Đây là cách thực hiện đơn giản của phương thức này:

// Not the final implementation!
public Product PostProduct(Product item)
{
    item = repository.Add(item);
    return item;
}

Lưu ý hai điều về phương pháp này:

  • Tên phương thức bắt đầu bằng "Post ...". Để tạo một sản phẩm mới, thì client sẽ gửi yêu cầu HTTP POST.
  • Phương thức này lấy một tham số thuộc loại Product. Trong API Web, các tham số có kiểu phức tạp sẽ được giải tuần tự hóa khỏi phần thân yêu cầu (request body). Do đó, ta mong đợi client gửi bản trình bày được tuần tự hóa của một đối tượng sản phẩm ở định dạng XML hoặc JSON.

Việc triển khai này sẽ hoạt động nhưng nó chưa hoàn chỉnh. Lý tưởng nhất là ta muốn phản hồi HTTP bao gồm những nội dung sau:

  • Mã phản hồi: Theo mặc định, framework API Web đặt mã trạng thái phản hồi thành 200 (OK). Nhưng theo giao thức HTTP/1.1, khi yêu cầu POST dẫn đến việc tạo tài nguyên, máy chủ sẽ phản hồi với trạng thái 201 (Created).
  • Vị trí: Khi máy chủ tạo tài nguyên, nó phải bao gồm URI của tài nguyên mới trong header Location của phản hồi.

ASP.NET Web API giúp bạn dễ dàng thao tác với thông báo phản hồi HTTP. Đây là cách thực hiện được cải thiện:

public HttpResponseMessage PostProduct(Product item)
{
    item = repository.Add(item);
    var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);

    string uri = Url.Link("DefaultApi", new { id = item.Id });
    response.Headers.Location = new Uri(uri);
    return response;
}

Lưu ý rằng kiểu trả về của phương thức hiện là HttpResponseMessage. Bằng cách trả về HttpResponseMessage thay vì Product, ta có thể kiểm soát chi tiết của thông báo phản hồi HTTP, bao gồm mã trạng thái và header Location.

Phương thức CreateResponse tạo một HttpResponseMessage và tự động ghi một biểu diễn được tuần tự hóa của đối tượng Product vào phần nội dung của thông báo phản hồi.

Ghi chú

Ví dụ này không xác thực file Product. Để biết thông tin về model validation, hãy xem Model validation trong API Web ASP.NET.

Cập nhật tài nguyên

Cập nhật sản phẩm bằng PUT rất đơn giản:

public void PutProduct(int id, Product product)
{
    product.Id = id;
    if (!repository.Update(product))
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

Tên phương thức bắt đầu bằng "Put...", do đó API Web khớp nó với các yêu cầu PUT. Phương thức này có hai tham số, ID sản phẩm và sản phẩm được cập nhật. Tham số id được lấy từ đường dẫn URI và tham số product được giải tuần tự hóa khỏi nội dung yêu cầu. Theo mặc định, framework API Web ASP.NET lấy các loại tham số đơn giản từ route và các kiểu phức tạp từ phần thân yêu cầu.

Xóa tài nguyên

Để xóa tài nguyên, ta định nghĩa phương thức "Delete...".

public void DeleteProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    repository.Remove(id);
}

Nếu yêu cầu DELETE thành công, nó có thể trả về trạng thái 200 (OK) với phần nội dung thực thể mô tả trạng thái; trạng thái 202 (Accepted) nếu việc xóa vẫn đang chờ xử lý; hoặc trạng thái 204 (No Content) không có nội dung thực thể. Trong trường hợp này, phương thức DeleteProduct có kiểu trả về là void, vì vậy ASP.NET Web API sẽ tự động dịch mã này thành mã trạng thái 204 (No Content).

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