Đây là cách tôi bắt đầu tiếp cận vấn đề. Một mô hình tùy chỉnh chất kết dính sẽ được khá dễ dàng để xây dựng dựa trên tài sản FormKey (có thể được xác định bởi chỉ số và/hoặc nhãn, tùy thuộc).
public class CustomFormModel
{
public string FormId { get; set; }
public string Label { get; set; }
public CustomFieldModel[] Fields { get; set; }
}
public class CustomFieldModel
{
public DataType DateType { get; set; } // System.ComponentModel.DataAnnotations
public string FormKey { get; set; }
public string Label { get; set; }
public object Value { get; set; }
}
public class CustomFieldModel<T> : CustomFieldModel
{
public new T Value { get; set; }
}
Ngoài ra, tôi nhận thấy một trong các nhận xét bên dưới có hệ thống kết nối mô hình được lọc. Jimmy Bogard từ Automapper đã thực hiện một bài viết thực sự hữu ích về phương pháp này tại http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/03/17/a-better-model-binder.aspx, và sau đó sửa đổi trong, http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/11/19/a-better-model-binder-addendum.aspx. Nó đã được rất hữu ích cho tôi trong việc xây dựng chất kết dính mô hình tùy chỉnh.
Cập nhật
Tôi nhận ra rằng tôi hiểu sai câu hỏi, và rằng ông đã đặc biệt yêu cầu làm thế nào để xử lý niêm yết dưới hình thức "với một số biến của lĩnh vực đầu vào mà đại diện cho các kiểu dữ liệu khác nhau". Tôi nghĩ cách tốt nhất để làm điều này là sử dụng cấu trúc tương tự như trên nhưng tận dụng số Composite Pattern. Về cơ bản, bạn sẽ cần phải tạo một giao diện như IFormComponent
và triển khai nó cho mỗi kiểu dữ liệu sẽ được biểu diễn. Tôi đã viết và cho ý kiến một giao diện ví dụ để giúp giải thích cách thức này sẽ được thực hiện:
public interface IFormComponent
{
// the id on the html form field. In the case of a composite Id, that doesn't have a corresponding
// field you should still use something consistent, since it will be helpful for model binding
// (For example, a CompositeDateField appearing as the third field in the form should have an id
// something like "frmId_3_date" and its child fields would be "frmId_3_date_day", "frmId_3_date_month",
// and "frmId_3_date_year".
string FieldId { get; }
// the human readable field label
string Label { get; }
// some functionality may require knowledge of the
// Parent component. For example, a DayField with a value of "30"
// would need to ask its Parent, a CompositeDateField
// for its MonthField's value in order to validate
// that the month is not "February"
IFormComponent Parent { get; }
// Gets any child components or null if the
// component is a leaf component (has no children).
IList<IFormComponent> GetChildren();
// For leaf components, this method should accept the AttemptedValue from the value provider
// during Model Binding, and create the appropriate value.
// For composites, the input should be delimited in someway, and this method should parse the
// string to create the child components.
void BindTo(string value);
// This method should parse the Children or Underlying value to the
// default used by your business models. (e.g. a CompositeDateField would
// return a DateTime. You can get type safety by creating a FormComponent<TValue>
// which would help to avoid issues in binding.
object GetValue();
// This method would render the field to the http response stream.
// This makes it easy to render the forms simply by looping through
// the array. Implementations could extend this for using an injected
// formatting
void Render(TextWriter writer);
}
Tôi giả định rằng các hình thức tùy chỉnh có thể được truy cập thông qua một số loại id mà có thể được chứa như một tham số hình thức. Với giả định đó, người mẫu và nhà cung cấp mô hình có thể trông giống như thế này.
public interface IForm : IFormComponent
{
Guid FormId { get; }
void Add(IFormComponent component);
}
public interface IFormRepository
{
IForm GetForm(Guid id);
}
public class CustomFormModelBinder : IModelBinder
{
private readonly IFormRepository _repository;
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult result;
if(bindingContext.ValueProvider.TryGetValue("_customFormId", out result))
{
var form = _repository.GetForm(new Guid(result.AttemptedValue));
var fields = form.GetChildren();
// loop through the fields and bind their values
return form;
}
throw new Exception("Form ID not found.");
}
}
Rõ ràng, tất cả mã ở đây chỉ để lấy điểm và cần được hoàn thành và dọn dẹp để sử dụng thực tế. Ngoài ra, ngay cả khi hoàn thành điều này sẽ chỉ liên kết với một thực hiện của giao diện IForm, không phải là một đối tượng kinh doanh mạnh mẽ đánh máy.(Nó sẽ không phải là một bước tiến lớn để chuyển đổi nó thành từ điển và xây dựng một proxy mạnh mẽ bằng cách sử dụng Castle DictionaryAdapter, nhưng vì người dùng của bạn đang tạo động các biểu mẫu trên trang web, có lẽ không có mô hình nào được đánh máy mạnh mẽ trong giải pháp của bạn và điều này là không liên quan). Hy vọng điều này sẽ giúp ích nhiều hơn.
Cảm ơn các ý kiến, rất sâu sắc. – DanP