2011-12-14 13 views
9

Ok, Diciamo che ho un URL in questo modo, che viene mappato tramite HTTP verbo GET alla azione di controllo che ho qui di seguito:Come associare parametri URL per modellare proprietà con nomi diversi

GET /foo/bar?sort=asc&r=true 

Come posso legare questo al mio modello di Bar sulla mia azione di controllo che ho qui di seguito:

class Bar { 
    string SortOrder { get; set; } 
    bool Random { get; set; } 
} 

public ActionResult FooBar(Bar bar) { 
    // Do something with bar 
    return null; 
} 

si noti che i nomi di proprietà non saranno e non può necessariamente corrispondere ai nomi dei parametri URL. Inoltre, questi sono parametri url OPTIONAL.

+1

Vorrei solo aggiungere una classe con i nomi di proprietà corrispondenti, ma sono interessato a vedere se è possibile configurare il modello di associazione per associare a nomi di proprietà arbitrarie. Forse c'è qualche attributo da usare ... – dotjoe

+1

Non riesco a capirlo, perché le proprietà non possono corrispondere ai parametri url? – gdoron

+1

@gdoron, POSSONO, preferirei fortemente che NON corrispondano ... Preferirei avere un attributo sulla proprietà per renderlo esplicito su quale parametro URL è associato a quale proprietà. – Polaris878

risposta

7

Il raccoglitore modello corrisponde ai parametri che ottiene dalla vista al modello che si ha nell'azione dai nomi , quindi se non corrispondono l'associazione non funzionerà.

opzioni che hanno ottenuto:

  1. adattare gli ingressi nomi alle proprietà modello nomi ... ma hai detto che non si può fare questo, (per qualche motivo sconosciuto).
  2. Scrivi Raccoglitore modello personalizzato. *
  3. Utilizzare l'attributo Bind con prefisso, anche se imporrà comunque di avere nomi di input vicino ai nomi delle proprietà del modello.

quindi in pratica, non è possibile fare esattamente ciò che si desidera.


Aggiornamento:

Hai scritto in un commento che le proprietà possono abbinare i nomi dei parametri, così invece di scrittura attributi personalizzati che forse sarà riuscito a fare il legame, basta scrivere un ViewModel (Il VM fromMVC ...) per regolare i nomi dei parametri dell'url.

scrittura legante modello personalizzato non è raccomandato dal team MVC:

In generale, si consiglia la gente non scrivere leganti modello personalizzato perché sono difficili da ottenere e raramente sono necessari
da here

9

non è supportato, fuori dalla scatola, ma si potrebbe fare questo:

class BarQuery : Bar { 

    public string sort { get { return SortOrder; } set { SortOrder = value; } } 
    public bool r { get { return Random; } set { Random = value; } } 
} 

public ActionResult FooBar(BarQuery bar) { 
    // Do something with bar 
} 

È possibile implementare una personalizzazione IModelBinder, ma è molto più semplice eseguire la mappatura manuale.


Se è possibile cambiare la classe Bar è possibile utilizzare questo attributo:

class FromQueryAttribute : CustomModelBinderAttribute, IModelBinder { 

    public string Name { get; set; } 

    public FromQueryAttribute() { } 

    public FromQueryAttribute(string name) { 
     this.Name = name; 
    } 

    public override IModelBinder GetModelBinder() { 
     return this; 
    } 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
     return controllerContext.HttpContext.QueryString[this.Name ?? bindingContext.ModelName]; 
    } 
} 

class Bar { 

    [FromQuery("sort")] 
    string SortOrder { get; set; } 

    [FromQuery("r")] 
    bool Random { get; set; } 
} 

public ActionResult FooBar(Bar bar) { 
    // Do something with bar 
    return null; 
} 
+0

Mi è piaciuto l'attributo Query, ma non è la procedura migliore (come probabilmente sei d'accordo) – gdoron

+0

@ gdoron Non so cosa intendi. –

+2

Voglio dire, anche se è un bel "trucco" ma il team di MVC suggerisce davvero di evitare di scrivere Model Binder personalizzato. "In generale, raccomandiamo che la gente non scriva legami modello personalizzati perché sono difficili da ottenere e raramente sono necessari" – gdoron

1

Si potrebbe implementare IModelBinder per mappare i parametri in arrivo per l'oggetto della vostra scelta a condizione che il parametro di ingresso sono definiti i nomi. Altrimenti dovresti fare affidamento sull'ordine dei parametri e/o sul tipo per dedurre l'associazione corretta che sembra essere una scelta molto scarsa.

3

Ho avuto lo stesso problema molto tempo fa e utilizzato questa soluzione pila da Andras Zoltan: Asp.Net MVC 2 - Bind a model's property to a different named value

ho impostato l'attributo ModelBinder sulla mia classe e le BindAlias ​​sulla proprietà:

[ModelBinder(typeof(DefaultModelBinderEx))] 
    public class MyModel 
    { 
     [Required] 
     [BindAlias("new")] 
     public int? Amount { get; set; } 

Se non è possibile modificare o non accedere al file del modello per impostare gli attributi, è ancora possibile creare un modello personalizzato legatore, OPPURE, creare un oggetto specifico di quello che si associerà al modello (AutoMapper è utile)

1

Là non è gratuito MVC.Net Mo funzionalità di delocalizzazione che ti dà quello che vuoi fuori dalla scatola. Quando ho bisogno di fare qualcosa del genere, mi fa davvero pensare alla mia modellazione che mi fa quasi sempre creare un ViewModel per il mio view binding e un EntityModel per il mio storage di repository.

Mi piace usare AutoMapper per convertire tra questi diversi tipi. La parte migliore dell'uso di AutoMapper è che ti allontana dal dover scrivere la logica di mappatura da te stesso ripetutamente per ogni Azione nel tuo controller. Basta impostarlo una volta con AutoMapper nelle sezioni di inizializzazione e solo eseguire qualcosa di simile in futuro.

Mapper.Map<Bar>(barViewModel); 
Problemi correlati