2009-07-24 11 views
12

È possibile? Ecco quello che sto cercando:Dynamic typed ViewPage

public ActionResult Index() 
    { 
     dynamic p = new { Name = "Test", Phone = "111-2222" }; 
     return View(p); 
    } 

E poi la mia vista eredita da System.Web.Mvc.ViewPage<dynamic> e cerca di stampare Model.Name.

che sto ottenendo un errore: '<> f__AnonymousType1.Name' è inaccessibile a causa del livello di protezione

Quindi, fondamentalmente, è quello che sto cercando di fare proprio possibile? Perché o perché no?

Aggiornamento: ecco la mia vista

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %> 

<asp:Content ...> 
    <%=Model.Name%> 
    <%=Model.Phone%> 
</asp:Content> 

The View costruttore viene incorporata nel quadro.

+1

Puoi pubblicare altro codice? Mi piacerebbe soprattutto vedere il costruttore su View – Randolpho

+1

Controllare il mio ultimo aggiornamento con un collegamento al post del blog di Phil Haack. – CoderDennis

risposta

7

I tipi anonimi non possono essere restituiti con un metodo; sono validi solo nell'ambito del metodo in cui sono definiti.

È necessario utilizzare una classe del modello precedentemente definita e passarla alla vista. Non c'è niente di sbagliato nel passare una classe Model che non ha alcun campo definito.

Aggiornamento:

penso di essere stato sbagliato prima. Questo dovrebbe funzionare. Forse il problema è all'interno della vista. Puoi pubblicare più codice? Soprattutto la vista e il suo costruttore.

Aggiornamento Seconda:

Ok, mi sbagliavo circa il superamento di un tipo anonimo a un altro metodo per l'uso come una variabile dinamica - che può essere fatto.

Ma avevo anche torto nella mia convinzione che quello che stai cercando di fare funzionerebbe. Sfortunatamente per te, non lo farà. Il problema è che stai usando ViewPage<TModel>, che usa un ViewDataDictionary<TModel> internamente. Poiché richiedono tipi forti, non sarà possibile utilizzare oggetti dinamici con essi. La struttura interna non usa solo la dinamica internamente e specifica la dinamica quando il tipo fallisce.

Quello che sarebbe necessario è una classe DynamicViewPage e la classe DynamicViewDataDictionary corrispondente che accetta object e la memorizza internamente come una dinamica. Quindi potresti usare un tipo anonimo e passarlo alle tue Views.

Detto questo, non si guadagna nulla. Sarai in grado di specificare le tue Visualizzazioni come hai fatto tu (ad esempio <%=Model.Name%>), ma non trarrai vantaggio da una digitazione forte. Non ci sarebbe intellettualità e non ci sarebbe alcun tipo di sicurezza. Faresti altrettanto bene ad usare il non codificato ViewDataDictionary come suggerisce @Dennis Palmer.

Questo è stato un interessante esperimento di pensiero (e, purtroppo per me, assorbente), ma penso, in definitiva, che non accadrà. Dichiarare un tipo pubblico e passarlo alle tue Views o usare il dizionario non tipizzato.

+1

Ma potevo accedere ai membri dell'oggetto tramite la riflessione, motivo per cui ho pensato che la digitazione dinamica potesse funzionare. –

+1

hmm ...e il tuo errore suggerisce che si verifica all'interno della tua vista, il che significa che il passaggio del tipo anonimo alla vista funziona, ma che il livello di protezione predefinito di Name è protetto o privato. E non puoi specificare il livello di protezione di un tipo anonimo quando lo dichiari. – Randolpho

+0

Ok, ho pubblicato un aggiornamento. –

7

Quale vantaggio speravi di ottenere utilizzando il tipo dinamico qui?

L'utilizzo del dizionario ViewData è un modo molto semplice di aggiungere oggetti/elementi arbitrari all'output della vista.

Non è necessario il riflesso per ottenere i nomi delle proprietà nella vista. Basta usare ViewData.Keys per ottenere la raccolta di nomi.

Modifica: Ho appena imparato un po 'di più sulla dinamica e penso che forse è necessario creare la propria classe oggetto dinamica che eredita da DynamicObject. Avrai voglia di avere un dizionario privato in quella classe e quindi di sovrascrivere TrySetMember e TryGetMember.

Modifica a parte: Penso che un vantaggio di un ViewModel fortemente tipizzato è che è possibile accettarlo come parametro nei metodi di azione POST. Il framework MVC gestirà l'associazione del modello e nel metodo di azione è sufficiente un'istanza della classe ViewModel. Non penso che avrai un vantaggio con una dinamica anche se funzionano.

Modifica risultato: Bene, ho provato a utilizzare una classe derivata da DynamicObject, ma VS2010 si arresta in modo anomalo quando tenta di eseguire il rendering della vista. Non ottengo alcuna eccezione, solo un arresto anomalo e riavvio di Visual Studio. Ecco il codice che ho scoperto che causa l'arresto.

La classe dinamica personalizzato:

public class DynViewModel : DynamicObject 
{ 
    private Dictionary<string, object> ViewDataBag; 
    public DynViewModel() 
    { 
     this.ViewDataBag = new Dictionary<string, object>(); 
    } 
    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     this.ViewDataBag[binder.Name] = value; 
     return true; 
    } 
    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     result = this.ViewDataBag[binder.Name]; 
     return true; 
    } 
} 

Nel controllore:

public ActionResult DynamicView() 
{ 
    dynamic p = new DynamicViewModel.Models.DynViewModel(); 
    p.Name = "Test"; 
    p.Phone = "111-2222"; 

    return View(p); 
} 

mio punto di vista è fondamentalmente lo stesso di quello che è elencato nella questione:

<p>Name: <%=Model.Name %></p> 
<p>Phone: <%=Model.Phone %></p> 

mio Conclusione: Questo potrebbe funzionare, ma nella Beta 1 di VS2010 non posso capire perché il mio codice causa l'arresto anomalo di Visual Studio. Lo proverò di nuovo in VS2010 Beta 2 quando verrà rilasciato perché è un esercizio interessante per imparare le dinamiche. Tuttavia, anche se dovesse funzionare, non vedo alcun vantaggio sull'uso del dizionario ViewData.

Phil Haack in soccorso! Ecco un post sul blog di Phil Haack che potrebbe aiutarti. Sembra che sia quello che stavi cercando. Fun With Method Missing and C# 4

+0

Beh, non sono ancora sicuro al 100%, sto solo sperimentando un po 'con la 4.0. Immagino che mi piacerebbe vedere la possibilità di utilizzare il pattern ViewModel senza dover scrivere esplicitamente una serie di ViewModels, ma sto anche cercando di comprendere meglio la digitazione dinamica in C#. –

1

L'errore attuale qui (<>f__AnonymousType1.Name' is inaccessible due to its protection level) è il risultato dell'utilizzo di tipi anonimi. I tipi anonimi sono implicitamente internal (almeno in C#), pertanto è possibile accedervi solo normalmente dallo stesso assembly. Poiché la vista è stata compilata in un gruppo separato in fase di runtime, non può accedere al tipo anonimo internal.

La soluzione è passare classi concrete/denominate come modelli alla vista. La vista stessa può ancora usare dynamic se vuoi.

1

Su .NET 4.0 I tipi anonimi possono essere facilmente convertiti in ExpandoObjects e quindi tutti i problemi vengono risolti con il sovraccarico della conversione stessa. Check out here