2009-05-29 27 views
24

Đây là câu hỏi chung về thiết kế: Bạn sẽ triển khai biểu mẫu động (thời gian chạy được tạo) trong ASP.NET MVC như thế nào?Các biểu mẫu động (thời gian chạy được tạo) trong ASP.NET MVC

Đây là tình hình:

  1. A admin trang web có thể xác định các tham số hình thức (lĩnh vực, loại lĩnh vực, xác nhận) với một giao diện đồ họa (MVC xem).
  2. Khi cần, thời gian chạy sẽ tạo biểu mẫu cho người dùng cuối dựa trên cấu hình quản trị. Tôi giả định rằng tất cả logic này sẽ nằm trong bộ điều khiển - hoặc có lẽ là các phương thức mở rộng, các bộ lọc hành động hoặc một cái gì đó tương tự.
  3. Người dùng cuối điền vào biểu mẫu, lần truy cập gửi, thông tin được ghi lại trong cơ sở dữ liệu.

Tùy chỉnh không cần hỗ trợ kiểm soát lồng nhau, kiểm soát của bên thứ ba và vv, nhưng tôi nghi ngờ một thiết kế rất thanh lịch sẽ cho phép điều đó. Chủ yếu, tôi chỉ cần quản trị viên có thể chỉ định các trường bổ sung dưới dạng hộp văn bản, hộp kiểm, nút radio và combobox. Tôi cũng sẽ cần ứng dụng để phân bổ một không gian cho dữ liệu này được lưu trong db, nhưng tôi tin rằng tôi có phần đó đã tìm ra.

Cảm ơn sự giúp đỡ.

+0

Tôi phản đối việc đóng câu hỏi này. Kiến trúc đằng sau việc tạo các biểu mẫu thời gian chạy * trên một khuôn khổ phía máy chủ cụ thể * là rộng, nhưng nó rõ ràng là câu trả lời như các câu trả lời dưới đây chứng minh. Có phải tất cả các câu hỏi về kiến ​​trúc đều nằm ngoài chủ đề của trang web này đơn giản vì các quyết định về kiến ​​trúc ở mức cao và có ưu và nhược điểm? –

Trả lời

1

Một cách để thực hiện việc này là tạo ModelBinder của riêng bạn, đây sẽ là trọng tâm của các biểu mẫu được tạo của bạn. Modelbinder chịu trách nhiệm xác nhận hợp lệ ModelState và xây dựng lại kiểu đã nhập ViewDataModel (giả sử các chế độ xem của bạn được nhập).

Bộ kết nối mô hình DataAnnotations có thể là một tham chiếu tốt cho việc này mà trình mô phỏng tùy chỉnh này cho phép bạn thực hiện thông qua Attributes trên xác nhận của thuộc tính (và gợi ý khi hiển thị giao diện người dùng). Tuy nhiên đây là tất cả thời gian biên dịch được xác định nhưng sẽ là một tham chiếu tuyệt vời để bắt đầu viết một mô hình tùy chỉnh.

Trong trường hợp của bạn, trình kết nối mô hình của bạn sẽ nhận được xác thực cho trường trong thời gian chạy từ tệp/chuỗi xml.

Nếu bạn có một tuyến đường như:

routes.MapRoute(null, "Forms/{formName}/", new { action = "Index", controller = "Forms", formName = ""}), 

Sau đó, bạn có thể xác định vị trí các hình thức xml đúng trong FormsController.Index(string formName) và vượt qua nó để xem.

FormsModel nên giữ tất cả các phương pháp có thể để nhận dữ liệu Tôi không thấy bất kỳ cách nào khác xung quanh việc này. Xml có thể ánh xạ tới tên hàm (thậm chí có thể là đối số) mà bạn có thể gọi bằng cách sử dụng sự phản chiếu trên FormsModel để điền vào ViewData hoặc nhập ViewDataModel với dữ liệu.

Chế độ xem cho Chỉ mục biểu mẫu có thể tạo biểu mẫu từ xml đó thông qua số HtmlHelper Tiện ích mở rộng có số XmlDocument.

Sau đó, khi bạn (hoặc asp.net mvc) liên kết biểu mẫu với ViewData trình liên kết mô hình tùy chỉnh của bạn được gọi, nó có thể kiểm tra giá trị bộ điều khiển hiện tại để tìm biểu mẫu và tìm kiếm xml tương ứng chứa tất cả các quy tắc xác thực . Sau đó, ModelBinder chịu trách nhiệm điền ModelState với bất kỳ lỗi nào được xác định trong thời gian chạy.

Đó là một nhiệm vụ khó khăn nhưng khi kéo ra thành công cũng có giá trị nó trong quan điểm của tôi :)

Cập nhật một lựa chọn tốt hơn để mô hình hóa dữ liệu sẽ là một CSDL rất lỏng lẻo như David Liddle gợi ý. Tôi vẫn gặp rắc rối khi lưu nó dưới dạng xml (hoặc định dạng được tuần tự hóa khác) và sử dụng để tạo khung nhìn và giữ các quy tắc xác thực cho một tuỳ chỉnh ModelBinder để bạn có nhiều quyền kiểm soát hơn đối với bố cục và xác thực của từng trường.

3

Một tùy chọn khác là có lược đồ cơ sở dữ liệu rất lỏng lẻo.

 
//this will contain all the fields and types that the admin user sets 
**ApplicationFields** 
FieldName 
FieldType 
... 

//these are all the values that have some mapping to a ParentObjectID 
**FormValues** 
ParentObjectID 
FieldName 
FieldValue 

Khi bạn gửi thời gian chạy của bạn tạo Xem (từ ApplicationFields) thì chỉ cần lặp qua FormCollection của bạn và thử đặt nó trên ParentObject bạn cần cập nhật.

 
public ActionResult MyForm(FormCollection form) 
{ 
    //this is the main object that contains all the fields 
    var parentObject; 

    foreach (string key in form) 
    { 
     parentObject.SetValue(key, form[key]); 
    } 
    ... 

Sau đó parentObject của bạn có thể là một cái gì đó như thế này ... Câu trả lời

 
public partial class ParentObject 
{ 
    IList _FormValues; 

    public void SetValue(string key, string value) 
    { 
     //try and find if this value already exists 
     FormValue v = _FormValues.SingleOrDefault(k => k.Key == key); 

     //if it does just set it 
     if (v != null) 
     { 
      v.Value = value; 
      return; 
     } 

     //else this might be a new form field added and therefore create a new value 
     v = new FormValue 
     { 
      ParentObjectID = this.ID, 
      Key = key, 
      Value = value 
     }; 

     _FormValues.Add(v); 
    } 
} 
12

Tôi có nhu cầu tương tự trong một dự án gần đây. Tôi đã tạo một thư viện lớp cho việc này. Tôi vừa phát hành một phiên bản mới của thư viện.

Có lẽ nó có thể giúp bạn: ASP.NET MVC Dynamic Forms

+0

Chỉ cần nhìn vào mã nguồn cho giải pháp khá tốt đẹp này, bạn có dự định phát hành mã nguồn cho phiên bản 2.0 không? Nếu không, bạn có danh sách các khác biệt giữa hai phiên bản không? – Tr1stan

+0

Nguồn được phát hành. Toàn bộ dự án là mã nguồn mở @ codeplex. –

+0

Ồ OK, tôi đã nhầm lẫn vì ngày phát hành của v2 là năm 2012, nhưng mã nguồn đã không thay đổi kể từ năm 2010, đó là khi bạn phát hành v1, đó là tất cả. Cảm ơn. – Tr1stan

0

Tôi không thể nhìn thấy lợi thế rất lớn của việc tạo XForms hoặc bất kỳ "trừu tượng" khác so với HTML so sánh với thế hệ thẳng về phía trước của HTML với "Web Forms 2.0" danh sách điều khiển cho kiểu như List<Tuple<Meta, Value>>. Lưu ý: về phía máy chủ bạn trong mọi trường hợp sẽ có nghĩa vụ phân tích các kết quả theo cách thủ công để phù hợp với cấu trúc của bạn.

Tìm kiếm "trừu tượng lớp tiếp theo" là tốt để phát triển nhanh chóng, nhưng hãy xem "tạo mã" (thời gian chạy hoặc thời gian xây dựng) có riêng của nó. Thông thường, mã tạo ra của "tầng dưới" là giải pháp tốt hơn so với việc tạo ra "lớp trừu tượng cao hơn".

Vì vậy, chỉ cần đi và sử dụng mã tạo điều khiển Web 2 trong vòng lặp @Foreach.

4

Bạn có thể thực hiện việc này rất dễ dàng bằng cách sử dụng thư viện FormFactory của mình.

Theo mặc định, nó phản ánh mô hình khung để tạo ra một mảng PropertyVm[], nhưng bạn cũng có thể tạo thuộc tính theo chương trình, vì vậy bạn có thể tải cài đặt từ cơ sở dữ liệu rồi tạo PropertyVm.

Đây là đoạn trích từ tập lệnh Linqpad.

`` `

//import-package FormFactory 
//import-package FormFactory.RazorGenerator 


void Main() 
{ 
    var properties = new[]{ 
     new PropertyVm(typeof(string), "username"){ 
      DisplayName = "Username", 
      NotOptional = true, 
     }, 
     new PropertyVm(typeof(string), "password"){ 
      DisplayName = "Password", 
      NotOptional = true, 
      GetCustomAttributes =() => new object[]{ new DataTypeAttribute(DataType.Password) } 
     } 
    }; 
    var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper()); 

    Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field. 
} 

` ``

Theres một demo site với ví dụ về các tính năng khác nhau mà bạn có thể thiết lập (ví dụbộ sưu tập lồng nhau, tự động hoàn thành, trình đặt ngày, v.v.)

Các vấn đề liên quan