Những khái niệm này hoàn toàn phù hợp với một ứng dụng web Tương tác với ứng dụng MVC dựa theo một vòng tuần hoàn của hoạt động người dùng và cập nhật view khi mà các view sẽ không có t
Trang 1CHƯƠNG 3: MÔ HÌNH MVC
Lịch sử của MVC
Khái niệm Model, View, Controller đã được sử dụng từ những năm 70 của thế
kỷ 20 và phát triển từ đồ án Smalltalk của XeroxPARC Tại đây nó đã được nhìn nhận như một cách tổ chức các ứng dụng GUI đầu tiên
Một số nội dung chi tiết ban đầu của mô hình MVC gắn liền với khái niệm trong Smalltalk như màn hình và các công cụ, nhưng khái niệm broader vẫn được áp dụng vào ứng dụng Những khái niệm này hoàn toàn phù hợp với một ứng dụng web
Tương tác với ứng dụng MVC dựa theo một vòng tuần hoàn của hoạt động người dùng và cập nhật view khi mà các view sẽ không có trạng thái nhất định (stateless) Mô hình này phù hợp với các HTTP request và response được dùng trong ứng dụng web Xa hơn nữa, MVC yêu cầu tách rời các yếu tố bao gồm
domain model và controller logic tách riêng khỏi giao diện người dùng (UI) trong ứng dụng web Nghĩa là HTML sẽ được tách rời khỏi phần còn lại của ứng dụng dẫn đến việc bảo trì và sửa lỗi sẽ trở nên dễ dàng và đơn giản hơn Ruby on Rails dẫn đầu trong việc xây dựng mới lại mô hình MVC và hiện các ứng dụng vẫn xây dựng dựa trên mô hình này Một số MVC framework khác đã được giới thiệu và trình diễn những ưu điểm của mô hình MVC, trong số đó có ASP.NET
Trang 2Tìm hiểu mô hình MVC
Ở khái niệm mức cao, mô hình MVC có nghĩa là ứng dụng MVC sẽ được chia làm ít nhất 3 phần tách biệt, Models bao gồm những thể hiện của dữ liệu mà người dùng sẽ làm việc trên đó, đó có thể là 1 view model đơn giản dùng để thể hiện
những luồng dữ liệu giữa View và controller hoặc đó có thể là domain models chứa những dữ liệu business cũng như các hàm tính, chuyển đổi và những quy ước khi thao tác với dữ liệu đó
Views dùng để biểu diễn 1 phần dữ liệu của model trên giao diện người dùng Controllers xử lý những yêu cầu đến, thực hiện những tác vụ từ phía model và lựa chọn view để biểu diễn dữ liệu đến người dùng Model được định nghĩa là không gian không gian mà ứng dụng của bạn hoạt động dựa theo đó
Ví dụ, trong một ứng dụng ngân hàng (Banking), model đại diện cho tất cả những gì mà ứng dụng banking hỗ trợ như account, sổ cái, giới hạn tiền gửi của khách hàng … cũng như các hoạt động có thể dùng để thao tác trên dữ liệu như chuyển khoản hoặc rút tiền từ tài khoản Model cũng chịu tách nhiệm đảm bảo tính toàn vẹn và nhất quán của dữ liệu
Ví dụ: đảm bảo 66 giao dịch đều được ghi vào trong sổ cái cũng như người
dùng không thể rút hơn số tiền mà người đó có trong ngân hàng
Các models cũng được định nghĩa dựa trên những gì nó đại diện Model không đảm nhận công việc biểu diễn dữ liệu trên giao diện người dùng, đó là công việc của Views và Controllers
View chứa các yêu cầu logic để biểu diễn các thuộc tính của View cho người dùng, đó là công việc duy nhất mà View đảm nhận, nó không quan tâm trực tiếp đến model cũng như không trực tiếp giao tiếp với tầng Model
Controller là cầu nối giữa Views và Models Yêu cầu được gửi từ phía client và được giải quyết bởi controler bao gồm lựa chọn view thích hợp để biểu diễn nội dung đến người dùng, nếu cần, sẽ thực hiện các tác vụ ở tầng model
Mỗi thành phần của MVC đều được định nghĩa chi tiết và độc lập dựa vào những yêu cầu khác nhau Những tác vụ logic điều khiển dữ liệu chỉ nằm duy nhất trong Model Những tác vụ logic dùng để hiển thị dữ liệu chỉ nằm ở tầng View và phần code xử lý yêu cầu người dùng bao gồm cả các thông tin đầu vào chỉ có trong
Trang 3controller Với sự phân chia rõ ràng từng phần như vậy, công tác bảo trì và mở rộng ứng dụng sẽ trở nên dễ dàng xuyên suốt vòng đời của nó, bất chấp độ lớn ứng dụng mà ứng dụng đó được nới rộng
Tìm hiểu Domain Model
Phần quan trọng nhất trong một ứng dụng MVC là Domain model Chúng ta tạo một model bằng cách xác định những thực thể, tác vụ và các quy tắc tồn tại trong kinh doanh hoặc trong các hoạt động mà ứng dụng đó hỗ trợ Sau đó chúng ta tạo nên phần mềm để diễn tả các domain đó, gọi là domain model Nhằm đáp ứng mục tiêu của ASP.NET MVC framework, domain model là 1 bộ các C# types
(classes, struct ) được biết đến như là các domain types Những hoạt động của domain được biểu diễn bởi các methods được xác định trong domain types Và những quy tắc của domain sẽ được biểu diễn bởi những hàm logic bên trong các method đó
(Có thể tìm xem lại ở chương trước, bằng cách áp dụng các thuộc tính C#, khi một thể hiện (instance) của domain type được tạo ra để thể hiện một phần của dữ liệu, nó gọi là một domain object
Domain model thường được bảo toàn với vòng đời dài, có rất nhiều giải pháp cho những tính chât này của domain model nhưng cơ sở dữ liệu quan hệ vẫn là lựa chọn phổ biến nhất )
Một cách ngắn gọn, domain model là định nghĩa duy nhất, cao cấp nhất về business data và các quy trình bên trong ứng dụng Một domain model cố định cũng nắm giữ định nghĩa cho các trạng thái mà domain đó thể hiện
Chúng ta có thế tiếp cận và xử lý các vấn đề nảy sinh của Domain model trong quá trình bảo trì ứng dụng Nếu cần thiết phải điều chỉnh các dữ liệu của Model hoặc thêm váo các hoạt động hay quy tắc mới, domain model là phần duy nhất trong ứng dụng cần phải được chỉnh sửa
Mẹo: Một cách phổ biến để thực hiện tách rời domain model ra khỏi những
phần còn lại của ứng dụng ASP.NET MVC là đặt model đó trong một assembly C# tách biệt Bằng cách này, bạn có thể tạo ra các references cho domain model từ những phần khác của của ứng dụng nhưng đảm bảo không còn references nào ở miền khác Cách xây dựng này hiệu quả đối với những project lớn
Trang 4Cách ASP.NET triển khai mô hình MVC
Trong MVC, controller là một lớp C# , thường kế thừa từ lớp
System.Web.Mvc.Controller Mỗi public method trong lớp kế thừa từ Controller là một action method, nghĩa là liên quan đến cấu hình URL thông qua hệ thống định hướng của ASP.NET (routing system) Khi một yêu cầu đươc gửi đến URL tương ứng với action method nào đó, câu lệnh trong lớp Controller sẽ đươc thực thi để thực hiện các tác vụ trên domain model sau đó lựa chọn một view để biểu diễn nội dung dữ liệu về phía Client
ASP.NET MVC Framework sử dụng view engine, nghĩa là một cấu trúc đảm nhận việc phát sinh view nhằm tạo ra phản hồi trên Browser Những version trước đây của MVC sử dụng chuẩn ASP.NET view engine, nghĩa là xây dựng các trang ASPX sử dụng streamlined version theo các cú pháp Web Form MVC 3 giới thiệu engine Razor, sử dụng cấu trúc cú pháp hoàn toàn khác (Sẽ được miêu tả cụ thể hơn ở chương 5) Razor đã được cải tiến ở MVC 4 và không thay đổi ở MVC 5
Mẹo: Visual studio cung cấp công cụ IntelliSense hỗ trợ cho Razor, giúp đơn giản hóa
trong việc truyền và nhận dữ liệu đến view bởi controller
ASP.NET không áp dụng bất kỳ một ràng buộc nào trong việc thực thi domain
model.Người dùng có thể tạo một đối tượng C# bình thường và sử dụng bất kỳ một
Database nào Bản đồ quan hệ đối tượng (ORM Framework) hoặc bất kỳ công cụ data nào
hỗ trợ bởi NET
So sánh MVC với những mô hình khac
MVC không phải là kiến trúc xây dựng phần mềm duy nhất Có rất nhiều kiến trúc khác và một vài trong số đó cực kỳ phổ biến Chúng ta đã học nhiều về MVC khi tìm hiểu qua những định nghĩa.Ở phần tiếp theo , chúng ta sẽ bàn đến những hướng tiếp cận khác nhau khi xây dựng một ứng dụng và những mặt đối nghịch của chúng so với MVC Một số
mô hình có biến thể rất gần với MVC, một số khác thì hoàn toàn khác biệt
MVC không hoàn toàn là mô hình hoàn hảo cho tất cả các giải pháp phần mềm Trong một số trường hợp, những mô hình xây dựng phần mềm khác sẽ hiệu quả hơn MVC
Chúng ta cần tìm hiểu và cân nhắc kỹ lưỡng trước khi lựa chọn một mô hình Nội dung sách
Trang 5sẽ chỉ xoay quanh mô hình MVC nhưng người phát triển phần mềm cần có tư duy mở và cân nhắc để đưa ra quyết định sáng suốt nhất
Hiểu về mô hình Smart UI
Một trong những mô hình thiết kế phổ biến được biết đến với tên gọi smart user
interface (Smart UI) Hầu hết người lập trình đều đã từng tạo ít nhất 1 ứng dụng smart UI Nếu như bạn đã từng sử dụng Web Forms hoặc ASP.NET Web Form thì bạn cũng đã từng
sử dụng mô hình này
Để xây dựng một ứng dụng Smart UI , người lập trình cấu trúc một giao diện người dùng, thường là công việc kéo thả các thành phần hoặc controls lên giao diện rỗng ban đầu controls hồi đáp những tương tác với người dùng bằng xử lý những sự kiện (events) (bấm nút, kéo thả chuột, tổ hợp phím…).Người lập trình thêm các đoạn code để phản hồi lại những sự kiện trong một bộ xử lý sự kiện (event handlers): đoạn code sẽ được gọi khi một
sự kiện xác định xảy ra trên components
Mô hình này tạo ra một ứng dụng nguyên khối như trong hình Những đoạn code xử lý trên giao diện người dùng và các tác vụ business nằm tất cả trong một mà không phân thành những phần nhỏ Phần code xác định những giá trị chấp nhận cho việc nhập liệu, truy vấn dữ liệu hoặc sửa đổi thông tin tài khoản người dùng chỉ nằm trong 1 phần nhỏ, liên kết với nhau theo trật tự sắp xếp theo những yêu cầu của sự kiện
SmartUI là ý tưởng nhằm tạo ra 1 project đơn giản vì nó có thể đạt hiệu quả trong thời gian ngắn (so sánh với mô hình MVC (chương 7): MVC vốn đòi hỏi sự chuẩn bị kỹ lưỡng và
sự đầu tư từ ban đầu để đạt được hiệu quả) Smart UI cũng phù hợp với giao thức giao diện người dùng Công cụ thiết kế giao diện tốt dù WebForm có thể hoạt động một cách kỳ quặc
và khó đoán Nếu bạn đang tiếp xúc với khách hàng và muốn thể hiện nhanh ý tưởng về những yêu cầu về giao diện cũng như luồng hoạt động của giao diện, Smart UI là một công
cụ nhanh và đáp ứng việc tạo dựng và thử nghiệm những ý tưởng khác nhau
Trang 6Một khuyết điểm của Smart UI là những khó khăn trong công tác bảo trì và mở rộng
Sự trộn lẫn giữa Model và Business logic trong giao diện người dùng dẫn đến sự trùng lặp (duplication), khi mà cùng 1 mảng business được sao chép lại nhiều lần để hỗ trợ những thành phần được thêm vào sau đó Tìm ra tất cả những vị trí trùng lặp và sửa chữa gặp nhiều khó khăn Việc thêm tính năng mới mà không ảnh hưởng đến những tính năng đã có gần như là không thể Kiểm thử ứng dụng theo mô hình Smart UI cũng gặp nhiều khó khăn Cách duy nhất là giả lập những giao tiếp của người dùng, đi ngược lại những ý tưởng về kiểm thử và khó khăn để thực hiện công tác kiểm thử một cách trọn vẹn
Trong thế giới MVC, Smart UI thường được xem như là một phản mô hình, cần phải tránh bằng mọi giá Những người tìm đến mô hình MVC vốn đã dành nhiều thời gian của
họ để bảo trì và phát triển ứng dụng Smart UI trước đó
Mặc dù tồn tại nhiều luồng quan điểm, tuy nhiên chúng ta không nên đơn giản hóa vấn
đề cũng như không nên loại bỏ phương án SmartUI hoàn toàn Không phải tất cả mọi thứ đều xấu trong mô hình Smart UI, nó vẫn tồn tại rất nhiều mặt tích cực khi tiếp cận Ứng dụng Smart UI nhanh và dễ dàng phát triển Những người tạo ra công cụ thiết kế
component và giao diện đang nỗ lực để đem đến trải nghiệm tốt hơn Ngay cả những người lập tình thiếu kinh nghiệm nhất vẫn có thể tạo ra một ứng dụng với giao diện chuyên nghiệp
và đấy đủ tính năng trong thời gian ngắn
Điểm yếu lớn nhất của các ứng dụng Smart UI đó là khả năng bảo trì, không nên tốn công sức cho công tác bảo trì Nếu bạn xây dựng một ứng dụng nhỏ và đơn giản, Smart UI
là giải pháp hoàn hảo khi mà những yếu tố phức tạp hơn trong mô hình MVC là không cần thiết
Tìm hiểu kiến trúc Model-View
Business Logic là nguyên nhân dẫn đến những khó khăn về bảo trì trong SmartUI, gây
ra dài dòng trong ứng dụng gây cản trở khi chỉnh sửa hoặc thêm tính năng mới Mô hình Model-View đưa ra những khắc phục đối với vấn đề này bằng cách đẩy phần business logic
ra thành một phần domain model tách biệt Bằng cách này, dữ liệu, process, và các quy tắc (Rules) được kết nối với nhau trong ứng dụng như trong hình 3-3
Trang 7Mô hình model view có thể cải thiện mô hình nguyên khối của Smart UI lấy ví dụ như vấn đề bảo trì Tuy nhiên có 2 vấn đề nảy sinh:
Vấn đề đầu tiên là từ khi UI và domain model đã được tích hợp chặt chẽ với nhau, nó
có thể gây khó khăn để thực hiện công tác unit testing
Vấn đề thứ hai nảy sinh trong thực tế nhiều hơn là trong định nghĩa của mô hình Model thường chứa 1 lượng lớn code truy suất dữ liệu (không nhất thiết nhưng trong thực
tế vẫn thường gặp) điều này nghĩa là data model không những chỉ chứa business data, operation và các quy tắc
Tìm hiểu kiến trúc 3 lớp cổ điển (3 tier architecture)
Để xác định vấn đề của kiến trúc model-view, mô hình ba lớp chia những đoạn code
cố định của domain model và đặt nó vào trong một thành phần mới gọi là lớp data access (data access layer) Hình 3-4
Kiến trúc ba lớp được sử dụng phổ biến nhất trong các kiến trúc ứng dụng business
Nó cũng không hề có ràng buộc hoạt động của UI và phân chia các yếu tố thành từng phần
mà không biến nó trở nên quá phức tạp Và nếu quan tâm hơn, lớp DAL có thể được tạo ra
để các công tác unit testing được thực hiện một cách tương đối dễ dàng Bạn có thể nhận
ra sự giống nhau rõ ràng giữa phần mềm theo kiến trúc ba lớp cổ điển về kiến trúc.Sự khác biệt nằm ở việc khi lớp UI được tách thành click-and-event GUI framework (như trong
Windows Forms hoặc ASP.NET Web Forms) Nó trở nên bất khả thi để thực hiện công việc unit test một cách tự động Và khi UI là một phần của kiến trúc 3 lớp , nó có thể trở nên phức tạp, rất nhiều phần code không thể kiểm thử một cách tỉ mỉ
Trang 8Trong trường hợp xấu nhất, mô hình 3 lớp sẽ thiếu đi tính chặt chẽ trong phân lớp UI, nghĩa là nhìu ứng dụng theo đó sẽ trở nên giống như các ứng dụng theo mô hình Smart UI(không có sự tách biệt giữa các thành phần) Điều này gây ra hậu quả tệ nhất , phần mềm không thể kiểm thử, bảo trì và trở nên vô cùng phức tạp
Tìm hiểu những biến thể của MVC
Chúng ta đã tìm hiểu những mô tả cơ bản về những yếu tố chính của ứng dụng MVC, đặc biệt khi nó vận hành trên ASP.NET MVC Một số định nghĩa về mô hình khác đã thêm bớt, vay mượn những yếu tố của mô hình MVC để trở nên phù hợp hơn với phạm vi và nhu cầu của các dự an Trong phần tiếp theo , chúng ta sẽ có cái nhìn sơ lược của 2 mô hình dựa trên nền tảng MVC Nắm được nội dung của những biến thể của MVC là không cần thiết khi làm việc trên ASP.NET MVC.Tuy nhiên nội dung vấn được thêm vào để hoàn thiện kiến thức về các mô hình phát triển phần mềm
Tìm hiểu mô hình Model View Presenter
Model View Presenter là một biến thể của MVC được thiết kế để phù hợp hơn với nền tảng GUI ổn định như Windows Form hoặc ASP.NET Web Forms Đây là nỗ lực nhằm đạt đến mô hình Smart UI nhưng giảm thiểu những khuyết điểm nó đem lại
Trong mô hình MVP, lớp presenter đóng vai trò tương tự như Controller trong MVC nhưng nó đồng thời cũng đảm nhận mối quan hệ trực tiếp đến các stateful view Trực tiếp điều khiển giá trị xuất ra trên các phần giao diện dựa trên nhập liệu của người dùng Có 2 yếu tố được triển khai trong mô hình này
Passive view, trong đó view không chứa các tác vụ logic _ nó là một nơi chứa các UI controls được điều khiển bởi presenter
Supervising controller (controller giám sát), view có thể chịu trách nhiệm cho một số thành phần logic trình bày như ràng buộc dữ liệu (data binding), và được cho phép tham chiếu từ nguồn dữ liệu (data source) bên trong domain models
Sự khác biệt giữa 2 hướng tiếp cận liên quan đến sự thông minh của lớp view Ngoài
ra presenter được tách ra từ GUI Framework, điều này khiến thành phần presenter logic đơn giản và phù hợp hơn cho công việc unit testing
Trang 9Tìm hiểu mô hình Model -View- View model
Mô hình Model view view model ( MVVM) là một trong những biến thể gần đây nhất của MVC Nó được xây dựng bởi Microsoft và được sử dụng trong WPF (Windows
Presentation Foundation) Trong mô hình MVVM, Model và view có cùng một vai trò như trong MVC Sự khác biệt trong khái niệm của MVVM nằm trong lớp view model Đây là một lớp trừu tượng thể hiện của giao diện người dùng Thường là lớp C# cho thấy cả các thành phần của dữ liệu được biểu diễn trên UI và các tác vụ trên dữ liệu có thể được gọi bởi UI Không như MVC controller, MVVM view model không hề tồn tại các khái niệm về view (hoặc bất cứ định nghĩa về UI nào khác) MVVM view sử dụng chực năng WPF binding để liên kết
2 chiều với những thuộc tính điều khiển trong view (item trong các dropdown menu hoặc tác dụng khi bấm nút) với thuộc tính được thể hiện bởi viewmodel
Mẹo: MVC cũng dùng khái niệm view model nhưng liên quan đến các class model
đơn giản và chỉ được dùng với mục đích duy nhất là truyền dữ liệu từ controller vào view, đối nghịch với domain model vốn đại diện cho dữ liệu, hoạt động và quy tắc
Loose Coupling (Độ phụ thuộc thấp)
Một trong những tính năng quan trọng của mô hình MVC là nó cho phép chia nhỏ các vấn đề cần quan tâm Chúng ta muốn mỗi bộ phận trong ứng dụng của phải độc lập nhất có thể và có ít tính phụ thuộc lẫn nhau nhất trong khả năng sắp xếp của chúng ta Ý tưởng cho giải pháp trên, mỗi thành phần không hề biết gì về các thành phần khác và chỉ hoạt động với các phần khác thông qua lớp các lớp interface trừu tượng Đây được xem như độ phụ thuộc thấp (Loose Coupling)
Nó khiến cho công đoạn kiểm thử và chỉnh sưa trở nên dễ dàng hơn Một ví dụ đơn giản sẽ giúp chúng ta dễ hình dung, giả sử khi chúng ta viết một component tên
MyEmailSender làm nhiệu vụ gửi email, chúng ta sẽ thực hiện mợi lớp interface để định nghĩa tất cả các chức năng chung cần thiết để gửi một email (tạm gọi là IEmailSender) Tất
cả những component khác của ứng dụng khi cần gửi email- giả sử chức năng trợ giúp reset lại password sẽ gọi hàm PasswordResetHelper có thể gửi 1 email bằng cách liên hệ với hàm chức năng (method) trong lớp interface Không hè có sự phụ thuộc trực tiếp nào giữa
PasswordResetHelper và MyEmailSender Hinh 3-5
Trang 10Bằng giới thiệu về IEmailSender, chúng ta có thể thấy không hề có sự phụ thuộc nào
giữa PasswordResetHelper và MyEmailSender. Chúng ta có thể thay thế MyEmailSender bằng
một nhà cung cấp e-mail khác hoặc xây dựng một hàm chức năng giả nhằm mục đích kiểm
thử mà không cần phải chỉnh sửa lại PasswordResetHelper (Chương 6)
Sử dụng Dependency Injection
Interface cho phép chia nhỏ các components nhưng vẫn phải đối mặt với một vấn đề:
C# không hỗ trợ công cụ built-in có thể dễ dàng tạo một đối tượng thực thi interfaces, ngoại
trừ tạo một instance cụ thể của component bằng từ khóa mới Gỉa sử đoạn code
Điều này làm cản trở mục tiêu nhằm thay thế MyEmailSender mà không cần phải thay
đổi PasswordResetHelper và có nghĩa là chúng ta chỉ mới hoàn thành một phần của thao tác
kết nối các component riêng biệt PasswordResetHelper class được cấu hình và gửi mail
thông qua lớp interface IEmailSender, nhưng để tạo một đối tượng thực thi lớp interface đó,
chúng ta phải tạo ra một instance của MyEmailSender. Thực tệ, chúng ta đã khiến vấn đề trở
nên xấu đi khi bởi vì hiện giờ PasswordResetHelper giờ đã bị phụ thuộc vào MyEmailSender
với lớp Interface IEmailSender Hình 3-6
Những gì chúng ta cần là một cách để lấy đối tượng thực thi lớp interface mà không
cần phải tạo đối tượng một cách trực tiếp Giải pháp cho vấn đề này gọi là Denpendency
Injection Hoặc có thể biết đến với tên gọi Inversion of control (IoC) DI là mô hình thiết kế có
thể hoàn thiện kết nối các thành phần rời rạc Như đã miêu tả về DI, chúng ta có thể tự hỏi
tại sao lại cần đến nó nhưng thực sự đây là một khái niệm trung tâm quan trọng ảnh hưởng
đến quá trình phát triển ứng dụng MVC và nó có thể gây ra rất nhiều nhầm lẫn (confusion)