2009-09-09 8 views
6

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

// View Model 
public class AccountViewModel { 
    public string Email { get; set; } 
    public IProfile Profile { get; set; } 
} 

// Interface 
public interface IProfile { 
    // Empty 
} 

// Actual profile instance used 
public class StandardProfile : IProfile { 
    public string FavoriteFood { get; set; } 
    public string FavoriteMusic { get; set; } 
} 

// Controller action 
public ActionResult AddAccount(AccountViewModel viewModel) { 
    // viewModel is populated already 
    UpdateModel(viewModel.Profile, "Profile"); // This isn't working. 
} 

// Form 
<form ... > 
    <input name='Email' /> 
    <input name='Profile.FavoriteFood' /> 
    <input name='Profile.FavoriteMusic' /> 
    <button type='submit'></button> 
</form> 

भी ध्यान रखें कि मैं एक कस्टम मॉडल बांधने की मशीन है कि DefaultModelBinder से विरासत इस्तेमाल किया जा रहा है कि ओवरराइड CreateModel विधि में StandardProfile का एक उदाहरण के साथ IProfile भरता है।

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

धन्यवाद, ब्रायन

उत्तर

2

मैं ASP.NET MVC कोड (DefaultModelBinder) की जाँच करने के लिए होगा, लेकिन मेरा अनुमान है कि कि इस प्रकार IProfile को दर्शाती है, और नहीं उदाहरण, StandardProfile।

तो ऐसा लगता है कि यह किसी भी आईप्रोफाइल सदस्यों को बांधने का प्रयास कर सकता है, लेकिन यह एक खाली इंटरफ़ेस है, इसलिए यह स्वयं ही किया जाता है।

आप BindingContext को अद्यतन करने और StandardProfile को ModelType बदल रहा है और उसके बाद बुला

bindingContext.ModelType = typeof(StandardProfile); 
IProfile profile = base.BindModel(controllerContext, bindingContext); 

फिर भी, एक खाली इंटरफेस होने की तरह कुछ की कोशिश कर सकते अजीब है ~


संपादित करें: सिर्फ जोड़ना चाहते हैं ऊपर दिया गया कोड सिर्फ छद्म कोड है, आपको यह देखने के लिए कि आप क्या लिखना चाहते हैं, उसे डिफॉल्टमोडेल बाइंडर की जांच करनी होगी।


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

आप कर सकते हैं:

public class ProfileModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
    { 
     bindingContext.ModelType = typeof(StandardProfile); 
     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

AccountView के लिए एक मॉडल बांधने की मशीन बनाने के लिए कोई ज़रूरत नहीं है, कि एक ठीक काम करता है।

public ActionResult AddAccount(AccountViewModel viewModel) { 
    // viewModel is fully populated, including profile, don't call UpdateModel 
} 

आप उपयोग कर सकते हैं: जैसे

ModelBinders.Binders[typeof(IProfile)] = new ProfileModelBinder(); 

आपकी कार्रवाई दिखता है:


# संपादित 3

इसे बाहर परीक्षण किया गया, इसके बाद के संस्करण बांधने की मशीन काम करता है, बस जोड़ने की जरूरत मॉडल बाइंडर सेट करते समय आईओसी (उदाहरण के लिए टाइप कंस्ट्रक्टर इंजेक्शन दिया गया है)।

+0

खाली इंटरफ़ेस मुझे प्रत्येक साइट पर एक ही कोर कोड कोड का पुन: उपयोग करने की अनुमति देता है, जबकि मैं एक आईओसी का उपयोग करके एक अलग प्रोफ़ाइल प्रकार की आपूर्ति करता हूं। मैं इस उद्देश्य के लिए एक इंटरफेस के बजाय बेस क्लास का प्रयास करने में सक्षम हो सकता हूं, लेकिन मुझे यकीन है कि मैं और क्या कर सकता हूं जो मुझे लचीलापन देता है जो मैं चाहता हूं। मैं आपके द्वारा वर्णित मॉडल टाइप में देखूंगा। –

+0

एक खाली बेस क्लास आपको बहुत अच्छा नहीं करेगा। तो CreateModel विधि के लिए अपने कोड में आप कुछ ऐसा कह रहे हैं: IoC.GetInstance () जिसे आपने एक नया मानक प्रोफाइल वापस करने के लिए प्लग किया है? दिलचस्प :)। मैं अभी भी अस्पष्ट हूं कि जब आप आईप्रोफाइल का उपयोग करते हैं तो आपको कितना कोड पुन: उपयोग करना पड़ सकता है, इसे पहले दाएं वर्ग में डालना है, लेकिन हाँ ... मुझे लगता है कि बाइंडिंग संदर्भ में टाइप निर्दिष्ट करना काम करेगा। – anonymous

+0

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

0

नहीं वास्तविक प्रकार निरीक्षण के पीछे इंटरफ़ेस यहाँ पर चर्चा की गई: http://forums.asp.net/t/1348233.aspx

जिसके अनुसार, मैं इस समस्या के चारों ओर एक hackish रास्ता मिल गया। चूंकि मेरे पास पहले से ही इस प्रकार के लिए कस्टम मॉडल बाइंडर था, इसलिए मैं इसके लिए बाध्यकारी करने के लिए कुछ कोड जोड़ सकता था।यहाँ मेरी मॉडल बांधने की मशीन अब कैसा दिखता है:

public class AccountViewModelModelBinder : DefaultModelBinder 
{ 
    private readonly IProfileViewModel profileViewModel; 
    private bool profileBound = false; 

    public AccountViewModelModelBinder(IProfileViewModel profileViewModel) 
    { 
     this.profileViewModel = profileViewModel; 
    } 

    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     // Bind the profile 
     if (profileBound) 
      return; 

     profileBound = true; 

     bindingContext.ModelType = profileViewModel.GetType(); 
     bindingContext.Model = profileViewModel; 
     bindingContext.ModelName = "Profile"; 

     BindModel(controllerContext, bindingContext); 
    } 

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType) 
    { 
     var model = new AccountViewModel(); 
     model.Profile = profileViewModel; 

     return model; 
    } 
} 

असल में, जब मॉडल बांधने की मशीन "किया" है मुख्य AccountViewModel बंधन, मैं तो बाध्यकारी संदर्भ में परिवर्तन (के रूप में EYSTON ने सुझाव दिया) और BindModel एक बार फिर से कहते हैं। यह फिर मेरी प्रोफाइल बांधता है। ध्यान दें कि मैंने प्रोफ़ाइल ViewModel पर GetType को बुलाया (जिसे कन्स्ट्रक्टर में आईओसी कंटेनर द्वारा आपूर्ति की जाती है)। यह भी ध्यान दें कि मैं यह इंगित करने के लिए एक ध्वज शामिल करता हूं कि प्रोफाइल मॉडल पहले ही सीमित है या नहीं। अन्यथा OnModelUpdated कहा जा रहा एक अंतहीन पाश होगा।

मैं यह नहीं कह रहा कि यह सुंदर है, लेकिन यह मेरी आवश्यकताओं के लिए काफी अच्छा काम करता है। मुझे अभी भी अन्य सुझावों के बारे में सुनना अच्छा लगेगा।

+0

संपादित करें # 2/# 3 देखें। – anonymous

संबंधित मुद्दे