@str
} @Html.ActionLink("Back", "Names"); } Tính action Names khơng đổi tơi làm việc với collection thay mảng Ràng buộc Collection kiểu Model tùy chỉnh Tôi ràng buộc riêng thuộc tính dự liệu vào mảng tùy chọn liệu, lớp model AddressSummary Trong Listing 24-25, bạn thấy tơi thêm vào mội phương thức action vào controller Home gọi Address có tham số kiểu collection dựa vào lớp model tùy chỉnh Listing 24-25 Nội dung tập tin HomeController.cs using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MvcModels.Models; namespace MvcModels.Controllers { public class HomeController : Controller { // other methods and statements omitted for brevity public ActionResult Address(IList addresses) { addresses = addresses ?? new List(); return View(addresses); } } } View mà tạo cho phương thức action /Views/Home/Address.cshtml, bạn thấy Listing 24-26 Listing 24-26 Nội dung tập tin Address.cshtml tập tin @using MvcModels.Models @model IList @{ ViewBag.Title = "Address"; Layout = "∼/Views/Shared/_Layout.cshtml"; }< h2>Addresses @if (Model.Count() == 0) { using (Html.BeginForm()) { for (int i = 0; i < 3; i++) { Address @(i + 1) City:@Html.Editor("[" + i + "].City") Country:@Html.Editor("[" + i + "].Country") } Submit } } else { foreach (AddressSummary str in Model) {@str.City, @str.Country
} @Html.ActionLink("Back", "Address"); } View trả vể khơng có item model collection Form bao gồm cặp thuộc tính mơ tả name prefixed với số mảng sau: Address 1 City: Country: Address 2 City: Country: Khi Form submit, model binder mặc định nhận cần phải tạo đối tượng collection AddressSummary sử dụng số mảng để prefix thuộc tính mô tả name để thu thập giá trị cho thuộc tính đối tượng Các thuộc tính prefix [0] sử dụng cho đối tượng AddressSummary đầu tiên, prefix [1] sử dụng cho đối tượng thứ hai tiếp tục đến hết View Address.cshtml định nghĩa cho ba đối tượng đánh mục hiển thị chúng model collection có chứa item Trước tơi minh họa nó, tơi cần xóa thuộc tính mơ tả Bind lớp model AddressSummary Listing 24-27; không model binder bỏ qua thuộc tính Country Listing 24-27 Nội dung tập tin AddressSummary.cs using System.Web.Mvc; namespace MvcModels.Models { // This attribute has been commented out //[Bind(Include="City")] public class AddressSummary { public string City { get; set; } public string Country { get; set; } } } Bạn thấy cách trình ràng buộc cho đối tượng collection tùy chỉnh làm việc cách khởi động ứng dụng điều hướng đến URL /Home/Address Sử dụng vài thành phố vài quốc gia sau submit để post form đến server Model binder tìm kiếm xử lí giá trị liệu đánh mục sử dụng chúng để tạo đối tượng collection AddressSummary mà sau truyền ngược cho view hiển thị cho bạn hình 24-9 Gọi model binding cách thủ cơng Q trình model binding thực thi tự động phương thức action định nghĩa tham số tơi trực tiếp điều khiển tơi muốn Việc cho phép điều khiển cách rõ ràng cách đối tượng model khởi tạo, chỗ mà giá trị liệu thu thập, cách lỗi chuyển đổi liệu xử lí Listing 24-28 minh họa cách tơi thay đổi phương thức action Address controller Home để gọi trình binding cách thủ cơng Listing 24-28 Nội dung tập tin HomeController.cs using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MvcModels.Models; namespace MvcModels.Controllers { public class HomeController : Controller { // other methods and statements omitted for brevity public ActionResult Address() { IList addresses = new List(); UpdateModel(addresses); return View(addresses); } } } Phương thức UpdateModel lấy đối tượng model mà vừa định nghĩa tham số cố thu thập giá trị cho thuộc tính public sử dụng q trình binding chuẩn Khi tơi gọi q trình binding cách thủ cơng, tơi ngăn cản q trình ràng buộc liệu đơn Mặc định, binder tìm kiêm nơi: liệu form, liệu định tuyến, chuỗi truy vấn tập tin tải lên Listing 24-29 thể cách hạn chế binder tìm kiếm dử liệ vị trí nhất, trường hợp liệu form Listing 24-29 Nội dung tập tin HomeController.cs public ActionResult Address() { IList addresses = new List(); UpdateModel(addresses, new FormValueProvider(ControllerContext)); return View(addresses); } Phiên phương thức UpdateModel lấy thực thi interface IValueProvider, mà người liệu cho trình ràng buộc Mỗi vị trí bốn vị trí liệu mặc định thề thực thi IValueProvider hình Table 24-3 Mỗi lớp liệt kê bảng 24-3 thâm số khởi tạo ControllerContext mà tơi thu thập thơng qua thuộc tính gọi ControllerContext định nghĩa lớp Controller listing Cách phổ biến để hạn chế nguồn liệu tìm kiếm giá trị form Có mẹo ràng buộc gọn gàng mà sử dụng tơi khơng phải tạo thực thể FormValueProvider Listing 2430 Listing 24-30 Nội dung tập tin HomeController.cs public ActionResult Address(FormCollection formData) { IList addresses = new List(); UpdateModel(addresses, formData); return View(addresses); } Lớp FormCollection thực thi interface IValueProvider định nghĩa phương thức action để lấy tham số kiểu này, model binder cung cấp cho dối tượng mà tơi truyền trực tiếp vào phương thức UpdateMethod Tip: có phiên khác phương thức UpdateMethod rõ prefix để tìm kiếm thuộc tính model chứa trình ràng buộc Giải lỗi ràng buộc Người dùng chắn cung cấp giá trị mà khơng thể bị ràng buộc vào thuộc tính ngày tháng hợp lệ model text giá trị số Khi gọi model binding cách rõ ràng, tơi có trách nhiệm đối phó với lỗi Các model binder lỗi ràng buộc cách ném InvalidOperationException Chi tiết lỗi tìm thấy thơng qua tính ModelState, mà mô tả Chương 25 Nhưng sử dụng phương pháp UpdateModel, phải chuẩn bị để bắt ngoại lệ sử dụng ModelState để thể thông báo lỗi cho người dùng, hiển thị Listing 24-31 Listing 24-31 Nội dung tập tin HomeController.cs public ActionResult Address(FormCollection formData) { IList addresses = new List(); try { UpdateModel(addresses, formData); } catch (InvalidOperationException ex) { // provide feedback to user } return View(addresses); } Như cách tiếp cận thay thế, tơi sử dụng phương thức TryUpdateModel, mà trả true trình model binding thành cơng false có lỗi Listing 24-32 Listing 24-32 Nội dung tập tin HomeController.cs public ActionResult Address(FormCollection formData) { IList addresses = new List(); if (TryUpdateModel(addresses, formData)) { // proceed as normal } else { // provide feedback to user } return View(addresses); } Lý để ưu tiên TryUpdateModel UpdateModel bạn khơng thích bắt xử lý trường hợp ngoại lệ Khơng có khác biệt chức mơ hình q trình ràng buộc Tip: Khi model binding gọi tự động, lỗi ràng buộc không thông báo với trường hợp ngoại lệ Thay vào đó, bạn phải kiểm tra kết thơng qua thuộc tính ModelState.IsValid Tơi giải thích ModelState Chương 25 Tùy chỉnh hệ thống Model Binding Tôi cho bạn mơ hình mặc định quy trình ràng buộc Như bạn kỳ vọng bây giờ, có số cách khác nhau, hệ thống ràng buộc tùy chỉnh Tơi cho bạn số ví dụ phần sau Tạo Provider tùy chỉnh giá trị Bằng việc xác định Provider tùy chỉnh giá trị, tơi thêm source riêng tơi liệu cho q trình model binding Provider thực thi interface IValueProvider, thể Listing 24-33 Listing 24-33 Nội dung interface IValueProvider namespace System.Web.Mvc { public interface IValueProvider { bool ContainsPrefix(string prefix); ValueProviderResult GetValue(string key); } } Các Phuong thức ContainsPrefix gọi model binder để xác định liệu giá trị Provider giải liệu prefix cho hay không Phương thức GetValue trả giá trị key cho, null provider khơng có liệu phù hợp Tơi thêm thư mục Infrastructure cho ứng dụng ví dụ tạo lớp gọi CountryValueProvider.cs, mà sử dụng để cung cấp giá trị cho thuộc tính Country Bạn xem nội dung tập tin Listing 24-34 Listing 24-34 Nội dung tập tin CountryValueProvider.cs using System.Globalization; using System.Web.Mvc; namespace MvcModels.Infrastructure { public class CountryValueProvider : IValueProvider { public bool ContainsPrefix(string prefix) { return prefix.ToLower().IndexOf("country") > -1; } public ValueProviderResult GetValue(string key) { if (ContainsPrefix(key)) { return new ValueProviderResult("USA", "USA", CultureInfo.InvariantCulture); } else { return null; } } } } Giá trị Provider đáp ứng yêu cầu cho giá trị cho thuộc tính Country ln ln trả giá trị USA Đối với tất yêu cầu khác, trả null, cung cấp liệu Tôi phải trả giá trị liệu kiểu ValueProviderResult Lớp có ba thơng số constructor Đầu tiên liệu mà tơi muốn kết hợp với khóa u cầu Tham số thứ hai phiên giá trị liệu an toàn để hiển thị phần trang HTML.Tham số cuối thơng tin văn hóa có liên quan đến giá trị; Tơi có định InvariantCulture Để đăng giá trị provider cho ứng dụng, cần phải tạo lớp factory mà tạo thực thể provider chúng yêu cầu MVC Framework Các lớp factory phải chiết xuất từ lớp Abstract ValueProviderFactory Listing 24-35 Nội dung tập tin ValueProviderFactory.cs using System.Web.Mvc; namespace MvcModels.Infrastructure { public class CustomValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { return new CountryValueProvider(); } } } Phương pháp GetValueProvider gọi model binder muốn có giá trị cho q trình binding Việc thực thi đơn giản tạo trả thể lớp CountryValueProvider, bạn sử dụng liệu cung cấp thông qua tham số ControllerContext để đáp ứng với loại khác yêu cầu cách tạo provider giá trị khác Tôi cần đăng kí lớp factory với ứng dụng phương thức Application_Start tập tin Global.asax Listing 24-36 Listing 24-36 Nội dung tập tin Global.asax using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using MvcModels.Infrastructure; namespace MvcModels { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Insert(0, new CustomValueProviderFactory()); } } } Tôi đăng ký lớp factory cách thêm thực thể vào collection ValueProviderFactories.Factories tĩnh Model binder xem xét provider giá trị theo thứ tự, có nghĩa phải sử dụng phương thức Insert để đặt factory tùy chỉnh vị trí sưu tập muốn ưu tiên provider tích hợp Nếu tơi muốn provider tùy chinh fallback sử dụng provider khác khơng thẻ cung cấp giá trị liệu tơi sử dụng phương thức Add để thêm lớp factory vào vị trí cuối collection ValueProviderFactories.Factories.Add(new CustomValueProviderFactory()); Tôi muốn provider giá trị tùy chỉnh sử dụng trước provider khác, sử dụng phương pháp Insert Tôi cần phải chỉnh sửa phương thức action Address trước kiểm tra provider giá trị, model binder không xem xét liệu mẫu cho giá trị thuộc tính model Trong Listing 24-37, bạn nhìn thấy cách tơi tơi xố hạn chế mã nguồn cho giá trị lệnh gọi phương thức TryUpdateModel Listing 24-37 Nội dung tập tin HomeController.cs using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MvcModels.Models; namespace MvcModels.Controllers { public class HomeController : Controller { // other methods and statements omitted for brevity public ActionResult Address() { IList addresses = new List(); UpdateModel(addresses); return View(addresses); } } } Bạn thấy provider giá trị tùy chỉnh hoạt động bạn khởi động ứng dụng điều hướng đến URL /Home/Address Nhập vào liệu thuộc tính thành phố quốc gia, sau submit Bạn thấy provider giá trị tùy chỉnh có ưu tiên provider tích hợp dùng để tạo giá trị cho thuộc tính Country đối tượng AddressSummary tạo model binder hình 24-10 Tạo model binder tùy chỉnh Tơi ghi đè hàn vi binder mặc cách tạo model binder tùy chỉnh cho loại cụ thể Model binder tùy chỉnh thực thi interface IModelBinder mà đầu chương Để minh họa cách tạo binder tùy chỉnh, thêm lớp AddressSummaryBinder.cs thư mục Infrastructure, bạn thấy nội dung Listing 24-38 Listing 24-38 Nội dung tập tin AddressSummaryBinder.cs using MvcModels.Models; using System.Web.Mvc; namespace MvcModels.Infrastructure { public class AddressSummaryBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { AddressSummary model = (AddressSummary)bindingContext.Model ?? new AddressSummary(); model.City = GetValue(bindingContext, "City"); model.Country = GetValue(bindingContext, "Country"); return model; } private string GetValue(ModelBindingContext context, string name) { name = (context.ModelName == "" ? "" : context.ModelName + ".") + name; ValueProviderResult result = context.ValueProvider.GetValue(name); if (result == null || result.AttemptedValue == "") { return ""; } else { return (string)result.AttemptedValue; } } } } MVC Framework gọi phương thức BindModel muốn thể kiểu model mà binder hỗ trợ Tơi bạn cách ngắn gọn để đăng kí model binder lớp AdreesSummaryBinder sử dụng để tạo thể lớp AddressSummary làm cho code đơn giản (bạn tạo binder tùy chỉnh hỗ trợ đa định dạng tơi thích binder cho kiểu) Tip: Tôi không thực kiểm tra đầu vào model binder này, có nghĩa tơi vơ tình đốn người dùng cung cấp giá trị hợp lệ cho tất thuộc tính Person Tôi thảo luận xác nhận Chương 25, thời điểm này, muốn tập trung vào trình model binding Các tham số phương pháp BindModel đối tượng ControllerContext mà bạn sử dụng để có thơng tin chi tiết yêu cầu đối tượng ModelBindingContext, cung cấp thông tin chi tiết đối tượng model tìm kiếm, truy cập vào phần lại sở model binding ứng dụng MVC Trong Bảng 24-4, mô tả thuộc tính hữu ích xác định lớp ModelBindingContext Model binder tùy chỉnh đơn giản Khi phương thức BindModel gọi, tơi kiểm tra xem thuộc tính Model đối tượng ModelBindingContext có cài đặt hay khơng Nếu cài đặt, đối tượng mà tạo giá trị liệu cho, khơng tơi tạo thực thể lớp AddressSummary Tơi lấy giá trị cho thuộc tính City Country cách gọi phương thức GetValue trả đối tượng AddressSummary Trong phương thức GetValue, sử dụng thực thi interface IValueProvider thu từ thuộc tính ModelBindingContext.ValueProvider để lấy giá trị cho thuộc tính mơ hình đối tượng Thuộc tính ModelName nói với tơi có tiền tố tơi cần phải nối thêm vào tên thuộc tính tơi tìm kiếm Bạn nhớ lại phương thức action cố gắng để tạo collection đối tượng AddressSummary, có nghĩa yếu tố đầu vào riêng có giá trị thuộc tính tên bắt đầu [0] [1] Giá trị tơi tìm kiếm yêu cầu [0] City, [0] Country, tiếp tục Bước cuối cùng, cung cấp giá trị mặc định tơi khơng thể tìm thấy giá trị cho thuộc tính thuộc tính chuỗi rỗng (đó gửi đến máy chủ người dùng không nhập giá trị vào thẻ form) Đăng kí Model Binder tùy chọn Tơi phải đăng ký model binder tùy chọn để ứng dụng MVC hiểu cần phải hỗ trợ kiểu Tôi thực việc phuong thức Application_Start Global.asax, minh họa Listing 24-39 Listing 24-39 Nội dung tập tin Global.asax using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using MvcModels.Infrastructure; using MvcModels.Models; namespace MvcModels { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); // This statement has been commented out //ValueProviderFactories.Factories.Insert(0, // new CustomValueProviderFactory()); ModelBinders.Binders.Add(typeof(AddressSummary), new AddressSummaryBinder()); } } } Tôi đăng ký binder thông qua phương thức ModelBinders.Binders.Add, truyền vào loại mà binder hỗ trợ thể lớp binder Chú ý tơi xố câu lệnh để đăng ký provider giá trị tùy chỉnh Bạn kiểm tra model binder tùy chỉnh cách bắt đầu ứng dụng, điều hướng đến URL / Home / Address, điền vào vài thẻ cùa form Khi bạn submit form, model binder tùy chỉnh sử dụng để hiển thị tất thuộc tính mà bạn không nhập vào giá trị, thể hình 24-11 Đăng kí Model Binder với thuộc tính mơ tả Bạn đăng ký model binders tùy chỉnh cách thêm vào lớp model thuộc tính mơ tả ModelBinder, có nghĩa bạn khơng cần phải sử dụng tập tin Global.asax Trong Listing 24-40, bạn thấy tơi định AddressSummaryBinder binder cho lớp AddressSummary Listing 24-40 Nội dung tập tin AddressSummary.cs using System.Web.Mvc; using MvcModels.Infrastructure; namespace MvcModels.Models { [ModelBinder(typeof(AddressSummaryBinder))] public class AddressSummary { public string City { get; set; } public string Country { get; set; } } } Tổng kết Trong chương này, giới thiệu cho bạn hoạt động trình model binding, cho bạn thấy làm model binding mặc định hoạt động cách thức triển khai khác nhau, q trình tùy chỉnh Nhiều ứng dụng MVC Framework cần model binder mặc định đủ để xử lý HTML mà phương thức helper tạo Nhưng ứng dụng cao cấp hơn, việc sử dụng model binding tùy chỉnh hữu ích việc tạo đối tượng model cách hiệu cụ thể Trong chương tiếp theo, cho bạn làm để chứng thực đối tượng mơ hình cách thể cho người dùng với lỗi có ý nghĩa liệu khơng hợp lệ nhận ... buộc liệu đơn Mặc định, binder tìm kiêm nơi: liệu form, liệu định tuyến, chuỗi truy vấn tập tin tải lên Listing 24- 29 thể cách tơi hạn chế binder tìm kiếm dử liệ vị trí nhất, trường hợp liệu. .. thực thi concrete( dù tơi tơi thích) Trong Listing 24- 24, bạn thấy cách tơi chỉnh sửa tập tin view Names.cshtml để sử dụng kiểu model Listing 24- 24 Nội dung tập tin Names.cshtml @model IList... mà giá trị liệu thu thập, cách lỗi chuyển đổi liệu xử lí Listing 24- 28 minh họa cách thay đổi phương thức action Address controller Home để gọi trình binding cách thủ công Listing 24- 28 Nội dung