Ở phần trước một lớp service đã được tạo, ở phần này chúng ta sẽ làm quen với một khái niệm khá là mới ‘Dependency injection‘.
Sử dụng dependency injection:
Quay lại TodoController, thêm một số mã để làm việc với ItodoItemService:
public class TodoController : Controller
{
private readonly ITodoItemService _todoItemService;
public TodoController(ITodoItemService todoItemService)
{
_todoItemService = todoItemService;
}
public IActionResult Index()
{
// Get to-do items from database
// Put items into a model
// Pass the view to a model and render
}
}
Vì ItodoItemService nằm trong namespace Services nên ở đây bạn cũng cần phải khai báo chúng thông qua câu lệnh using ở trên cùng:
using AspNetCoreTodo.Services;
Dòng đầu tiên của lớp khai báo một biến riêng để lưu trữ một tham chiếu đến ItodoItemService. Biến này cho phép bạn sử dụng Service từ phương thức hành động Index.
Phương thức public TodoController(ITodoItemService todoItemService), định nghĩa một hàm khởi tạo cho lớp. Hàm khởi tạo là phươn thức đặc biệt được gọi khi bạn muốn tạo một thể hiện mới của mộ lớp. Bằng cách thêm một tham số ItodoItemService vào hàm khởi tạo, bạn đã quy định rằng để tạo một TodoController, bạn sẽ cần cung cấp 1 đối tượng khớp với interface ItodoItemService.
Bây giờ cuối cùng chúng ta cũng có thể sử dụng ItodoItemService thông qua biến private đã khai báo trong phương thức Index để nhận các công việc từ lớp Service:
public IActionResult Index()
{
var items = await _todoItemService.GetIncompleteItemsAsync();
// …
}
Lưu ý GetIncompleteItemsAsync là phương thức trả về một Task<TodoItem[]> không có kết quả ngay lập tức, nên ở đây bạn có thể sử dụng từ khóa await để đảm bảo mã của bạn đợi cho đến khi kết quả sẵn sàng trước khi tiếp tục.
Task được sử dụng phổ biến khi bạn gọi tới cơ sở dữ liệu hoặc API, nó sẽ không trả về kết quả thực cho tới khi có phản hồi. Nếu bạn đã sử dụng callback trong Javascript thì điều này cũng tương tự.
Nếu trong Javascript bạn phải vất vả để giải quyết thứ gọi là ‘bất đồng bộ’ thì ở đây bạn có thể yên tâm hơn vì việc sử lý bất đồng bộ trong .Net dễ dàng hơn nhiều nhờ vào từ khóa await. Await cho phép mã của bạn dừng trên một hoạt động không đồng bộ. Trong khi đó ứng dụng của bạn không bị chặn, bởi vì nó có thể xử lý các yêu cầu khác khi cần.
Điều duy nhất ở đây là bạn cần cập nhật phương thức Index trả về Task<IActionResult> thay vì IActionResult và đánh dấu nó là async:
public async Task<IActionResult> Index()
{
var items = await _todoItemService.GetIncompleteItemsAsync();
// Put items into a model
// Pass the view to a model and render
}
Đến lúc này bạn đã tạo TodoController phụ thuộc vào ItodoItemService interface, nhưng bạn chưa nói với Asp.Net Core rằng bạn muốn FakeTodotemService là dịch vụ thực tế được sử dụng trong chương trình. Điều này có thể là hiển nhiên trong trường hợp này vì bạn chỉ có một lớp triển khai ItodoItemService, nhưng sau này bạn sẽ có nhiều lớp thực hiện cùng một interface, vì vậy chúng ta nên làm cho nó rõ ràng.
Khai báo lớp cụ thể sẽ sử dụng cho mỗi interface được thực hiện trong phương thức ConfigureService của lớp startup. Công việc của ConfigureService là thêm mọi thứ vào phân vùng service hoặc bộ sưu tập các service mà Asp.Net Core biết. Dòng services.AddMvc thêm các service mà hệ thống Asp.Net Core cần. Bất kỳ dịch vụ nào bạn muốn sử dụng trong ứng dụng của bạn phải được thêm vào phân vùng dịch vụ trong ConfigureService:
Thêm dòng sau vào bất kỳ đâu trong phương thức ConfigureServices:
services.AddSingleton<ITodoItemService, FakeTodoItemService>();
Dòng này báo cho Asp.Net Core sử dụng FakeTodoItemService bất cứ khi nào giao diện ItodoItemService được yêu cầu trong hàm khởi tạo hoặc bất kỳ nơi nào khác.
AddSingleton thêm dịch vụ của bạn vào phân vùng dịch vụ dưới dạng đơn lẻ. Điều này có nghĩa là chỉ có một bản sao của FakeTodoItemService được tạo và nó được sử dụng lại bất cứ khi nào dịch vụ được yêu cầu. Sau này khi bạn viết một lớp dịch vụ khác giao tiếp với cơ sở dữ liệu, bạn sẽ sử dụng một cách tiếp cận khác được gọi là Scoped, chúng ta sẽ đi sâu vào nó hơn ở phần sau khi chúng ta làm với cơ sở dữ liệu.
Khi một yêu cầu được chuyển đến TodoController, Asp.Net Core sẽ xem xét các dịch vụ có sẵn và tự động cung cấp FakeTodoItemService khi controller yêu cầu ItodoItemService. Vì các dịch vụ được thêm từ phân vùng dịch vụ, nên được gọi là dependency injection.