Trong chương này chúng ta sẽ mô tả lại một số tính năng hữu ích của MVC mà một người lập trình ứng dụng MVC cần biết thông qua những ví dụ được đưa ra trong sách Nội dung sẽ chỉ gồm nhữn
Trang 1Chương 4 Một số tính năng quan trọng
trong C#
C# là ngôn ngữ nhiều tính năng và nhiều người lập trình vẫn chưa thông thạo hết
những tính năng mà trong sách này đề cập đến Trong chương này chúng ta sẽ mô tả lại
một số tính năng hữu ích của MVC mà một người lập trình ứng dụng MVC cần biết thông
qua những ví dụ được đưa ra trong sách
Nội dung sẽ chỉ gồm những tổng quan ngắn gọn và cơ bản về mỗi tính năng, nếu
nhưng người đọc muốn đi sâu hơn vào ngôn ngữ C# hoặc LINQ có thể tìm xem qua : For a
complete guide to C#, Introducing Visual C#, và để nghiên cứu sâu hơn về LINQ, tìm đọc
Pro LINQ in C# Những ví dụ chi tiết về NET hỗ trợ lập trình không đồng bộ (asynchronous
programming) , tìm đọc Pro net parallel Programming in C# Tất cả sách đều được phát
hành bởi Apress
Chuẩn bị Project cho ví dụ
Để tiến hành mô tả những tính năng của ngôn ngữ lập trình trong chương này, chúng
ta tạo một project tên LanguageFeatures sử dụng template ASP.NET MVC Web application
Chọn Emty project cho phần nội dung lúc đầu và chọn mục MVC để dựng sẵn các folders và những phần liên quan (Xem chương 2) Những tính năng ngôn ngữ chúng ta vừa miêu tả
không dành riêng cho MVC, nhưng VS 2013 Express cho Web không hỗ trợ tạo project có
thể viết trên console vì thế bạn nên tạo một ứng dụng MVC nếu muốn theo kịp những ví dụ Chúng ta cần một controller cơ bản để diễn tả tính năng trong ngôn ngữ lập trình, do đó
chúng tạ tạo một lớp HomeController.cs trong folder Controllers Các làm: nhấp chuột phải tại folder Controllers trong cửa sổ Solution explorer, chọn Add >Controller Trong phần pop-up
menu, chọn MVC 5 Controller-Emty trong phần Add Scafold menu , sau đó nhấn nút Add
Đặt tên lớp là HomeController trong hộp thoại Add Controller và nhấn nút Add để tạo lớp
Controller List 4-1
Trang 2Chúng ta sẽ tạo một action method đơn giản cho mỗi ví dụ, kết quả nhận được của
Index action method là một thông điệp đơn giản
Chú ý: Lớp HomeController sẽ không biên dịch ở thời điểm hiện tại vì nó khai báo
namespace LanguageFeatures.Models Namespace này sẽ không được tạo cho đến khi
chúng ta thêm một lớp vào folder Models.Chúng ta sẽ làm việc này trong ví dụ đầu tiên của
phần tiếp theo
Để hiển thị kết quả của action method Chúng ta chuột phải vào tên Index của action
method> chọn Add View và tạo một view đặt tên là result (list 4-2)(Không quan trọng chúng
ta chọn option nào trong hộp thoại Add View vì chúng ta sẽ thay thế nội dung ban đầu của
file với đoạn code trong list 4-2)
Chúng ta có thể thấy đây là một strongly typed view , khi model type là kiểu String ở
hầu hết các phần Ví dụ sau đây không phải là một ví dụ phức tạp và chúng ta có thể biểu
diễn kết quả bằng một đoạn string đơn giản
Trang 3Thêm System.Net.Http Assembly
Trong phần sau của chương này, chúng ta sẽ sử dụng ví dụ dựa vào System.Net.Http
assembly Tính năng này mặc định không được thêm vào MVC Chọn Add Reference trong Visual Studio Project menu để mở cửa sổ Reference Manager Đảm bảo rằng chúng ta đang chọn section Assemblies trong danh sách bên trái sau đó nhấn chọn System.Net.Http
(Hình 4-1)
Trang 4Sử dụng tính năng Automatically Implemented Properties
Tính năng property cơ bản trong C# cho phép người dùng triển khai 1 phần của dữ liệu bằng cách tách cách dữ liệu được đặt và lấy về (Listing 4-3) có chứa một ví dụ cơ bản của lớp tên Product Chung ta thêm lớp này vào folder Models trong project của mình với tên gọi Product.cs
Thuộc tính Name được in đậm Câu lệnh get (hoặc còn gọi là getter) thực hiện khi dữ liệu được đọc và câu lệnh set (hoặc còn gọi là settle) được thực hiện khi một giá trị được điền vào cho thuộc tính (biến được biện value thể hiện cho giá trị được điền vào) Một thuộc tính được sử dụng bởi các lớp khác và xem nó như một field Hình 4-4 cho thấy
AutoProperty action method chúng ta sẽ thêm vào trong lớp Homecontroller
Trang 5Chúng ta có thể thấy giá trị của thuộc tính được đọc và đặt giá trị như những field bình thường Sử dụng properties được ưa chuộng hơn so với fields bởi vì nó có thể thay đổi câu lệnh trong phần code get và set mà không cần thay đổi lớp phụ thuộc của thuộc tính
Mẹo Chúng ta để ý ràng chúng ta đã đặt đối số thứ hai vào View như một đối tượng
(listing 4-4) Điều này là bởi vì View method phần tham số cho phép chứa 2 đối số dạng
string và khác so với phần tham số chỉ cho phép một chuỗi và một đối tượng Để tránh gọi
nhầm, chúng ta sẽ khai báo tường minh tham số thứ hai Chúng ta sẽ đề cập đến phần
tham số cho view Method ở chương 20
Chúng ta có thể kiểm tra hiệu quả bằng cách khởi động project hướng đến địa chỉ
/Home/AutoProperty (nhắm đến AutoProperty action method và sẽ là phần nền để kiểm thử
mỗi ví dụng trong chương này) Bởi vì chúng ta chưa truyền một chuỗi string vào từ action
method đến view Đây là kết quả dưới dạng text, thay vì hình chụp Đây là kết quả của
action method trong listing 4-4
Tất cả thuộc tính đều tốt đẹp, tuy nhiên chúng trở nên khó khăn khi chúng ta có một
class chứa quá nhiều thuộc tính, tất cả chúng đều được đưa vào một field, tạo nên file class rườm rà một cách không cần thiết Ví dụ 4-5 cho thấy thêm một số thuộc tính vào lớp
Product trong file Product.cs
Trang 6Chúng ta muốn có được sự mềm dẻo trong mỗi thuộc tính mà không cần cấp số nhân lượng getter và setter Giải pháp là tự động thực hiện thao tác property, còn được gọi là automatic property Với tính năng này chúng ta có thể tạo các đoạn code cho sẵn của thuộc tính mà không cần đặt lại các đoạn code getter và setter Hình 4-6
Trang 7Chú ý rằng chúng ta không định nghĩa phần thân của getter và setter đặt cho thuộc tính đó Cả hai thuộc tính đều được thược hiện cho người dùng thông qua hệ thống biên dịch của C# Sử dụng tính năng thuộc tính tự động này không khác biệt so với việc viết gettter và setter cho thuộc tính thông thương Đoạn code trong list 4-4 sẽ hoạt động mà không cần điều chỉnh
Bằng cách sử dụng thuộc tính tự động, chúng ta rút ngắn được thời gian nhập code, tạo ra các đoạn code dễ đọc nhưng đồng thời vẫn hỗ trợ tính mềm dẻo mà thuộc tính cung cấp Nếu một lúc nào đó chúng ta thay đổi cách vận hành thuộc tính, chúng ta vẫn có thể quay lại cách thiết lập thuộc tính truyền thống Như trong list 4-7, chúng ta cần phải chỉnh sửa khi cần thay đổi cách thức thuộc tính Name được thiết lập
Chú ý: chúng ta phải chỉnh cả getter lẫn setter để trả về thuộc tính thông thường C# không hỗ trợ việc trộn lẫn chế độ tự động và nhập liệu thông thường của getter và setter trên cùng một thuộc tính
Trang 8Sử dụng Object và Collection Initializers
Một công việc buồn chán trong quá trình lập trình là cấu trúc một đối tượng mới và
đưa vào các giá trị cho thuộc tính List 4-8 miêu tả hành động thêm vào của CreatProduct
action method trong Home controller
Chúng ta đi qua ba bước để tạo một đối tượng Product và tạo ra một kết quả: tạo đối
tượng, đặt các giá trị tham số và sau đó gọi đến View method để trả về kết quả thông qua
view May mắn thay, chúng ta có thể sử dụng tính năng object initializer, cho phép chúng ta
tạo và biểu diễn một instance của đối tượng Product trong một bước đơn giản List 4-9
Trang 9Trong dấu ({ }) sau lời gọi Product là một mẫu của Initializer cho phép chúng ta cung
cấp giá trị vào các thông số như một phần của quá trình cấu trúc đối tượng Tính năng
tương tự cho phép chúng ta khởi tạo nội dung của một bộ và một danh sách như một phần
của quá trình cấu trúc List 4-10
Đoạn code trên miệu tả cách cấu trúc và khởi tạo một dãy và 2 lớp từ thư viện
collection Tính năng này là một cú pháp hiệu quả Giúp cho C# trở nên thân thiện hơn mà
không gây ra thêm tác động hay đem lại những lợi ích nào khác
Trang 10Sử dụng Extension Methods
Extension Method thêm các method vào các class mà chúng ta không sở hữu hoặc
không thể điều chỉnh trực tiếp một cách thuận lợi.List 4-11 biểu diễn 1 lớp ShoppingCart,
chúng ta sẽ thêm vào folder Models trong file tên là ShoppingCart.cs và sẽ thể hiện một bộ
các đối tượng Product
Đây là một lớp cơ bản hoạt động như một gói danh sách của các đối tượng Product
(Đây là một lớp đơn giản phục vụ cho ví vụ) Gỉa sử chúng ta cần xác định tổng giá trị của
các đối tượng Product trong lớp ShoppingCart nhưng không để chỉnh sửa lớp đó trực tiếp, có thể nó đóng vai trò như bên thứ 3 khi chúng ta không nắm giữ phần source code Chúng ta
có thể thêm một extension method để thêm tính năng mà chúng ta cần List 4-12 biểu diễn
lớp MyExtensionMethods chúng ta thêm vào trong folder Models trong file
MyExtensionMethods.cs
Keyword “this” đứng trước tham số của TotalPrices đánh dấu nó là một extension
method Tham số đầu tiên cho NET biết extension method này có thể được áp dụng vào
lớp ShoppingCart trong trường hợp này Chúng ta có thể tham khảo instance của
ShoppingCart mà extension method này áp dụng để sử dụng tham số cartParam Method của chúng ta liệt kệ các đối tượng Products trong ShoppingCart sau đó trả về tống giá của các
Product (dựa vào thuộc tính Product.Price) List 4-13 cho thấy cách chúng ta thêm một
extension method trong một action method tên UseExtension mà chúng ta thêm trong trong
Homecontroller
Trang 11Lưu ý : Extension Method không cho phép chúng ta bỏ qua quy tắc truy suất là các class
định nghĩa method và thuộc tính của chính nó Chúng ta có thể mở rộng chức năng của một class bằng cách sử dụng extension method nhưng chỉ sử dụng thành phần của lớp chúng ta truy suất vào đó
Chúng ta gọi TotalPrice method trong đối tượng ShoppingCart như nó là một phần của lớp ShoppingCart mặc dù nó chỉ là phần mở rộng được định nghĩa bởi 1 lớp khac .NET sẽ tìm phần mở rộng của các class nếu chúng có tham chiếu từ lớp hiện tại, nghĩa là chúng là một phần của cùng 1 namespace hoặc trong namespace có sử dụng câu lệnh using Đây là một ví dụ trong UseExtension action methos, chúng ta có thể thấy ứng dụng chuyển đến địa chỉ URL /Home/UseExtension
Trang 12Ứng dụng Extension Method vào Interface
Chúng ta cũng có thể tạo các extension method và áp dụng nó vào một interface Điều này cho phép chúng ta gọi extension method từ tất cả các class thực thi lớp interface đó
List 4-14 biểu diễn lớp ShoppingCart đã được thay đổi để thực thi lớp interface
IEnumerable<Product>
Bây giờ chúng ta có thể thêm extension method vào lớp interface
IEnumarable<Product> List 4-15
Kiểu của tham số đầu tiên đã thay bằng IEnumerable<Product> nghĩa là vòng lặp
foreach trong phần thân làm việc trực tiếp trên các đối tượng Product Việc chuyển qua
interface nghĩa là chúng ta có thể tính tổng giá trị của đối tượng Product được liệt kệ bởi bất
kỳ IEnumerable<Product>, bao gồm cả ShoppingCart là một thể hiện của nó, đồng thời cũng là
danh sách các đối tượng Product List 4-16
Trang 14Ghi nhớ: cách C# thực hiện lập danh sách theo interface IEnumerable<T> có một chút khác thường Chúng ta có thể xem nội dung của các interfaces trong tài liệu MSDN Công
cụ hỗ trợ này được xử lý bởi trình biên dịch vì thế nên phần code của phần C# trước đây vẫn hoạt động Chúng ta có thể sử dụng một kiểu lớp collection khác cho ví dụ này nhưng ví
dụ này thể hiện được những mảng tối của C#
Khi chúng ta chạy lại Project, và chỉ vào action method, chúng ta sẽ nhận được cùng một kết quả khi thu thập các đối tượng Product
Tạo bộ lọc Extension Methods (Extension Methods Filter)
Vấn đề cuối cùng cần đề cập về extension methods là nó có thể dùng để lọc một bộ các đối tượng Một extension method chạy theo IEnumerable<T> và cũng trả về
IEnumerable<T> có thể dùng từ khóa yield để áp dụng các tiêu chí cho các item trong source data để trả về 1 bộ các kết quả List 4-17 mô tả một method như vậy, nó được thêm vào lớp MyExtensionMethods
Extension method này gọi là FilterByCategory, lấy thêm một tham số nữa cho phép chúng ta truyền vào điều kiện lọc khi chúng ta có lời gọi đến method này Các đối tượng
Product có thuộc tính Category thỏa mãn tham số này sẽ được trả về trong phần kết quả của
IEnumerable<Product>, những đối tượng không thỏa mãn sẽ bị lược bỏ List 4-18 miêu tả cách sử dụng method này
Trang 15
Khi chúng ta có lời gọi hàm FilterByCategory trong lớp ShoppingCart, chỉ những sản phẩm có thuộc tính Category là Soccer được trả về Nếu chúng ta cho chạy project và điều hướng vào UseFileterExtensionMethod action method, chúng ta có thể thấy kết quả là tổng giá trị của các đối tượng có thuộc tính Category là Soccer
Trang 16Sử dụng Lambda Expression
Chúng ta có thể sử dụng một đại diện để giúp cho FilterByCategory có tính tổng thể hơn Bằng cách này, đại diện sẽ được gọi đối với từng Product để lọc các đối tượng mỗi khi chúng ta chọn List 4-19 miêu tả Filter extension method được thêm vào lớp
MyExtensionMethods
Chúng ta sử dụng Func như là tham số để lọc, nghĩa là chúng ta không cần định nghĩa đại diện này như một kiểu Đại diện này lấy tham số là Product và trả về kết quả kiểu bool, nghĩa là sẽ trả về true nếu đối tượng Product đó có nằm trong phần kết quả trả về Phần còn lại của cách sắp xếp này tương đối dài dòn List 4-20 miêu tả những thay đổi trên
UserFilterExtensionMethod action method trong lớp Home controller
Trang 17Chúng ta đã tiến thêm một bước, hiện chúng ta có thể lọc các đối tượng Product sử dụng những tiêu chí được đặt ra trong phần đại diện nhưng chúng ta phải định nghĩa Func cho mỗi kiểu lọc chúng ta muốn, đây không phải là ý tưởng chúng ta hướng đến Một cách
để giảm bớt sự dài dòng này là sử dụng lambda expression, đây là một định dạng xúc tích nhừng thể hiện phần thân của một method trong bằng một đại diện Chúng ta có thể dùng
nó để định nghĩa đại diện trong action method: List 4-21
Trang 18Phần lambda expression được tô đậm Tham số được biểu diễn mà không cần định
nghĩa kiểu, nghĩa là nó sẽ được suy ra một cách tự động Phần ký tự ‘=>’ có thể hiểu nghĩa
là đi đến và sau đó là phần link chỉ đến tham số cho kết quả của lambda expression Trong
ví dụ này, một tham số Product gọi là prod trả về kết quả kiểu bool, nghĩa là sẽ trả về kết quả
true nếu tham số Category của prod bằng Soccer Chúng ta có thể xây dựng các câu lệnh
chặt chẽ hơn nữa bằng cách bỏ đi hoàn toàn từ khóa Func List 4-22
Trang 19Trong ví dụ này chúng ta cungcấp lambda expression như một tham số cho hàm
Filter Đây là một cách hay và tự nhiên để thể hiện cách lọc mà chúng ta muốn áp dụng
Chúng ta có thể kết hợp nhiều bộ lọc bằng cách mở rộng kết quả trong lambda expression
như trong List 4-23
Trang 20Khi thực hiện, chương trình sẽ kiểm tra xem các đối tượng Product nào có thuộc tính Category là Soccer và có thuộc tính giá Price lớn hơn 20
Một số mẫu cho Lambda expression
Chúng ta không cần định nghĩa logic cho các đại diện trong lambda expreesion, chúng
ta có thể dễ dàng gọi đến một method như sau
Nếu chúng ta cần lambda expression cho một đại diện có nhiều tham số, chúng ta có thể nhóm các tham số vào trong dấu ngoặc :
Và cuối cùng khi chúng ta cần hàm logic trong lambda expression cần nhiều hơn một câu lệnh, chúng ta có thể dùng dấu ({ }) và hoàn tất với câu lệnh return
Chúng ta không nhất thiết sử dụng Lambda expression trong phần code của mình tuy nhiên chúng là một công cụ khéo léo xử lý các hàm phức tạp một cách tường minh và dễ đọc Công cụ này sẽ được sử dụng xuyên suốt trong cuốn sách này