2014-10-28 20 views
10

Utilizzo il binding del modello API Web per analizzare i parametri di query da un URL. Ad esempio, ecco una classe del modello:Modifica del nome del parametro Associazione del modello Web Api

public class QueryParameters 
{ 
    [Required] 
    public string Cap { get; set; } 

    [Required] 
    public string Id { get; set; } 
} 

Questo funziona bene quando chiamo qualcosa come /api/values/5?cap=somecap&id=1.

C'è qualche modo posso cambiare il nome della proprietà nella classe del modello, ma mantenere il nome del parametro di query lo stesso - per esempio:

public class QueryParameters 
{ 
    [Required] 
    public string Capability { get; set; } 

    [Required] 
    public string Id { get; set; } 
} 

ho pensato di aggiungere [Display(Name="cap")] alla proprietà Capability avrebbe funzionato, ma non è così. C'è qualche tipo di annotazione dei dati che dovrei usare?

Il controller sarebbe avere un metodo che si presentava così:

public IHttpActionResult GetValue([FromUri]QueryParameters param)  
{ 
    // Do Something with param.Cap and param.id 
} 

risposta

7

Web API utilizza un meccanismo diverso bit per modello articolate di ASP.NET MVC. Utilizza i formattatori per i dati trasmessi nel corpo e i raccoglitori del modello per i dati trasmessi nella stringa di query (come nel tuo caso). I formattatori rispettano gli attributi di metadati aggiuntivi mentre i raccoglitori di modelli non lo fanno.

Quindi, se hai superato il modello in corpo del messaggio piuttosto che stringa di query, è possibile annotare i vostri dati come segue e che avrebbe funzionato:

public class QueryParameters 
{ 
    [DataMember(Name="Cap")] 
    public string Capability { get; set; } 

    public string Id { get; set; } 
} 

Probabilmente saperlo già. Per farlo funzionare con i parametri della stringa di query e quindi il raccoglitore modello, è necessario utilizzare il proprio raccoglitore modello personalizzato che verrebbe effettivamente ispezionato e utilizzato gli attributi DataMember.

Il seguente pezzo di codice farebbe il trucco (anche se è lontano dalla qualità della produzione):

public class MemberModelBinder : IModelBinder 
{ 
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
    { 
     var model = Activator.CreateInstance(bindingContext.ModelType); 
     foreach (var prop in bindingContext.PropertyMetadata) 
     { 
      // Retrieving attribute 
      var attr = bindingContext.ModelType.GetProperty(prop.Key) 
            .GetCustomAttributes(false) 
            .OfType<DataMemberAttribute>() 
            .FirstOrDefault(); 
      // Overwriting name if attribute present 
      var qsParam = (attr != null) ? attr.Name : prop.Key; 
      // Setting value of model property based on query string value 
      var value = bindingContext.ValueProvider.GetValue(qsParam).AttemptedValue; 
      var property = bindingContext.ModelType.GetProperty(prop.Key); 
      property.SetValue(model, value); 
     } 
     bindingContext.Model = model; 
     return true; 
    } 
} 

Sarà inoltre necessario indicare nel metodo di controllo che si desidera utilizzare questo modello legante:

public IHttpActionResult GetValue([ModelBinder(typeof(MemberModelBinder))]QueryParameters param) 
+0

[Commento eliminato] – user2966445

+0

È possibile che un qualsiasi downgoter spieghi cosa c'è di sbagliato in questa risposta? –

+0

+1 Funziona per me, anche se ho contrassegnato l'attributo DataMember solo su proprietà con nomi di parametri diversi dal nome della proprietà. Pertanto, avevo bisogno di separare la chiamata del metodo GetValue e il riferimento AttemptedValue, e posto un controllo nullo sulla proprietà, altrimenti rischierai una NullReferenceException. Probabilmente non è una cattiva idea a prescindere :) – si618

1

ho trascorso diverse ore a lavorare su una soluzione robusta per lo stesso problema, quando una battuta farà il trucco bene:

myModel.Capability = HttpContext.Current.Request["cap"]; 
+0

HttpContext.Current.Request ["chiave"] restituirà sempre una stringa. – pholly

13

È possibile utilizzare la proprietà Name dell'attributo di associazione FromUri per utilizzare i parametri della stringa di query con nomi diversi per gli argomenti del metodo.

Se si passa parametri semplici piuttosto che il vostro tipo QueryParameters, è possibile associare i valori in questo modo:

/api/values/5?cap=somecap&id=1 

public IHttpActionResult GetValue([FromUri(Name = "cap")] string capabilities, int id)  
{ 
} 
0

Ho appena incontrato questo e ha utilizzato un getter nella mia classe parametro per restituire la proprietà vincolata.

Quindi nel tuo esempio:

public class QueryParameters 
{ 
    public string cap {get; set;} 
    public string Capability 
    { 
     get { return cap; } 
    } 

    public string Id { get; set; } 
} 

Ora nel tuo controller è possibile fare riferimento alla proprietà Capability.

public IHttpActionResult GetValue([FromUri]QueryParameters param)  
{ 
    // Do Something with param.Capability, 
    // except assign it a new value because it's only a getter 
} 

Naturalmente se si utilizza riflessione sull'oggetto param o serializzare la proprietà cap sarà incluso. Non sono sicuro del motivo per cui qualcuno dovrebbe farlo con i parametri di query.

+0

e se il nome del parametro fosse '$ cap' non 'cap'? – Ali

Problemi correlati