168 votes

Comment passer un objet à HttpClient.PostAsync et le sérialiser en tant que corps JSON ?

J'utilise System.Net.Http J'ai trouvé plusieurs exemples sur le web. J'ai réussi à créer ce code pour faire un POST demande :

public static string POST(string resource, string token)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(baseUri);
        client.DefaultRequestHeaders.Add("token", token);

        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("", "")
        });

        var result = client.PostAsync("", content).Result;
        string resultContent = result.Content.ReadAsStringAsync().Result;
        return resultContent;
    }
 }

tout fonctionne bien. Mais supposons que je veuille passer un troisième paramètre à la fonction POST un paramètre appelé data . Le paramètre de données est un objet comme celui-ci :

object data = new
{
    name = "Foo",
    category = "article"
};

comment puis-je faire cela sans créer le KeyValuePair ? Mon php RestAPI attend une entrée json, donc le FormUrlEncodedContent devrait envoyer le raw json correctement. Mais comment puis-je faire cela avec Microsoft.Net.Http ? Merci.

0 votes

Si je comprends bien votre question, vous voulez envoyer un contenu JSON au lieu d'un contenu codé par formulaire (et par extension vous voulez que votre type anonyme soit sérialisé en JSON dans ce contenu) ?

0 votes

@CodingGorilla oui est un type anonyme.

4 votes

À titre d'avertissement pour les futurs lecteurs, n'utilisez pas de fichier using pour le HttpClient . aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong

218voto

CodingGorilla Points 12373

La réponse directe à votre question est : non. La signature de l'acte de naissance de l'enfant. PostAsync est la suivante :

public Task PostAsync(Uri requestUri, HttpContent content)

Ainsi, alors que vous pouvez passer un object à PostAsync il doit être de type HttpContent et votre type d'anonymat ne répond pas à ces critères.

Cependant, il existe des moyens d'accomplir ce que vous voulez accomplir. Tout d'abord, vous devrez sérialiser votre type anonyme en JSON, l'outil le plus courant pour cela étant Json.NET . Et le code pour cela est assez trivial :

var myContent = JsonConvert.SerializeObject(data);

Ensuite, vous devrez construire un objet de contenu pour envoyer ces données, je vais utiliser un ByteArrayContent mais vous pouvez utiliser ou créer un autre type si vous le souhaitez.

var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);

Ensuite, il faut définir le type de contenu pour que l'API sache qu'il s'agit de JSON.

byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

Vous pouvez ensuite envoyer votre demande de manière très similaire à votre exemple précédent avec le contenu du formulaire :

var result = client.PostAsync("", byteContent).Result

D'ailleurs, l'appel de la .Result propriété comme vous le faites ici peut avoir quelques mauvais effets secondaires comme la fermeture à clé, il faut donc être prudent avec ça.

0 votes

Ok, c'est très clair. Merci pour cette réponse. Juste une question : quand un POST, PUT, DELETE est effectuée, généralement le retour API TRUE j'ai déclaré la méthode comme string mais quand je le fais : return result; J'ai compris : Can't Convert HttpResponseMessage in string Dois-je modifier la déclaration de la méthode ? J'ai besoin de la réponse sous forme de chaîne car je dois la désérialiser après dans une autre méthode de classe.

3 votes

Si vous avez besoin de désérialiser le corps de la réponse, alors le retour de la chaîne de caractères comme vous l'avez fait dans votre question (à l'aide de result.Content.ReadAsStringAsync() ) est probablement très bien. En fonction de la structure de votre application, il peut être préférable de renvoyer l'élément Content directement si vous devez inspecter les en-têtes pour déterminer le type de contenu (par exemple, XML ou JSON). Mais si vous connaître il va toujours renvoyer JSON (ou un autre format), alors renvoyer le corps de la réponse sous forme de chaîne de caractères devrait suffire.

0 votes

Désolé de demander, mais devez-vous faire cela si les données sont de type StringContent ?

126voto

Nouvelle solution .NET 5 :

Dans .NET 5, une nouvelle classe a été introduite, appelée JsonContent qui dérive de HttpContent . Voir dans les documents de Microsoft

Cette classe possède une méthode statique appelée Create() qui prend un objet comme paramètre.

Utilisation :

var myObject = new
{
    foo = "Hello",
    bar = "World",
};

JsonContent content = JsonContent.Create(myObject);

HttpResponseMessage response = await _httpClient.PostAsync("https://...", content);

0 votes

J'ai utilisé votre exemple et pendant le débogage, mon code est sorti sans aucune erreur ou réponse... Je n'ai jamais vu cela... une idée de ce que cela peut être ?

99voto

elolos Points 946

Vous devez transmettre vos données dans le corps de la requête sous la forme d'une chaîne brute plutôt que de FormUrlEncodedContent . Une façon de le faire est de le sérialiser en une chaîne JSON :

var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json

Il ne vous reste plus qu'à passer la chaîne de caractères à la méthode post.

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); // use MediaTypeNames.Application.Json in Core 3.0+ and Standard 2.1+

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);

0 votes

Qu'est-ce que stringContent ? Dans mon cas stringContent valeur est "\"\"" . Cette valeur est-elle correcte ?

0 votes

Est-il possible d'obtenir le résultat de la chaîne de caractères en vb à partir de votre code c# ? j'ai découvert que c'est assez similaire.....

58voto

trydis Points 1822

Une solution simple consiste à utiliser Microsoft ASP.NET Web API 2.2 Client de NuGet .

Vous pouvez alors simplement faire ceci et cela sérialisera l'objet en JSON et définira l'attribut Content-Type à l'en-tête application/json; charset=utf-8 :

var data = new
{
    name = "Foo",
    category = "article"
};

var client = new HttpClient();
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Add("token", token);
var response = await client.PostAsJsonAsync("", data);

4 votes

Définitivement PostAsJsonAsync est là pour utiliser

0 votes

Ce serait bien s'il y avait aussi un PatchAsJsonAsync correspondant.

33voto

Ken Lyon Points 1054

Il existe maintenant un moyen plus simple avec .NET Standard ou .NET Core :

var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());

NOTE : Afin d'utiliser le JsonMediaTypeFormatter vous devrez installer la classe Microsoft.AspNet.WebApi.Client paquet NuGet, qui peut être installé directement, ou via un autre tel que Microsoft.AspNetCore.App .

En utilisant cette signature de HttpClient.PostAsync vous pouvez passer n'importe quel objet et l'option JsonMediaTypeFormatter se chargera automatiquement de la sérialisation, etc.

Avec la réponse, vous pouvez utiliser HttpContent.ReadAsAsync<T> pour désérialiser le contenu de la réponse au type que vous attendez :

var responseObject = await response.Content.ReadAsAsync<MyResponseType>();

1 votes

Quelle version de .net utilisez-vous ? Ma version ne trouve pas "Formatting" dans l'espace de noms System.Net.Http.

1 votes

@Programmatic Vous devez utiliser .NET Standard o .NET Core comme je l'ai mentionné. Peut-être utilisez-vous .NET Framework ? Dans mon projet, le JsonMediaTypeFormatter est chargé à partir d'ici : C:\Program Fichiers \dotnet\sdk\NuGetFallbackFolder\microsoft.aspnet.webapi .client \5.2.6\lib\ne tstandard2.0 \System. Net.Http.Formatage.dll

1 votes

@Programmatic Si vous utilisez déjà l'un de ces types de projet, il se peut que vous deviez ajouter un paquet NuGet supplémentaire. J'oublie exactement lesquels ont été inclus automatiquement pour moi. Dans mon cas, il a été inclus dans le paquet Microsoft.AspNetCore.App NuGet.

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