6

Quando un modello vista viene creata è possibile popolare le opzioni (ad esempio utilizzato in un elenco a discesa) in una proprietà setter del modello di vista. Il problema è che quando quel modello di vista è in seguito passato come parametro (dal quadro!) In un metodo di azione, quei valori di proprietà non è diventato automagicamente ripopolò, quindi se avete bisogno per visualizzare di nuovo la forma a causa di errori di convalida, è necessità di ripopolare nuovamente queste opzioni.Costruttore iniezione di un'istanza di Vista modello utilizzato come metodo di azione parametro

Una soluzione potenziale, che sto chiedendo specificamente in questa domanda, è come rendere il framework MVC istanziare il modello di vista con l'iniezione del costruttore, che fornirebbe al costruttore del modello di vista un'implementazione di una sorta di oggetto di accesso ai dati (ad esempio un repository) che può essere utilizzato per recuperare le opzioni quando vengono richieste dalla vista (ad esempio nel metodo helper "DropDownListFor")?

Penso che la soluzione potrebbe avere qualcosa a che fare con le implementazioni di IModelBinderProvider o IModelBinder ma dopo aver sperimentato queste cose da frammenti di codice di esempio qua e là sulla rete, sto ancora cercando un esempio completamente funzionante, con eseguibile scaricabile codice senza alcun pezzo mancante di come mettere insieme tutte le cose.

Se siete alla ricerca di qualche discussione alternativa su come compilare un elenco di selezione, ad esempio, con "Dependecy Lookup" invece di "Dependecy iniezione" si consiglia di controllare la seguente discussione: Il modo migliore per popolare SelectList per ViewModel su GET/POST Best way to populate SelectList for ViewModel on GET/POST

Qualche giorno fa ho scritto il seguente follow-up- domanda in che discussione riguardo il "Injection Dependecy" ora sto cercando in questa discussione: https://stackoverflow.com/a/8674525/310457 (che fornisce un esempio di codice per il problema che sto cercando una soluzione di)

Ma invece di sperare che qualcuno trova quel thread vecchio con un titolo meno specifico, ho creato questa nuova domanda con un argomento più specifico su ciò che sto cercando r. E fornirò anche un collegamento da quel thread in questa nuova domanda per chiunque desideri seguire questa specifica soluzione che sto cercando.

risposta

5

Sto assumendo che si desidera avere i vostri ViewModels iniettato automaticamente con qualcosa attraverso la loro Constructor - ad esempio una sorta di oggetto di configurazione che la vista utilizzerà per determinare cosa mostrare. Suppongo anche che questo approccio stia causando un errore "Nessun costruttore senza parametri definito per questo oggetto" quando MVC tenta di creare e associare automaticamente un'istanza del modello, dagli argomenti della propria Azione controller. Supponiamo inoltre di utilizzare un framework DI per iniettare automaticamente l'oggetto SiteConfig nei nostri controller in fase di runtime.

Ciò significa che l'unico problema che dobbiamo risolvere è come ottenere l'oggetto iniettato dalla nostra Controller nella ViewModels sua azione, quando essi sono tenuti automaticamente.

Quindi definiamo un modello di base da cui gli altri possano ereditare.

BaseViewModel

public class BaseViewModel 
{ 
    public ISiteConfig SiteConfig { get; set; } 

    public BaseViewModel(ISiteConfig siteConfig) 
    { 
     this.SiteConfig = siteConfig; 
    } 
} 

E ora creiamo un modello che eredita da essa.

IndexViewModel

public class IndexViewModel : BaseViewModel 
{ 
    public string SomeIndexProperty { get; set; } 

    public IndexViewModel (ISiteConfig siteConfig) : base(siteConfig) {} 
} 

E ora definiamo un controller di base che i nostri controllori erediteranno da.

BaseController

public abstract class BaseController : Controller 
{ 
    protected BaseController(ISiteConfig siteConfig) 
    { 
     _siteConfig = siteConfig; 
    } 

    private readonly ISiteConfig _siteConfig; 

    public ISiteConfig SiteConfig 
    { 
     get 
     { 
      return _siteConfig; 
     } 
    } 
} 

Ora definiamo il nostro controller vero e proprio.

HomeController

public HomeController: BaseController 
{ 
    public HomeController(ISiteConfig siteConfig): base(siteConfig) {} 
} 

Supponendo che stiamo usando Ninject per DI, Ninject viene configurato per creare automaticamente il controller e passare un ISiteConfig oggetto concreto nel suo costruttore in fase di esecuzione.

Ora aggiungiamo la nostra azione al controller.

Indice azione

public ActionResult Index(IndexViewModel model) 
{ 
    return View(model); 
} 

E così questo è il punto in cui senza fare niente altro, MVC esploderà con un errore "senza parametri Costruttore" se si tenta di chiamare l'azione Index, perché MVC puo' trovare un costruttore ViewModel che non accetta argomenti.

E così, la risposta. Abbiamo bisogno di sovrascrivere il ModelBinder predefinito.

BaseViewModelBinder

public class BaseViewModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     if (modelType == typeof(BaseViewModel) || modelType.IsSubclassOf(typeof(BaseViewModel))) 
     { 
      var baseControl = controllerContext.Controller as BaseController; 
      if (baseControl == null) 
      { 
       throw new Exception("The Controller must derive from BaseController"); 
      } 

      var instance = Activator.CreateInstance(modelType, baseControl.SiteConfig); 
      bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, modelType); 
      return instance; 
     } 
     else 
     { 
      return base.CreateModel(controllerContext, bindingContext, modelType); 
     } 
    } 
} 

e abbiamo bisogno di impostare questo come il legante modello predefinito in global.asax.cs:

protected void Application_Start() 
{ 
    ... 
    ModelBinders.Binders.DefaultBinder = new BaseViewModelBinder(); 
} 

Questo è tutto. Come puoi vedere, quando visualizzi l'azione di indicizzazione ora, MVC utilizzerà il nostro modello personalizzato. Si renderà conto che IndexViewModel deriva da BaseViewModel e quindi tenterà di far ruotare un'istanza di IndexViewModel utilizzando ISiteConfig che può trovare nel controller di Action (poiché il controller deriva da BaseController).

+0

Non capisco esattamente cosa sia ISiteConfig. Devo implementarlo? –

+0

ISiteConfig è l'interfaccia per l'oggetto SiteConfig che si desidera iniettare automaticamente nella vista. ISiteConfig e SiteConfig si riferiscono a un oggetto di configurazione creato da te, è qualsiasi cosa tu voglia fornire alla tua vista, ed è solo per esempio. –

Problemi correlati