2013-08-19 11 views
5

Sto tentando di associare un'azione del controllore a un'interfaccia, mantenendo comunque il comportamento di associazione predefinito.modello Web API che si lega a un'interfaccia

public class CoolClass : ISomeInterface 
{ 
    public DoSomething {get;set;} // ISomeInterface 
} 

public class DosomethingController : ApiController 
{ 
    public HttpResponseMessage Post(ISomeInterface model) 
    { 
     // do something with model which should be an instance of CoolClass 
    } 
} 

Il consumatore del mio servizio non sa nulla di CoolClass così averli aggiungere "$ tipo" al JSON che sono di passaggio sarebbe un hack a mio parere. Mi piacerebbe essere in grado di gestirlo nel servizio. Se si specifica CoolClass come parametro di azione, funziona correttamente.

EDIT: Quindi ho trovato una soluzione parziale alla mia domanda qui Dependency injection for ASP.NET Web API action method parameters ma c'è un problema di follow-up. Quella soluzione non risolve le proprietà dell'interfaccia. Vedi il mio esempio qui sotto.

IConcreteClass verrà risolto, ma ISubtype no.

public class SubConcreteClass : ISubtype 
{ 
    // properties 
} 

public class ConcreteClass : IConcreteClass 
{ 
    public ISubtype Subtype {get;set;} 
} 

Una volta che il formattatore mezzi vede che è in grado di risolvere il tipo di IConcreteClass, è quindi legge l'intero flusso. Quindi immagino che non ci sia alcuna possibilità di risolvere i membri dell'interfaccia.

+0

per un'altra alternativa, controllare la mia risposta a una domanda simile [_here_] (http: // stackoverflow.com/questions/14124189/can-i-pass-an-interface-based-object-to-an-mvc-4-webapi-post/22279204#22279204). –

risposta

11

Quindi nel caso in cui questo può aiutare qualcun altro, andrò avanti e pubblicare la soluzione che ho trovato.

Come già detto, i parametri dell'interfaccia del metodo di azione possono essere risolti utilizzando DI. Ma i membri dell'interfaccia di quell'oggetto devono essere gestiti in modo diverso.

Ho creato 2 tipi di convertitori Json, un tipo di entità singola e un tipo di raccolta, per decorare le proprietà dell'interfaccia.

Ecco una classe che deve essere risolta come parametro dell'interfaccia di azione.

public class CreateEnvelopeModel : ICreateEnvelopeCommand 
{ 
    [JsonConverter(typeof(EntityModelConverter<CreateEmailModel, ICreateEmailCommand>))] 
    public ICreateEmailCommand Email { get; set; } 
    [JsonConverter(typeof(CollectionEntityConverter<CreateFormModel, ICreateFormCommand>))] 
    public IList<ICreateFormCommand> Forms { get; set; } 
} 

Ecco il metodo di azione del controller

public HttpResponseMessage PostEnvelope(ICreateEnvelopeCommand model) 
{ 
    // do stuff 
} 

Ecco i convertitori 2 JSON

public class EntityModelConverter<T, Tt> : JsonConverter where T : Tt 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Tt)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize<T>(reader); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value, typeof(T)); 
    } 
} 

public class CollectionEntityConverter<T, Tt> : JsonConverter where T : Tt 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(IList<Tt>)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     IList<Tt> items = serializer.Deserialize<List<T>>(reader).Cast<Tt>().ToList(); 
     return items; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value, typeof(IList<T>)); 
    } 
} 
+0

Questa è un'ottima soluzione. – saille

+0

Sei il migliore, ha funzionato perfettamente. – alsafoo

+0

Questo è meravigliosamente semplice ed efficace. Ci sono degli svantaggi nell'uso di questo modello di rilegatura personalizzato? Qualche idea su come utilizzare qualcosa di simile in una raccolta in cui l'interfaccia ha più classi di implementazione (ad esempio IAuto, Car: IAuto, Truck: IAuto)? – BrianS

-1

Vedere Model Binders sezione here. Penso che sia il tuo caso.

+0

Grazie Alex. Ho visto quella pagina ma speravo davvero che questo potesse essere risolto con il mio contenitore DI. Non è possibile risolvere i parametri dell'interfaccia dell'azione API con DI? – chrisl91

+0

Aggiornata la mia domanda. – chrisl91

Problemi correlati