2010-10-25 15 views
11

Nếu tôi có quan điểm mạnh mẽ-gõ sau:ASP.NET MVC 2 - Binding Để Tóm tắt Mẫu

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<XXX.DomainModel.Core.Locations.Location>" %> 

đâu Location là lớp trừu tượng.

Và tôi đã Controller sau đây, mà chấp nhận một mô hình mạnh mẽ, đánh máy thông qua một POST:

[HttpPost] 
public ActionResult Index(Location model) 

tôi nhận được một lỗi runtime nêu "Không thể Tạo Tóm tắt Lớp

nào Tuy nhiên - tôi không chắc giải pháp tốt nhất là gì ở đây

Tôi có nhiều loại bê tông (khoảng 8), và đây là chế độ xem bạn c một thuộc tính chỉnh sửa duy nhất của lớp trừu tượng.

Điều tôi đã cố gắng để làm là tạo quá tải cho tất cả các loại bê tông khác nhau và thực hiện logic của tôi theo một phương pháp chung.

[HttpPost] 
public ActionResult Index(City model) 
{ 
    UpdateLocationModel(model); 
    return View(model); 
} 

[HttpPost] 
public ActionResult Index(State model) 
{ 
    UpdateLocationModel(model); 
    return View(model); 
} 

vv vv

Và sau đó:

[NonAction] 
private void UpdateLocationModel (Location model) 
{ 
    // ..snip - update model 
} 

Nhưng điều này không làm việc, hoặc, MVC than phiền các phương pháp hành động là mơ hồ (cũng có ý nghĩa).

Chúng ta làm gì? Chúng ta có thể đơn giản không liên kết với một mô hình trừu tượng?

+1

Tốt câu hỏi. Quan tâm đến việc xem câu trả lời! –

+0

Tôi tò mò liệu bạn có bao giờ tìm ra cách tốt hơn để xử lý việc này không? –

+0

@Mystere Man - không. Tôi đã không phải làm điều đó một lần nữa. Nếu tôi đã làm, tôi sẽ làm những gì câu trả lời chấp nhận cho thấy. – RPM1984

Trả lời

7

Làm thế nào về cách viết một mô hình tùy chỉnh chất kết dính cho lớp trừu tượng này:

public class CustomBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     // TODO: based on some request parameter choose the proper child type 
     // to instantiate here 
     return new Child(); 
    } 
} 

này có ý nghĩa chỉ khi bạn có một hình thức mà các yếu tố đầu vào được chèn tự động dựa trên số hành động người dùng. Trong trường hợp này, bạn cần truyền một số tham số bổ sung để chỉ ra lớp bê tông nào bạn cần. Nếu không, tôi sẽ dính vào các mô hình xem bê tông như các tham số hành động.

+0

Đây là chế độ xem rất đơn giản, chỉnh sửa các trường cho thuộc tính trên mô hình trừu tượng. Vì vậy, tôi không muốn phải "trùng lặp" HTML này trên nhiều chế độ xem được nhập mạnh mẽ. Tôi sẽ có một cái nhìn vào chất kết dính mô hình tùy chỉnh - như tôi biết loại con khi tôi render khung nhìn. Tôi sẽ thử nó vào ngày mai - chúc mừng. – RPM1984

+0

Được rồi, tôi đã đọc về các chất kết dính mô hình và tôi đồng ý - điều đó không có ý nghĩa trong kịch bản của tôi. Tôi sẽ gắn bó với các mô hình xem cụ thể. Điều này sẽ làm việc mặc dù, vì vậy tôi sẽ chấp nhận câu trả lời của bạn. Cảm ơn. – RPM1984

1

Chỉ cần ném nó ra khỏi đó - Tôi rất quan tâm đến những gì người khác có thể trả lời, nhưng đây là những gì tôi đã kết thúc làm trong trường hợp tôi đã có một tình huống tương tự; Về cơ bản, tôi đã không sử dụng lớp mô hình làm tham số trong phương thức Hành động, thay vào đó chuyển qua số FormCollection và thử nghiệm một vài phân biệt đối xử đã biết để tìm ra loại/chỉnh sửa, sau đó sử dụng TryUpdateModel từ đó.

Dường như có thể có cách tốt hơn, nhưng tôi chưa bao giờ nghĩ đến nó nhiều hơn.

+0

Vâng, đó là bước tiếp theo của tôi! :) Nhưng awww, tôi không phải lòng tốt. :) – RPM1984

+0

Nó ngon và bổ dưỡng; Một phần của bữa sáng hoàn chỉnh này! –

3

Bạn cũng có thể xây dựng một ModelBinder chung chung phù hợp với tất cả các mô hình trừu tượng của bạn. Giải pháp của tôi yêu cầu bạn thêm trường ẩn vào chế độ xem của bạn được gọi là 'ModelTypeName' với giá trị được đặt thành tên của loại bê tông mà bạn muốn. Tuy nhiên, nó có thể làm cho điều này thông minh hơn và chọn một loại cụ thể bằng cách kết hợp các thuộc tính kiểu cho các trường trong dạng xem.

Trong Global.asax.cs tập tin của bạn trong Application_Start():

ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); 

CustomModelBinder:

public class CustomModelBinder2 : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var modelType = bindingContext.ModelType; 
     if (modelType.IsAbstract) 
     { 
      var modelTypeValue = controllerContext.Controller.ValueProvider.GetValue("ModelTypeName"); 
      if (modelTypeValue == null) 
       throw new Exception("View does not contain ModelTypeName"); 

      var modelTypeName = modelTypeValue.AttemptedValue; 

      var type = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == modelTypeName); 

      if (type != null) 
      { 
       var instance= bindingContext.Model ?? base.CreateModel(controllerContext, bindingContext, type); 
       bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, type); 
      } 
     } 
     return base.BindModel(controllerContext, bindingContext); 
    } 
} 
+0

Đây là một câu trả lời hữu ích, nhưng chỉ cho bất cứ ai áp dụng nó, tôi nghi ngờ có thể có một nguy cơ bảo mật ở đây nếu khách hàng gửi lại một tên không hợp lệ nhưng hợp pháp với một nhà xây dựng có hại. Đúng? –

+0

xem thêm http://stackoverflow.com/questions/7222533/polymorphic-model-binding/9813472#9813472 –

+0

@ uosɐſ: chỉ trong trường hợp MVC đang cố gắng ánh xạ tới một lớp con (xem '.IsSubclassOf (...) ') của lớp trừu tượng được mong đợi được sử dụng trong chữ ký hành động của bộ điều khiển hoặc một trong các thuộc tính con của đối tượng chữ ký của hành động điều khiển. Và sau đó nó phải có một nhà xây dựng "có hại". Tôi đang nghĩ đến việc sử dụng mã này. Bạn có thể đưa ra một ví dụ về rủi ro bảo mật như vậy không? –