2010-12-10 5 views
9

मेरे एएसपी.नेट एमवीसी 2 वेब एप्लिकेशन में, मैं उपयोगकर्ताओं को हमारे मूल इनपुट फॉर्म को बढ़ाने के लिए विभिन्न डेटा प्रकारों के कस्टम इनपुट फ़ील्ड बनाने की अनुमति देता हूं। मुश्किल होने पर, कस्टम फ़ील्ड के संग्रह से इनपुट फॉर्म का निर्माण करना काफी आगे है।एएसपी.नेट एमवीसी - विभिन्न डेटा प्रकारों के कस्टम फ़ील्ड के साथ एक फॉर्म पोस्ट करना

हालांकि, अब मैं उस बिंदु पर हूं जहां मैं इस फॉर्म को पोस्ट करना चाहता हूं और मुझे यकीन नहीं है कि इसे संभालने का सबसे अच्छा तरीका क्या होगा। आम तौर पर, हम दृढ़ता से टाइप किए गए इनपुट मॉडल का उपयोग करेंगे जो फ़ॉर्म पर उपलब्ध विभिन्न सांख्यिकीय-टाइप किए गए इनपुट से बंधे होते हैं। हालांकि, मुझे विभिन्न डेटा प्रकारों का प्रतिनिधित्व करने वाले इनपुट फ़ील्ड की एक चर संख्या के साथ ऐसा करने के लिए नुकसान हुआ है।

  • मेरे दिनांक फ़ील्ड: [दिनांक समय इनपुट नियंत्रण]
  • मेरे पाठ क्षेत्र: [पाठ इनपुट क्षेत्र]
  • मेरे फ़ाइल

    एक प्रतिनिधि इनपुट फार्म की तरह कुछ लग सकता है फ़ील्ड: [फ़ाइल अपलोड नियंत्रण]

  • मेरा नंबर फ़ील्ड: [संख्यात्मक इनपुट नियंत्रण]
  • मेरे पाठ क्षेत्र 2: [पाठ इनपुट क्षेत्र]
  • आदि ...

विचार के बारे में मैं सोचा है कर रहे हैं:

  • फ़ाइल आदानों के लिए छोड़कर (तारों के रूप में सब कुछ भेजा जा रहा है , जिसे विशेष रूप से संभालना होगा)।
  • "ऑब्जेक्ट" संपत्ति वाले मॉडल का उपयोग करके और उस से जुड़ने का प्रयास (यदि यह भी संभव है)।
  • मेरे नियंत्रक को सही ढंग से एन्कोड किए गए डेटा के साथ एक जेसन अनुरोध भेज रहा है और उसे पार्स करने का प्रयास कर रहा है।
  • मेरे नियंत्रक पोस्ट एक्शन में फॉर्म संग्रह को मैन्युअल रूप से प्रोसेस करना - निश्चित रूप से एक विकल्प है, लेकिन मुझे इससे बचना अच्छा लगेगा।

क्या किसी ने इससे पहले इस तरह कोई समस्या हल की है? यदि हां, तो आपने इसे कैसे हल किया?

अद्यतन:

मेरे "आधार" फ़ॉर्म अन्य इनपुट क्षेत्र पर सभी को एक साथ नियंत्रित किया जाता है, तो एक समाधान इस के लिए inheritence जादू की किसी भी प्रकार के लिए खाते की जरूरत नहीं है। मैं सिर्फ इस इंटरफेस पर कस्टम फ़ील्ड को संभालने में दिलचस्पी रखता हूं, न कि मेरे "बेस" वाले।

अद्यतन 2:

एआरएम और smartcaveman लिए धन्यवाद; आप दोनों ने यह कैसे किया जा सकता है इसके लिए अच्छा मार्गदर्शन प्रदान किया। लागू होने के बाद मैं अपने अंतिम समाधान के साथ इस प्रश्न को अपडेट कर दूंगा।

उत्तर

1

इस प्रकार मैं इस मुद्दे से संपर्क करना शुरू कर दूंगा। एक कस्टम मॉडल बाइंडर FormKey प्रॉपर्टी के आधार पर निर्माण करना बहुत आसान होगा (जिसे इंडेक्स और/या लेबल द्वारा निर्धारित किया जा सकता है)।

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; } 
} 

इसके अलावा, मैंने देखा कि नीचे दी गई टिप्पणियों में से एक फ़िल्टर फ़िल्टर मॉडल था। ऑटोमैपर से जिमी बोगर्ड ने इस विधि के बारे में http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/03/17/a-better-model-binder.aspx पर वास्तव में सहायक पोस्ट किया, और बाद में http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/11/19/a-better-model-binder-addendum.aspx में संशोधित किया। कस्टम मॉडल बाइंडर्स बनाने में मेरे लिए यह बहुत उपयोगी रहा है।

अद्यतन

मुझे एहसास हुआ कि मैं सवाल गलत व्याख्या की, और कहा कि वह विशेष रूप से कैसे "इनपुट फ़ील्ड विभिन्न डेटा प्रकार का प्रतिनिधित्व के परिवर्तनशील साथ" फ़ॉर्म की पोस्टिंग को संभालने के लिए पूछ रहा था। मुझे लगता है कि ऐसा करने का सबसे अच्छा तरीका ऊपर की तरह एक संरचना का उपयोग करना है, लेकिन Composite Pattern का लाभ उठाना है। असल में, आपको IFormComponent जैसे इंटरफ़ेस बनाने की आवश्यकता होगी और प्रत्येक डेटाटाइप के लिए इसे कार्यान्वित किया जाएगा जिसका प्रतिनिधित्व किया जाएगा। मैंने लिखा और एक उदाहरण इंटरफेस टिप्पणी की व्याख्या कर यह कैसे पूरा किया जाएगा मदद करने के लिए:

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); 
} 

मैं यह सोचते हैं कि कस्टम रूपों जो एक रूप पैरामीटर के रूप में निहित किया जा सकता है आईडी के कुछ प्रकार के माध्यम से पहुँचा जा सकता है। उस धारणा के साथ, मॉडल बाइंडर और प्रदाता इस तरह कुछ देख सकता है।

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."); 
    } 
} 

जाहिर है, सब कोड यहाँ सिर्फ बिंदु पार पाने के लिए है, और पूरी की और वास्तविक उपयोग के लिए साफ करने की आवश्यकता होगी। इसके अलावा, अगर यह पूरा हो जाता है तो यह केवल आईफॉर्म इंटरफेस के कार्यान्वयन से जुड़ा होगा, न कि दृढ़ता से टाइप की गई व्यावसायिक वस्तु।(यह एक शब्दकोश में बदलने के लिए एक बड़ा कदम नहीं होगा और कैसल डिक्शनरी एडाप्टर का उपयोग करके दृढ़ता से टाइप की गई प्रॉक्सी का निर्माण करेगा, लेकिन चूंकि आपके उपयोगकर्ता गतिशील रूप से साइट पर फॉर्म बना रहे हैं, इसलिए शायद आपके समाधान में कोई दृढ़ता से टाइप मॉडल नहीं है और यह अप्रासंगिक है)। उम्मीद है कि यह और मदद करता है।

+0

टिप्पणियों के लिए धन्यवाद, बहुत अंतर्दृष्टि। – DanP

1

मैंने जो किया है उस पर एक नज़र डालें: MVC2 Action to handle multiple models और देखें कि क्या आपको सही रास्ते पर मिल सकता है।

यदि आप अपनी क्रिया में अपने पैरामीटर में से एक के रूप में फॉर्मकोलेक्शन का उपयोग करते हैं, तो आप उस फॉर्म संग्रह के माध्यम से यहां या वहां डेटा के बिट्स की तलाश कर सकते हैं ताकि डेटा को सहेजने के लिए उन मानों को बाध्य किया जा सके। काम करने के लिए आपको सबसे अधिक रणनीति और कमांड पैटर्न का लाभ उठाने की आवश्यकता होगी।

शुभकामनाएं, अनुवर्ती प्रश्न पूछने के लिए स्वतंत्र महसूस करें।

संपादित करें:

आपका तरीका है जिसके करता है काम कुछ इस तरह दिखना चाहिए:

private/public void SaveCustomFields(var formId, FormCollection collection) //var as I don't know what type you are using to Id the form. 
{ 
    var binders = this.binders.select(b => b.CanHandle(collection)); //I used IOC to get my list of IBinder objects 
    // Method 1:  
    binders.ForEach(b => b.Save(formId, collection)); //This is the execution implementation. 
    // Method 2: 
    var commands = binders.Select(b => b.Command(formId, collection)); 
    commands.ForEach(c => c.Execute());  
} 

public DateBinder : IBinder //Example binder 
{ 
    public bool CanHandle(FormCollection collection) 
    { 
     return (null != collection["MyDateField"]); //Whatever the name of this field is. 
    } 

    //Method 1 
    public void Save(var formId, FormCollection collection) 
    { 
     var value = DateTime.Parse(collection["MyDateField"]); 
     this.someLogic.Save(formId, value); //Save the value with the formId, or however you wish to save it. 
    } 
    //Method 2 
    public Command Command(var formId, FormCollection collection) 
    { 
     //I haven't done command pattern before so I'm not sure exactly what to do here. 
     //Sorry that I can't help further than that. 
    } 
} 
+0

इस जानकारी के लिए धन्यवाद, आपका दृष्टिकोण बहुत दिलचस्प लगता है। सोमवार को आपके पास शायद कुछ फॉलो-अप होंगे। – DanP

+0

एआरएम; यदि आप अधिक प्रासंगिक कार्यान्वयन विवरण पोस्ट/साझा करना चाहते हैं तो मुझे आपको बक्षीस देने में खुशी होगी। – DanP

+0

इसका सबसे महत्वपूर्ण हिस्सा IUIWrapper.CanHandle है (आप एकाधिक रैपर प्राप्त करने के लिए सिंगलऑर्डडिल्ट के बजाय एक चयन का उपयोग करना चाहेंगे)। CanHandle विधि एक फॉर्मकोलेक्शन लेता है और एक संग्रह तत्व (var X = संग्रह ["SomeValue"] को पकड़ने का प्रयास करता है; एक्स एक्स = = null;) जो निर्धारित करेगा कि विशेष फ़ॉर्म संग्रह तत्व मौजूद है या नहीं। एक बार जब आपके रैपर का संग्रह हो जाए, तो प्रत्येक रैपर के पास उस विशेष तत्व को आपके भंडार में सहेजने का आदेश होगा और फिर डेटा को अपने भंडार में संग्रहीत करने के लिए आदेशों के संग्रह के माध्यम से चलाएं। फिर से, अनुवर्ती पूछने के लिए स्वतंत्र महसूस करें। – ARM

0

मुझे लगता है कि होगा सबसे अच्छा विकल्प में से एक कस्टम मॉडल बांधने की मशीन है, जो इसे संभव बनाता है बनाने के लिए है दृश्यों के पीछे कस्टम तर्क और अभी भी बहुत अनुकूलन कोड है।

हो सकता है कि इन लेखों आप मदद कर सकते हैं:

http://www.gregshackles.com/2010/03/templated-helpers-and-custom-model-binders-in-asp-net-mvc-2/

http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx

अधिक विशेष रूप से मैं शायद नियंत्रक तर्क के रूप में एक कस्टम वर्ग सभी "आधार" के साथ ले जाएगा गुण शामिल थे। कक्षा के लिए उदाहरण के लिए प्रत्येक फ़ील्ड के नाम को एक ऑब्जेक्ट या एक इंटरफ़ेस में जोड़ने वाला एक शब्दकोश शामिल होता है जिसे आप प्रत्येक डेटा-प्रकार के लिए एक बार लागू करते हैं, जिससे बाद में डेटा को संसाधित करना आसान हो जाता है।

/विक्टर