hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
    • Cấu trúc dữ liệu và giải thuật
    • Lập Trình C# Cơ Bản
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • ASP.NET Core MVC
Kiến trúc Onion trong ASP.NET Core

Kiến trúc Onion trong ASP.NET Core

  • 26-06-2025
  • Toanngo92
  • 0 Comments

Mục lục

  • 9.1 Khái niệm về Kiến trúc Onion
    • Tight Coupling (Ràng buộc chặt)
    • Loose Coupling (Ràng buộc lỏng)
  • 9.1.1 Đảo ngược điều khiển (Inversion of Control – IoC)
  • 9.1.2 Nguyên lý Đảo ngược Phụ thuộc (Dependency Inversion Principle – DIP)
    • Để áp dụng IoC và DIP hiệu quả, cần thực hiện:
    • Hình 9.1: Triển khai IoC và DIP
  • 9.2 Tại sao sử dụng Kiến trúc Onion?
    • Lợi ích chính của Onion Architecture:
  • 9.3 Các lớp trong Kiến trúc Onion
    • Hình 9.2: Kiến trúc truyền thống
    • Hình 9.3: Các lớp trong Kiến trúc Onion
  • 9.3 Các lớp của Kiến trúc Onion
    • Hình 9.2: Kiến trúc truyền thống
    • Hình 9.3: Các lớp của Kiến trúc Onion
  • Các lớp khác nhau trong Kiến trúc Onion:
  • 9.4 Khám phá nguyên lý DIP (Dependency Inversion Principle)
  • 9.4.2 Ví dụ thực tế về triển khai DIP
    • 1. Trừu tượng hóa dịch vụ (Service Abstraction)
      • Mã ví dụ 1:
    • 2. Module cấp cao sử dụng abstraction
      • Mã ví dụ 2:
  • 9.5 Truy cập dữ liệu và Kho lưu trữ trong tầng Hạ tầng
    • 9.5.1 Tầng Hạ tầng (Infrastructure Layer)
    • 9.5.2 Trách nhiệm của Tầng Hạ tầng
  • 9.5.3 Triển khai Truy cập Dữ liệu bằng Repository
  • 9.5.3 (tiếp theo) Triển khai Truy cập Dữ liệu bằng Repository
    • 1. Định nghĩa Interface Repository
      • Đoạn mã 3
    • 2. Cài đặt Repository
      • Đoạn mã 4
    • 3. Tiêm Repository vào Service
      • Đoạn mã 5
  • 9.6 Ưu điểm của Kiến trúc Onion
    • Các ưu điểm chính:
    • Nguyên tắc thực hiện kiến trúc Onion:
    • Kết luận

9.1 Khái niệm về Kiến trúc Onion

Kiến trúc Onion là một mô hình được giới thiệu vào năm 2008 nhằm giải quyết các vấn đề liên quan đến sự phụ thuộc trong thiết kế ứng dụng. Các vấn đề chính trong thiết kế truyền thống là ràng buộc chặt (tight coupling) và sự lo ngại về khả năng phân chia.

Tight Coupling (Ràng buộc chặt)

Trong lập trình hướng đối tượng, khi một lớp phụ thuộc mạnh vào lớp khác, thì bất kỳ thay đổi nào trong lớp phụ thuộc cũng ảnh hưởng đến lớp hiện tại. Điều này được gọi là ràng buộc chặt – thường thấy trong các chương trình nhỏ, nhưng không phù hợp cho các ứng dụng lớn, phức tạp.

Loose Coupling (Ràng buộc lỏng)

Trong ràng buộc lỏng, hai đối tượng không phụ thuộc trực tiếp vào nhau. Một đối tượng có thể thay đổi mà không làm ảnh hưởng đến đối tượng kia. Điều này làm tăng tính linh hoạt và khả năng bảo trì của phần mềm.


9.1.1 Đảo ngược điều khiển (Inversion of Control – IoC)

Trong thiết kế hướng đối tượng, nhiều phụ thuộc giữa các đối tượng và thành phần có thể gây khó khăn trong quản lý. Inversion of Control (IoC) là một nguyên lý cấp cao giúp tách biệt trách nhiệm của các lớp, cho phép tạo ra các mối quan hệ ràng buộc lỏng hơn.

  • Khi áp dụng IoC, các lớp không còn chịu trách nhiệm tạo hoặc kiểm soát các đối tượng khác – điều này giúp giảm sự phụ thuộc và cải thiện khả năng bảo trì, kiểm thử, và mở rộng.
  • Trong phương pháp truyền thống, mã gọi trực tiếp đến thư viện. Trong khi đó, với IoC, framework sẽ điều khiển luồng thay vì lập trình viên.
  • Trong ASP.NET Core, IoC thường được hiện thực thông qua Dependency Injection (DI), nơi các tham số được truyền thông qua constructor hoặc thuộc tính.

9.1.2 Nguyên lý Đảo ngược Phụ thuộc (Dependency Inversion Principle – DIP)

DIP là một trong những nguyên lý cốt lõi trong SOLID, được giới thiệu bởi Robert C. Martin:

  • DIP khuyến khích việc thiết kế phần mềm sao cho các mô-đun cấp cao không phụ thuộc trực tiếp vào các mô-đun cấp thấp.
  • Cả hai loại mô-đun nên phụ thuộc vào các abstraction (lớp trừu tượng).
  • Abstraction không nên phụ thuộc vào chi tiết; thay vào đó, chi tiết nên phụ thuộc vào abstraction.

Điều này giúp:

  • Giảm ràng buộc chặt
  • Tăng khả năng kiểm thử
  • Cải thiện khả năng mở rộng và bảo trì

Để áp dụng IoC và DIP hiệu quả, cần thực hiện:

  • Áp dụng IoC
  • Áp dụng DIP bằng abstraction
  • Áp dụng Dependency Injection
  • Sử dụng container DI
  • Tạo các lớp ràng buộc lỏng

Hình 9.1: Triển khai IoC và DIP

Vòng tròn thể hiện quá trình chuyển đổi từ các lớp ràng buộc chặt thành các lớp ràng buộc lỏng bằng cách:

  • Sử dụng pattern factory (mẫu nhà máy)
  • Tạo abstraction
  • Triển khai DI
  • Sử dụng container IoC

9.2 Tại sao sử dụng Kiến trúc Onion?

Kiến trúc Onion được xây dựng để giảm thiểu sự phụ thuộc giữa các lớp, từ đó giúp dễ dàng quản lý và kiểm thử.

  • Nó khắc phục các vấn đề của kiến trúc N-layers truyền thống.
  • Giúp tách biệt các mối quan tâm (Separation of Concerns).
  • Tăng tính linh hoạt, khả năng mở rộng, và tái sử dụng.

Lợi ích chính của Onion Architecture:

  • Các lớp được tổ chức thành các vòng đồng tâm (concentric layers)
  • Lớp domain luôn nằm ở trung tâm – dựa trên logic nghiệp vụ, không phụ thuộc vào UI hay cơ sở dữ liệu.
  • Giúp giao tiếp hiệu quả giữa các lớp
  • Hỗ trợ các nguyên lý như testability, maintainability, consistency

Kiến trúc Onion được đề xuất bởi Jeffrey Palermo.


9.3 Các lớp trong Kiến trúc Onion

Hình 9.2: Kiến trúc truyền thống

  • Bao gồm: Data Layer → Business Logic Layer → UI Layer → Hạ tầng.
  • Có xu hướng phụ thuộc từ trên xuống dưới.

Hình 9.3: Các lớp trong Kiến trúc Onion

  • Lớp trung tâm: Domain Entities
  • Bao quanh bởi: Repository, Service, UI
  • Lớp ngoài cùng có thể thay đổi thường xuyên (như giao diện người dùng – UI)

Lưu ý: Số lượng lớp có thể thay đổi tùy theo ứng dụng, nhưng lớp domain luôn ở trung tâm. Các lớp bên ngoài có thể bị thay đổi, nhưng domain thì không nên bị ảnh hưởng.

Dưới đây là bản dịch chi tiết phần tiếp theo từ các trang bạn gửi, nối tiếp phần trước về Onion Architecture trong ASP.NET Core – Phần I:


9.3 Các lớp của Kiến trúc Onion

Hình 9.2 và 9.3 hiển thị kiến trúc truyền thống và các lớp khác nhau trong kiến trúc Onion tương ứng:

Hình 9.2: Kiến trúc truyền thống

  • Data Layer: xử lý lưu trữ dữ liệu.
  • Business Logic Layer: xử lý logic nghiệp vụ.
  • UI Layer: tương tác người dùng.
  • Infrastructure: các phần hỗ trợ không liên quan trực tiếp tới logic nghiệp vụ.

Hình 9.3: Các lớp của Kiến trúc Onion

  • Lõi trung tâm: Domain Entities (thực thể miền)
  • Bao quanh lần lượt bởi: Repository → Service → UI

Lưu ý: Lớp Domain luôn ở trung tâm. Số lượng lớp có thể thay đổi tùy ứng dụng, nhưng Domain Entities không bao giờ bị thay đổi bởi các lớp bên ngoài. Các lớp ngoài như UI thường xuyên thay đổi.


Các lớp khác nhau trong Kiến trúc Onion:

  • Lớp Domain Entities: Lớp sâu nhất, chứa tất cả thực thể miền của ứng dụng. Đây là các mô hình cơ sở dữ liệu được tạo theo hướng code-first.
  • Lớp Repository: Là cầu nối giữa service và mô hình. Quản lý migration, context truy xuất dữ liệu, sử dụng mẫu thiết kế repository.
  • Lớp Service: Chứa các API có thể công bố. Đóng vai trò trung gian giữa repository và lớp giao diện. Bao gồm cả logic nghiệp vụ và các interface độc lập nhằm đảm bảo separation of concerns và loose coupling.
  • Lớp UI (hoặc Unit Test): Là giao diện người dùng hoặc lớp kiểm thử, chỉ đơn giản là chương trình frontend giao tiếp với API.

9.4 Khám phá nguyên lý DIP (Dependency Inversion Principle)

Nguyên lý DIP bao gồm hai nguyên lý cốt lõi:

  1. Các module cấp cao không được phụ thuộc vào module cấp thấp. Cả hai phải phụ thuộc vào abstraction.
    • Module cấp cao: chứa logic nghiệp vụ hoặc các chức năng đặc thù.
    • Module cấp thấp: xử lý chi tiết kỹ thuật hoặc giao tiếp thấp.
    • Cả hai cần phụ thuộc vào abstraction thay vì lẫn nhau.
  2. Abstraction không phụ thuộc vào chi tiết. Chi tiết phải phụ thuộc vào abstraction.
    • Abstraction là interface hoặc abstract class định nghĩa hành vi.
    • Chi tiết là phần hiện thực cụ thể (implementation) tuân theo abstraction.

9.4.2 Ví dụ thực tế về triển khai DIP

Các nhà phát triển có thể triển khai DIP trong thực tế bằng cách thiết kế phần mềm dựa trên abstraction thay vì các class cụ thể.

1. Trừu tượng hóa dịch vụ (Service Abstraction)

Ví dụ: một module cấp cao cần thực hiện logging, nhưng không muốn gắn chặt với loại logging cụ thể. Có thể định nghĩa một interface:

Mã ví dụ 1:

public interface ILogger
{
    void Log(string message);
}

2. Module cấp cao sử dụng abstraction

Mã ví dụ 2:

public class HighLevelModule
{
    private readonly ILogger logger;

    public HighLevelModule(ILogger logger)
    {
        this.logger = logger;
    }

    public void PerformOperation()
    {
        // Logic cấp cao
        logger.Log("Operation performed successfully.");
    }
}

Module này có thể sử dụng bất kỳ implementation nào của ILogger như file logger, database logger, hoặc console logger. Như vậy, module cấp cao không bị phụ thuộc vào các chi tiết hiện thực cụ thể.


9.5 Truy cập dữ liệu và Kho lưu trữ trong tầng Hạ tầng

Trong kiến trúc phần mềm hiện đại, tầng hạ tầng (infrastructure) là nền tảng của ứng dụng, quản lý các cơ chế cấp thấp như truy xuất dữ liệu, giao tiếp bên ngoài và các mối quan tâm hạ tầng khác.

Đây là một trong những lớp trong kiến trúc Onion, đảm bảo separation of concerns và tổ chức code rõ ràng.


9.5.1 Tầng Hạ tầng (Infrastructure Layer)

  • Tầng này quản lý các cơ chế cấp thấp cần thiết cho ứng dụng hoạt động.
  • Bao gồm:
    • Truy cập dữ liệu (data access)
    • Giao tiếp với hệ thống bên ngoài
    • Quản lý cấu hình, v.v.

9.5.2 Trách nhiệm của Tầng Hạ tầng

Xem trong Hình 9.4, gồm:

  1. Truy cập dữ liệu: tương tác với hệ lưu trữ dữ liệu như CSDL, thông qua DAO hoặc repository.
  2. Tích hợp hệ thống: tương tác với hệ thống ngoài như API hoặc dịch vụ web.
  3. Framework và thư viện: sử dụng framework, thư viện bên ngoài hỗ trợ chức năng.
  4. Cấu hình: quản lý cấu hình, thông tin môi trường, thông số kết nối, v.v.

9.5.3 Triển khai Truy cập Dữ liệu bằng Repository

Để triển khai việc truy cập dữ liệu:

  • Tạo interface định nghĩa các hành động cơ bản (CRUD): Create, Read, Update, Delete.
  • Việc này tách chi tiết hiện thực ra khỏi logic nghiệp vụ, đảm bảo tính đồng nhất và dễ mở rộng.

Bước 1: Định nghĩa Interface Repository (phần này sẽ tiếp tục ở trang kế tiếp).


Nếu bạn muốn mình dịch tiếp phần còn lại (từ bước 1 trở đi), hãy gửi thêm trang tiếp theo – mình sẽ tiếp tục bản dịch liền mạch.

Dưới đây là bản dịch tiếp theo từ các trang bạn đã gửi, nối tiếp phần trước về Onion Architecture trong ASP.NET Core – Phần I:


9.5.3 (tiếp theo) Triển khai Truy cập Dữ liệu bằng Repository

1. Định nghĩa Interface Repository

Đoạn mã sau định nghĩa một interface dùng để thực hiện các thao tác dữ liệu (CRUD):

Đoạn mã 3

public interface IRepository<T>
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    T GetById(int id);
    IEnumerable<T> GetAll();
}

2. Cài đặt Repository

Tạo các implementation cụ thể của interface IRepository cho từng kiểu thực thể hoặc kiểu dữ liệu. Ví dụ sau sử dụng Entity Framework để tương tác với cơ sở dữ liệu SQL:

Đoạn mã 4

public class SqlRepository<T> : IRepository<T> where T : class
{
    private readonly DbContext context;

    public SqlRepository(DbContext dbContext)
    {
        this.context = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
    }

    public void Add(T entity)
    {
        context.Set<T>().Add(entity);
        context.SaveChanges();
    }

    public void Update(T entity)
    {
        context.Set<T>().Update(entity);
        context.SaveChanges();
    }

    public void Delete(T entity)
    {
        context.Set<T>().Remove(entity);
        context.SaveChanges();
    }

    public T GetById(int id)
    {
        return context.Set<T>().Find(id);
    }

    public IEnumerable<T> GetAll()
    {
        return context.Set<T>().ToList();
    }
}

Ghi chú: Lớp SqlRepository ở trên cài đặt interface IRepository, thực hiện các thao tác CRUD sử dụng DbContext.


3. Tiêm Repository vào Service

Sử dụng Dependency Injection để truyền repository vào trong các service hoặc controller, giúp module cấp cao không phụ thuộc vào lớp hiện thực cụ thể.

Đoạn mã 5

public class UserService
{
    private readonly IRepository<User> userRepository;

    public UserService(IRepository<User> userRepository)
    {
        this.userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
    }

    public void AddUser(User user)
    {
        userRepository.Add(user);
    }

    public IEnumerable<User> GetAllUsers()
    {
        return userRepository.GetAll();
    }
}

9.6 Ưu điểm của Kiến trúc Onion

MVC giúp giải quyết vấn đề tách biệt mối quan tâm (separation of concerns), nhưng vẫn không khắc phục được ràng buộc chặt (tight coupling).

Onion Architecture ra đời để:

  • Đảm bảo tách biệt các lớp như giao diện, truy cập dữ liệu, logic nghiệp vụ
  • Tập trung vào miền nghiệp vụ (Domain)
  • Hạn chế phụ thuộc giữa các lớp

Các ưu điểm chính:

  • ✅ Dễ bảo trì (Easy Maintenance): Dễ bảo trì vì mã nguồn được phân tách rõ theo các lớp hoặc tập trung ở trung tâm (domain).
  • ✅ Cải thiện kiểm thử (Improved Testing): Có thể viết test đơn vị cho từng lớp mà không ảnh hưởng đến phần còn lại.
  • ✅ Ràng buộc lỏng (Loose Coupling): Các lớp bên ngoài luôn tương tác với lớp bên trong qua interface.
  • ✅ Triển khai dễ dàng (Easy Implementation): Khi dùng dịch vụ ngoài, có thể tạo interface để xử lý tại lớp cao hơn.

Nguyên tắc thực hiện kiến trúc Onion:

  • Ứng dụng theo mô hình hướng đối tượng độc lập
  • Mã có thể biên dịch riêng biệt so với tầng hạ tầng
  • Ràng buộc chỉ hướng về lõi trung tâm (domain)
  • Interface được định nghĩa ở lớp bên trong
  • Lớp ngoài dùng để triển khai các interface đó

Kết luận

Onion Architecture dễ bảo trì vì mã được phân tách rõ ràng hoặc đặt tập trung ở domain. Kiến trúc này giúp:

  • Kiểm thử từng phần dễ dàng
  • Giảm ràng buộc giữa các lớp
  • Đảm bảo sự tách biệt rõ ràng giữa các tầng
  • Giao tiếp giữa lớp ngoài và trong thông qua interface → giúp xây dựng ứng dụng có ràng buộc lỏng (loosely coupled)

Nếu bạn muốn mình tổng hợp lại toàn bộ tài liệu này thành bản PDF tiếng Việt hoặc dạng slide, mình có thể hỗ trợ thêm. Bạn cũng có thể yêu cầu ví dụ thực tế hoặc sơ đồ giải thích để học sâu hơn về Onion Architecture.

Bài tập

1. Xây dựng ứng dụng Web áp dụng nguyên lý Onion Architecture

  • Triển khai một ứng dụng web sử dụng các nguyên tắc của Onion Architecture, đặc biệt tập trung vào vai trò của tầng hạ tầng (Infrastructure Layer) như:

    • Truy cập dữ liệu

    • Cài đặt repository


2. Triển khai mẫu Repository đơn giản trong C# sử dụng .NET Core

  • Tạo một interface IRepository<T> với các phương thức:

    • Create

    • Read

    • Update

    • Delete (CRUD)

  • Sau đó, tạo một lớp hiện thực cụ thể của interface này cho một thực thể cụ thể (ví dụ: User).

  • Viết một đoạn mã ví dụ để minh họa cách thực hiện các thao tác CRUD trên thực thể User bằng repository đã tạo.


3. Triển khai Dependency Injection trong ứng dụng ASP.NET Core

  • Định nghĩa một interface dịch vụ và hiện thực tương ứng của nó.

  • Cấu hình Dependency Injection trong lớp Startup.cs của ứng dụng ASP.NET Core.

  • Trình bày cách sử dụng dịch vụ đã tiêm (injected service) trong:

    • Controller

    • hoặc Middleware

Bài viết liên quan:

Kiến trúc .NET Core và Triển khai Kestrel Web Server
Một số cải tiến trong ASP.NET Core, Razor Page, Model Binding, Gabbage collection
Các Phương thức hành động (Action Methods) và khái niệm nâng cao trong C# MVC
Giới thiệu chi tiết kiến trúc ASP.NET MVC và Core MVC
Phát triển Client Side sử dụng ASP.NET Core MVC
Khởi tạo dự án Hello World với ADO.NET và Entity Framework
Làm việc với Web Forms, Controls và Events trong ASP.NET
Giới thiệu về ASP.NET và ASP.NET Core

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

Kiến trúc Onion trong ASP.NET Core

Các tính năng nâng cao của C#

Các lớp trừu tượng và Giao diện

Các khái niệm nâng cao trong C#

Kiểu dữ liệu Generics và Iterators trong C# 

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×