Hướng dẫn về ASP.NET MVC và Action Result

Nếu bạn đã từng làm việc trong một dự án ASP.NET MVC thì chắc chẳng còn xa lạ gì với khái niệm Action result mà ASP.NET MVC đã và đang cung cấp. Việc nắm rõ các Action result này sẽ giúp bạn cải thiện chất lượng cũng như năng suất khi làm website bằng .NET MVC.

I. ViewResult là gì:

Đây có lẽ là Action Result (AS) cơ bản và phổ dụng nhất trong tất cả các AS, nó sẽ render ra mã HTML và trả lại cho trình duyệt ở phía người dùng. Để sử dụng thì chúng ta cần khái báo 1 đối tượng lớp ViewResult với kiểu trả về là View như sau:

using System.Web.Mvc; 

namespace ControllersAndActions.Controllers { 

    public class ExampleController : Controller { 

        public ViewResult Index() {
            return View("Index");
        }
    }
}

Chúng ta sẽ chỉ định View nào sẽ được hiển thị bằng cách gán tham số cho đối tượng View được trả về ở return, ở đây là Index.

Hoặc có thể viết một cách tường minh hơn như sau:

using System.Web.Mvc; 

namespace ControllersAndActions.Controllers { 

    public class ExampleController : Controller { 

        public ViewResult Index() {
            return new ViewResult {ViewName = "CodeDaily.vn"};
        }
    }
}

Khi MVC Framework goi View trả về thì nó sẽ tìm kiếm cái View mà chúng ta đã chỉ định (Index). Nếu có sử dụng Area trong dự án, thì framework sẽ tìm những vị trí như sau:

  • /Areas//Views//.aspx
  • /Areas//Views//.aspx
  • /Areas//Views//.ascx
  • /Areas//Views/Shared/.aspx
  • /Areas//Views/Shared/.ascx
  • /Areas//Views//.cshtml
  • /Areas//Views//.vbhtml
  • /Areas//Views/Shared/.cshtml
  • /Areas//Views/Shared/.vbhtml

Nếu không sử dụng Area hoặc chúng ta sử dụng Area nhưng MVC Framework không tìm thấy thấy file cần tìm thì nó sẽ tìm tiếp những vị trí sau:

  • /Views//.aspx
  • /Views//.ascx
  • /Views/Shared/.aspx
  • /Views/Shared/.ascx
  • /Views//.cshtml
  • /Views//.vbhtml
  • /Views/Shared/.cshtml
  • /Views/Shared/.vbhtml

Và ngay khi MVC framework kiểm tra một vị trí và file cần thiết được tìm thấy thì nó sẽ dừng công việc tìm kếm và sử dụng View đó để tạo kết quả và trả về cho người dùng.

Cách thức tìm kiếm tuần tự của MVC Framework được gọi là 

convention over configuration

. Chúng ta không cần đăng ký các file view với framework mà chúng ta chỉ cần đặt những file view vào những vị trí mà framework biết trước và framework sẽ tìm chúng.

Trong trường hợp chúng ta không chi định tên View như sau:

using System.Web.Mvc; 

namespace ControllersAndActions.Controllers { 

    public class ExampleController : Controller { 

        public ViewResult Codedaily() {
            return View();
        }
    }
}

Thì MVC Framework sẽ mặc định tên View là tên của Action, trong ví dụ trên tên View sẽ là Codedaily.

Nhìn đoạn code mẫu ở ví dụ trên thì chúng ta có thể xác định được file View sẽ nằm ở vị trí: ~/View/Example/Codedaily.chtml (hoặc ~/View/Example/Codedaily.vbhtml nếu là VB.NET).

II. Gửi và nhận data giữa View và Action:

1. Truyền dữ liệu trực tiếp vào return View():

Chúng ta có thể gửi trực tiếp một đối tượng dữ liệu từ Action đến View bằng cách truyền như là tham số đến phương thức View như sau:

public ViewResult Index() {
    DateTime date = DateTime.Now;
    return View(date);
}

Chúng ta truyền chuỗi codedaily như là view model. Chúng ta có thể truy xuất vào chuỗi này bằng cách dùng từ khóa Model của Razor như sau:

@{
    ViewBag.Title = "CodeDaily.vn";
}
<h2>Welcome to CodeDaily.vn</h2>
The day is: @(((DateTime)Model).DayOfWeek)

Cách mà chúng ta làm theo ở trên được gọi là 

untyped

 hay 

weakly type view

. View không biết bất cứ điều gì về đối tượng Model và xem nó như là một thể hiện của đối tượng object. Để lấy được giá trị của thuộc tính DayOfWeek, chúng ta cần chuyển đổi đối tượng thành thể hiện của lớp DateTime. Cách này thì chạy, nhưng nó làm cho code trong View của chúng ta thành một đóng bùi nhùi. Chúng ta có thể làm cho View của chúng ta sáng sủa, sạch sẽ hơn bằng cách dùng loại 

strongly typed view

 như đoạn mã sau:

@model DateTime
@{
    ViewBag.Title = "CodeDaily.vn";
}
<h2>Index</h2>
The day is: @Model.DayOfWeek

Chúng ta chỉ định kiểu của model view bằng cách sử dụng từ khóa 

model

 của Razor. Chúng ta sử dụng 

chữ m in thường

 khi chỉ định kiểu cho 

model

 và 

chữ M in hoa

 khi chúng ta 

đọc giá trị

. Điều này không chỉ giúp chúng ta dọn dẹp sạch sẽ view của chúng ta mà còn hỗ trợ IntelliSense cho strongly typed view

2. Sử dụng ViewBag:

View Bag cho phép chúng ta định nghĩa những thuộc tính bất kì trên 

dynamic object

 và truy xuất chúng trong View. 

Dynamic object

 được truy xuất qua thuộc tính

Controller.ViewBag

. Đoạn mã sau là ví dụ về View Bag

public ViewResult Index() { 

    ViewBag.Message = "Hello CodeDaily";
    ViewBag.Date = DateTime.Now; 

    return View();
}

Trong đoạn mã trên, chúng ta định nghĩa những thuộc tính là Message và Date đơn giản bằng cách gán những giá trị cho chúng. Và những thuộc tính này của chúng ta chưa hề tồn tại trước đó và chúng ta không hề chuẩn bị bất cứ gì để tạo ra chúng. Để đọc dữ liệu trở lại trong View, chúng ta đơn giản lấy cùng thuộc tính mà chúng ta đã set trong action như đoạn mã sau:

@{
    ViewBag.Title = "CodeDaily.vn";
}
<h2>Welcome to CodeDaily.vn</h2>
The day is: @ViewBag.Date.DayOfWeek

The message is: @ViewBag.Message

ViewBag có sự thuận tiện hơn view model ở chỗ nó dễ dàng truyền nhiều đối tượng đến view. Nếu chúng ta bị giới hạn sử dụng model của view, khi đó chúng ta cần tạo ra một kiểu mới có những member là string và DateTime để mà đạt được kết quả như dùng ViewBag ở trên Khi chúng ta làm việc với các đối tượng dynamic, chúng ta nhập vào trình tự của phương thức và gọi đến thuộc tính trong view như sau:

The day is: @ViewBag.Date.DayOfWeek.Blah.Blah.Blah

Tuy nhiên, Visual Studio không hỗ trợ IntelliSense những đối tượng dynamic, bao gồm ViewBag.

3. Sử dụng ViewData:

Tính năng View Bag được giới thiệu với phiên bản MVC 3. Trước đó, sự thay thế chính của model là view data. Tính năng của View Data tương tự như tính năng của View Bag, nhưng nó thực thi việc sử dụng lớp ViewDataDictionary hơn là việc sử dụng đối tương dynamic. Lớp ViewDataDictionary như là collection của các cặp key/value và truy xuất qua thuộc tính ViewData của lớp Controller. Ví dụ:

public ViewResult Index() { 

    ViewData["Message"] = "Hello CodeDaily";
    ViewData["Date"] = DateTime.Now; 

    return View();
}

Và chúng ta đọc ngược lại các giá trị trong view như sau:

@{
    ViewBag.Title = "CodeDaily";
}
<h2>Welcome to CodeDaily.vn</h2>
The day is: @(((DateTime)ViewData["Date"]).DayOfWeek)
The message is: @ViewData["Message"]

3. Sử dụng ViewModel:

Cách cuối cùng là sử dụng ViewModel, cách này là dễ sử dụng và nhiều ưu điểm nhất. Đầu tiên bạn cần khai báo một ViewModel. Về cơ bản ViewModel sẽ gần không gì một Entity class, ví dụ mẫu là 1 Entity Product:

public class Product
{
    public int Id { get; set; } // Ma product
    public string ProductName { get; set; } // Ten product
    public int CategoryId { get; set; } // Ma category (FK)
}

Còn đây là một ViewModel:

public class Product
{
    public int Id { get; set; } // Ma product

    [Display(Name="Product Name")]
    [Required]
    public string ProductName { get; set; } // Ten product

    [Required]
    public int CategoryId { get; set; } // Ma category (FK)

    public List<SelectedListItem> ListCategories { get; set; } // Danh sach category
}

Các bạn thấy là trong ViewModel không khác gì Entity, nhưng có thêm một số định nghĩa kèm theo như [Display], [Required], các định nghĩa này sẽ hỗ trợ trên View (Validate, Range,….) thay vì phải validate bằng Javascript hay các script chạy trên trình duyệt khác.

Với cách định nghĩa này thì ngoài View sẽ không sử dụng các thẻ input của Html mà sử dụng thư việc Html của .NET MVC như sau:

<div class="form-group">
    // Khoi tao textbox cho field ProductName
    @Html.TextboxFor(model => model.ProductName);

    // Khoi tao dropdownlist (select-option) cho field CategoryId với list data là ListCategories
    @Html.DropdownListFor(model => model.CategoryId, model.ListCategories);
</div>

Đặt tất cả trong Form và khi submit thì tất cả dữ liệu input trên page sẽ được fill vào ViewModel và truyền vào Controler, chúng ta có thể truy vẫn dữ liệu từ ViewModel như sau:

public ActionResult Create(ProductViewModel pvm)
{
    var productname = pvm.ProductName;
    var categoryId = pvm.CategoryId;

    // Xu ly business ....
    return View();
}