Ở bài trước chúng ta đã cùng nhau xây dựng các lớp View và Model, hôm nay cùng nhau xây dựng lớp dịch vụ nhé!
Thêm một lớp Service:
Bạn đã tạo một model và một view, trước khi sử dụng chúng trong controller, bạn sẽ phải viết code để lấy các mục công việc của người dùng từ cơ sở dữ liệu.
Bạn có thể viết chúng trực tiếp trong controller nhưng nó là tốt hơn để viết chúng riêng biệt vì khi bạn xây dựng một ứng dụng lớn bạn sẽ phải giải quyết nhiều vấn đề:
– Hiển thị View và xử lý dữ liệu đến: đây là những gì controller đã làm.
– Thực hiện các logic nghiệp vụ, hoặc code và logic liên quan tới nghiệp vụ của ứng dụng. Trong ứng dụng của chúng ta logic nghiệp vụ có nghĩa là các quyết định như đặt ngày đáo hạn mặc định cho các tác vụ mới hoặc hiển thị các công việc chưa hoàn thành. Các ví dụ khác về logic nghiệp vụ bao gồm tính toán tổng chi phí dựa trên giá sản phẩm và thuế suất hoặc kiểm tra xem người chơi có đủ điều kiện thăng cấp trò chơi hay không…
– Lưu trữ và lấy các mục từ cơ sở dữ liệu.
Ngoài ra điều đó còn làm cho việc quản lý và kiểm tra trở nên khó hơn rất nhiều. Thay vào đó, thông thường ứng dụng được chia thành hai, ba hoặc nhiều lớp mà mỗi lớp xử lý một và chỉ một mối quan tâm. Điều này giúp cho controller đơn giản nhất có thể và giúp cho việc quản lý và kiểm tra logic nghiệp vụ trở nên dễ hơn bao giờ hết.
Việc tách ứng dụng như vậy còn được gọi là kiến trúc nhiều tầng. Trong một số trường hợp, các lớp được phân lập trong các dự án hoàn toàn riêng biệt. Điều nhấn mạnh ở đây là việc chia ứng dụng của bạn thành các phần dễ quản lý và tránh việc để các controller hoặc các lớp quá cồng kềnh.
Đối với dự án này, bạn sẽ sử dụng hai lớp ứng dụng: lớp mô tả được tạo để các controller và view tương tác, lớp còn lại chứa các logic nghiệp vụ và mã cơ sở dữ liệu. Lớp trình bày đã tồn tại, vì vậy bước tiếp theo là xây dựng một lớp dịch vụ xử lý logic nghiệp vụ cần làm và lưu chúng vào cơ sở dữ liệu.
Tạo Interface:
Ngôn ngữ C# bao gồm khái niệm về các Interface, trong đó định nghĩa về các phương thức và thuộc tính của một đối tượng tách biệt với lớp thực sự chứa mã cho các phương thức và thuộc tính đó. Các interface giúp bạn dễ dàng tạo các lớp tách rời và dễ kiểm tra. Bạn sẽ sử dụng một interface để thể hiện dịch vụ có thể tương tác với các mục việc cần làm trong cơ sở dữ liệu.
Theo quy ước các Interface được thêm tiền tố ‘I’. Tạo một tệp mới trong thư mục Services:
Services/ITodoItemService.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AspNetCoreTodo.Models;
namespace AspNetCoreTodo.Services
{
public interface ITodoItemService
{
Task<TodoItem[]> GetIncompleteItemsAsync();
}
}
Lưu ý rằng namespace của tệp này là CoreTodo.Services. Namespace là một cách để tổ chức các tệp mã .NET và theo thông lệ, namespace sẽ theo thư mục mà tệp được lưu trữ.
Vì tệp này tham chiếu tới lớp TodoItem trong namespace Todo.Models nên nó cần được khai báo bởi câu lệnh using ở đầu tệp để nhập namespace đó. Nếu không khai báo bạn sẽ nhận được một lỗi như sau:
The type or namespace name ‘TodoItem’ could not be found (are you missing a using directive or an assembly reference?)
Vì đây là một interface nên không có bất kỳ mã thực tế nào ở đây, chỉ có định nghĩa của phương thức GetIncompleteItemsAsync Phương thức này không yêu cầu tham số và trả về Task<TodoItem[]>.
Task tương tự như một hứa, nó được sử dụng ở đây vì phương pháp này là không đồng bộ. Nói cách khác, phương thức có thể không trả về một danh sách các công việc ngay lập tức vì nó cần phải giao tiếp với cơ sở dữ liệu trước.
Tạo lớp Service:
Bây giờ Interface đã được xác định, bạn đã sẵn sàng tạo lớp dịch vụ thực tế? Hiện tại chúng ta sẽ tạo một dữ liệu cứng thay vì lấy nó trong cơ sở dữ liệu để hiểu được cách vận hành của chúng.
Services/FakeTodoItemService.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AspNetCoreTodo.Models;
namespace AspNetCoreTodo.Services
{
public class FakeTodoItemService : ITodoItemService
{
public Task<TodoItem[]> GetIncompleteItemsAsync()
{
var item1 = new TodoItem
{
Title = “Learn ASP.NET Core”,
DueAt = DateTimeOffset.Now.AddDays(1)
};
var item2 = new TodoItem
{
Title = “Build awesome apps”,
DueAt = DateTimeOffset.Now.AddDays(2)
};
return Task.FromResult(new[] { item1, item2 });
}
}
}
Ở đây, FakeTodoItemService thực hiện interface ItodoItemService nhưng luôn trả về một mảng gồm 2 TodoItem. Chúng ta sẽ sử dụng chúng để kiểm tra controller và view, sau đó sẽ kết nối với cơ sở dữ liệu ở phần sau.