2013-11-20 5 views
5

Ich versuche, von einem Client zu einem Web-API-Methode zu schreiben, wie folgt:POST Web API Aktion mit IEnumerable <Interface> Typ Parameter

// Create list of messages that will be sent 
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>(); 
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface. 

// Create http client 
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])}; 
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 

// Post to web api 
HttpResponseMessage response = client.PostAsJsonAsync("Communications/Messages", messages).Result; 

// Read results 
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result; 

My Web API Controller-Aktion wie folgt aussieht:

public HttpResponseMessage Post([FromBody]IEnumerable<IMessageApiEntity> messages) 
{ 
    // Do stuff 
} 

Das Problem, das ich habe, ist, dass messages immer leer ist (aber nicht null), wenn Sie in die Web-API-Controller-Aktion kommen. Ich habe im Debugger verifiziert, dass das Objekt messages auf der Client-Seite Elemente enthält, bevor es gepostet wird.

Ich vermute, es könnte etwas damit zu tun haben, dass der Interface-Typ beim Versuch, die Objekte zu übergeben, nicht in einen konkreten Typ konvertiert wird, aber ich weiß nicht, wie ich das machen soll. Wie kann ich das erreichen?

Antwort

7

Ich habe herausgefunden, wie es ohne einen benutzerdefinierten Modellbinder geht. Posting die Antwort, falls jemand anderes dieses Problem hat ...

Auftraggeber:

// Create list of messages that will be sent 
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>(); 
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface. 

// Create http client 
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])}; 
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 

// Post to web api (this is the part that changed) 
JsonMediaTypeFormatter json = new JsonMediaTypeFormatter 
{ 
    SerializerSettings = 
    { 
     TypeNameHandling = TypeNameHandling.All 
    } 
}; 
HttpResponseMessage response = client.PostAsync("Communications/Messages", messages, json).Result; 

// Read results 
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result; 

zu Register Methode in WebApiConfig.cs hinzufügen:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto; 

Der Schlüssel ist, die Art zu senden, wie Teil des JSON und aktivieren Sie die automatische Typnamenbehandlung, damit die Web-API herausfinden kann, um welchen Typ es sich handelt.

+0

Danke. Klappt wunderbar. Hat mir sehr geholfen. –

+0

Anstatt einen neuen 'SerializerSettings' zu instanziieren, empfehle ich, den Standard zu aktualisieren (greifen Sie einfach darauf zu, wie Sie es in' WebApiConfig.cs' tun).Auf diese Weise verlieren Sie keine anderen Standard-Serializer-Einstellungen. –

0

Warum verwenden Sie Schnittstellentyp in Methode? Sieht aus wie Web-API, hat keine Ahnung, welche Art von Instanz verwendet werden soll, um Nachrichten-Argument zu materialisieren. Es scheint, dass Sie benutzerdefinierte Modellbinder für diese Aktion schreiben müssen.

+0

Vielen Dank für die Antwort. Ich verwende einen Schnittstellentyp, weil ich in der Lage sein muss, eine Liste verschiedener Nachrichtentypen in einem API-Aufruf zu veröffentlichen. Ich habe bereits gesagt, dass das Problem darin besteht, dass der Interface-Typ nicht in einen konkreten Typ konvertiert wird. Ein Beispiel für das, was Sie beschreiben, wäre hilfreich. – mayabelle

+0

Zuerst müssen Sie einige Daten senden, um den konkreten Typ von IMessageApiEntity in Ihrer Anfrage anzugeben. dann sollten Sie Ihren IModelBinder ([kleines Beispiel] (http://www.dotnetcurry.com/ShowArticle.aspx?ID=584)) implementieren und schließlich das [FromBody] -Attribut dem [ModelBinder (typeof (YourCustomModelBinderTypeName)) ersetzen]] für Ihre "Nachrichten" Methode Parameter –

0

Ich hatte ein ähnliches Problem vor ein paar Wochen mit .NET Core WebAPI. Die vorgeschlagene Lösung, um die Zeile unter der Zugabe nicht für mich arbeiten:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto; 

Ich landete ein generisches Objekt erstellen, die meine IEnumerable tragen kann, wobei T meine beabsichtigte Klasse ist

[Serializable] 
public class GenericListContainer<T> where T : class 
{ 
    #region Constructors 

    public GenericListContainer() 
    { 

    } 

    public GenericListContainer(IEnumerable<T> list) 
    { 
     List = list; 
    } 
    #endregion 

    #region Properties 

    public IEnumerable<T> List { get; set; } 

    #endregion 
} 

ich dann änderte meine Webapi-Methode zu:

Diese Methode gibt die gespeicherte Benutzer-ID zurück (in meinem Fall Guid).

Hoffe das hilft jemand anderem!