103 votes

Comment utiliser le Système.Net.HttpClient pour poster un type complexe?

J'ai un custom de type complexe que je veux travailler avec l'aide de l'API Web.

public class Widget
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Et voici mon API web méthode de contrôleur. Je veux mettre cet objet comme ceci:

public class TestController : ApiController
{
    // POST /api/test
    public HttpResponseMessage<Widget> Post(Widget widget)
    {
        widget.ID = 1; // hardcoded for now. TODO: Save to db and return newly created ID

        var response = new HttpResponseMessage<Widget>(widget, HttpStatusCode.Created);
        response.Headers.Location = new Uri(Request.RequestUri, "/api/test/" + widget.ID.ToString());
        return response;
    }
}

Et maintenant, je tiens à utiliser le Système.Net.HttpClient pour faire l'appel à la méthode. Cependant, je ne suis pas sûr de quel type d'objet à passer dans le PostAsync méthode, et comment le construire. Voici quelques exemples de code client.

var client = new HttpClient();
HttpContent content = new StringContent("???"); // how do I construct the Widget to post?
client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
    (postTask) =>
    {
        postTask.Result.EnsureSuccessStatusCode();
    });

Comment puis-je créer l'HttpContent objet de façon que l'API web de se comprendre?

134voto

user39758 Points 3262

Le générique de l' HttpRequestMessage<T> a été supprimée. Ce :

new HttpRequestMessage<Widget>(widget)

aura pas plus de travail.

Au lieu de cela, à partir de ce post, l'ASP.NET l'équipe a inclus quelques nouveaux appels à l'appui de cette fonctionnalité:

HttpClient.PostAsJsonAsync<T>(T value) sends "application/json"
HttpClient.PostAsXmlAsync<T>(T value) sends "application/xml"

Ainsi, le nouveau code (à partir de dunston) devient:

Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268");
client.PostAsJsonAsync("api/test", widget)
    .ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );

99voto

dunston Points 1770

Vous devez utiliser la méthode SendAsync place, c'est une méthode générique, qui sérialise les données d'entrée du service

Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268/api/test");
client.SendAsync(new HttpRequestMessage<Widget>(widget))
    .ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );

Si vous ne voulez pas créer la classe de béton, vous pouvez le faire avec l'FormUrlEncodedContent classe

var client = new HttpClient();

// This is the postdata
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("Name", "test"));
postData.Add(new KeyValuePair<string, string>("Price ", "100"));

HttpContent content = new FormUrlEncodedContent(postData); 

client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
    (postTask) =>
    {
        postTask.Result.EnsureSuccessStatusCode();
    });

Remarque: vous devez faire votre identifiant à un nullable int (int?)

75voto

Fabiano Points 656

Notez que si vous utilisez une Bibliothèque de classes Portable, HttpClient n'aura pas PostAsJsonAsync méthode. Pour poster un contenu JSON à l'aide d'une Bibliothèque de classes Portable, vous aurez pour ce faire:

HttpClient client = new HttpClient();
HttpContent contentPost = new StringContent(argsAsJson, Encoding.UTF8, 
"application/json");

await client.PostAsync(new Uri(wsUrl), contentPost).ContinueWith(
(postTask) => postTask.Result.EnsureSuccessStatusCode());

4voto

Todd Menier Points 3599

Si vous voulez que les types de méthodes pratiques mentionnées dans d'autres réponses, mais besoin de portabilité (ou même si vous n'en avez pas), vous pourriez vouloir vérifier Flurl [divulgation: je suis l'auteur]. (Finement) encapsule HttpClient et Json.NET et ajoute quelques couramment le sucre et d'autres goodies, y compris certains de boulangerie-dans les essais aides.

Post JSON:

var resp = await "http://localhost:44268/api/test".PostJsonAsync(widget);

ou URL-encodé:

var resp = await "http://localhost:44268/api/test".PostUrlEncodedAsync(widget);

Les deux exemples ci-dessus, de retour d'un HttpResponseMessage, mais Flurl comprend les méthodes d'extension pour le retour d'autres choses si vous voulez juste pour couper à la chasse:

T poco = await url.PostJsonAsync(data).ReceiveJson<T>();
dynamic d = await url.PostUrlEncodedAsync(data).ReceiveJson();
string s = await url.PostUrlEncodedAsync(data).ReceiveString();

Flurl est disponible sur NuGet:

PM> Install-Package Flurl.Http

1voto

user2366741 Points 72

Après avoir étudié beaucoup de solutions de rechange, j'ai rencontré une autre approche, adapté pour la version de l'API 2.0.

(VB.NET est mon préféré, sooo...)

Public Async Function APIPut_Response(ID as Integer, MyWidget as Widget) as Task(Of HttpResponseMessage)
    Dim DesiredContent as HttpContent = New StringContent(JsonConvert.SerializeObject(MyWidget))
    Return Await APIClient.PutAsync(String.Format("api/widget/{0}", ID), DesiredContent)
End Function

Bonne chance! Pour moi cela a fonctionné (à la fin!).

En ce qui concerne, Peter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X