2013-01-02 13 views
15

Voglio avere un'API in quanto tale:Posso passare un oggetto basato su interfaccia a un POST di WebApi MVC 4?

public class RelayController : ApiController 
{ 
    // POST api/values 
    public void Post([FromBody]IDataRelayPackage package) 
    { 
     MessageQueue queue = new MessageQueue(".\\private$\\DataRelay"); 
     queue.Send(package); 
     queue.Close(); 
    } 
} 

sto ottenendo un valore nullo per il 'pacchetto' quindi mi chiedo cosa potrebbe andare male. Il mio unico pensiero è che il serializzatore di default JSON non sia in grado di gestirlo, ma non so come risolverlo.

+0

Nell'interesse del tempo, ho deciso di modificare il mio POST WebAPI per accettare una stringa contenente XML. Ho intenzione di tornare su questo più tardi. –

risposta

14

È possibile farlo abbastanza facilmente con un raccoglitore modello personalizzato. Ecco cosa ha funzionato per me. (Utilizzo di Web API 2 e JSON.Net 6)

public class JsonPolyModelBinder : IModelBinder 
{ 
    readonly JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }; 

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
    { 
     var content = actionContext.Request.Content; 
     string json = content.ReadAsStringAsync().Result; 
     var obj = JsonConvert.DeserializeObject(json, bindingContext.ModelType, settings); 
     bindingContext.Model = obj; 
     return true; 
    } 
} 

Il controller API Web si presenta così. (Nota: dovrebbe funzionare anche per le azioni regolari MVC - Ho fatto qualcosa di simile per loro prima pure.)

public class TestController : ApiController 
{ 
    // POST api/test 
    public void Post([ModelBinder(typeof(JsonPolyModelBinder))]ICommand command) 
    { 
     ... 
    } 
} 

Vorrei anche sottolineare che quando si serializza il JSON, si dovrebbe serializzare con il stessa impostazione, e serializzarlo come un'interfaccia per attivare l'Auto kick e includere il suggerimento sul tipo. Qualcosa come questo.

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }; 
    string json = JsonConvert.SerializeObject(command, typeof(ICommand), settings); 
+0

Questo è fantastico e apre le interfacce di JSON service factory sovraccaricate. Grazie! –

+1

Inoltre, JSON.Net può deserializzare i messaggi immutabili (nessun setter pubblico) a condizione che i nomi delle proprietà corrispondano ai parametri del costruttore (senza distinzione tra maiuscole e minuscole). –

+0

Alla fine, ho deciso che era più semplice avere la mia azione Post senza parametri e deserializzare il corpo del post come parte dell'azione. In questo modo posso gestire le eccezioni o qualsiasi altra cosa che voglio fare. –

1

Il serializzatore richiede un tipo che può essere costruito, uno con un costruttore vuoto (Predefinito). Poiché non è possibile creare un'interfaccia, la serializzazione non riesce e si ottiene un valore nullo.

Due opzioni:

  1. Utilizzare una POCO (Plain Old Clr oggetto) con un costruttore di default
  2. Implement your own binder using IActionValueBinder
3

Json.NET (serializzatore JSON predefinito per ASP.NET Web API) in grado di gestire questa situazione. Tutto ciò che devi fare è modificare le impostazioni del serializzatore e impostare TypeNameHandling su All (o Objects). Questo aggiungerà una proprietà "$ type" -json a json, contenente il nome tipo dell'istanza. Dall'altro lato proverà a deserializzare nuovamente questo tipo.

Abbiamo usato questo per noi stessi, prendendo una classe di base astratta come tipo.

+0

Quando si dice "cambia le impostazioni del serializzatore", dove lo faccio? –

+0

@DavidCornelson è mostrato nel link nella mia risposta http://stackoverflow.com/questions/12858748/asp-net-webapi-posting-collection-of-subclasses –

Problemi correlati