Nó không phải là thực hành xấu cho một bộ điều khiển để gọi một kho lưu trữ trực tiếp. Một "dịch vụ" chỉ là một công cụ khác, vì vậy hãy sử dụng nó ở nơi có ý nghĩa.
NikolaiDante bình luận:
... Chọn đúng mẫu cho ứng dụng phù hợp. Những gì tôi muốn nói là bạn nên làm cho ứng dụng của bạn nhất quán.
Tôi không nghĩ tính nhất quán là khía cạnh quan trọng nhất. Một lớp "dịch vụ" có nghĩa là gói gọn một số logic mức cao hơn để bộ điều khiển không cần phải thực hiện nó. Nếu không có "logic mức cao hơn" cần thiết cho một hoạt động nhất định, chỉ cần truy cập trực tiếp vào kho lưu trữ.
Để quảng bá tốt tách biệt các mối quan tâm và khả năng kiểm tra, kho lưu trữ phải là một phụ thuộc mà bạn đưa vào dịch vụ thông qua một hàm tạo:
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
Nếu tìm kiếm các bản ghi trong cơ sở dữ liệu cần một số loại truy vấn được tham số hóa, một lớp dịch vụ có thể là một nơi tốt để lấy mô hình xem của bạn và xây dựng một truy vấn được kho lưu trữ thực hiện.
Tương tự, nếu bạn có một mô hình khung nhìn phức tạp cho một biểu mẫu, một lớp dịch vụ có thể gói gọn logic của việc tạo, cập nhật và xóa các bản ghi bằng cách gọi các phương thức trên Mô hình / Thực thể Miền của bạn, sau đó duy trì chúng bằng cách sử dụng kho lưu trữ.
Đi theo hướng ngược lại, nếu bộ điều khiển của bạn cần lấy bản ghi bằng Id của nó, thì việc ủy thác cho một đối tượng dịch vụ cho việc này giống như đánh một cái đinh bấm bằng búa tạ - đó là cách bạn cần nhiều hơn.
Tôi đã thấy rằng bộ điều khiển ở vị trí tốt nhất để xử lý giao dịch hoặc đối tượng Đơn vị công việc . Sau đó, bộ điều khiển hoặc đối tượng Đơn vị công việc sẽ ủy quyền cho các đối tượng dịch vụ cho các hoạt động phức tạp hoặc trực tiếp đến kho lưu trữ cho các hoạt động đơn giản (như tìm bản ghi theo Id).
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
Tôi nghĩ rằng sự kết hợp của các dịch vụ và làm việc với các kho lưu trữ trực tiếp là hoàn toàn chấp nhận được. Bạn có thể đóng gói thêm giao dịch trong một đối tượng Đơn vị công việc nếu bạn cảm thấy cần thiết.
Phân tích trách nhiệm diễn ra như sau:
- Bộ điều khiển kiểm soát dòng chảy của ứng dụng
- Trả về "404 Không tìm thấy" nếu giỏ hàng không có trong cơ sở dữ liệu
- Hiển thị lại biểu mẫu với thông báo xác thực nếu xác thực không thành công
- Lưu giỏ hàng nếu mọi thứ kiểm tra
- Bộ điều khiển ủy quyền cho một lớp dịch vụ để thực thi logic nghiệp vụ trên Mô hình miền (hoặc Thực thể) của bạn. Đối tượng dịch vụ không nên thực hiện logic kinh doanh! Họ thực hiện logic kinh doanh.
- Bộ điều khiển có thể ủy quyền trực tiếp vào kho cho các hoạt động đơn giản
- Các đối tượng dịch vụ lấy dữ liệu trong mô hình khung nhìn và ủy quyền cho Mô hình miền để thực thi logic nghiệp vụ (ví dụ: đối tượng dịch vụ gọi các phương thức trên Mô hình miền trước khi gọi các phương thức trên kho lưu trữ)
- Các đối tượng dịch vụ ủy quyền cho các kho lưu trữ dữ liệu
- Bộ điều khiển nên:
- Quản lý thời gian tồn tại của giao dịch hoặc
- Tạo một đối tượng Đơn vị công việc để quản lý thời gian giao dịch