web-dev-qa-db-fra.com

Comment utiliser System.Net.HttpClient pour publier un type complexe?

J'ai un type de complexe personnalisé que je souhaite utiliser avec l'API Web.

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

Et voici ma méthode de contrôleur API Web. Je veux poster cet objet comme suit:

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, j'aimerais utiliser System.Net.HttpClient pour appeler la méthode. Cependant, je ne sais pas quel type d'objet passer dans la méthode PostAsync et comment le construire. Voici un exemple 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 créer l'objet HttpContent de manière à ce que l'API Web le comprenne?

101
indot_brad

Le générique HttpRequestMessage<T> a été supprimé . Cette :

new HttpRequestMessage<Widget>(widget)

ne fonctionnera plus .

À la place, à partir de cet article , l'équipe ASP.NET en a ajouté quelques nouveaux appels pour prendre en charge cette fonctionnalité:

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

Ainsi, le nouveau code ( 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() );
131
Joshua Ball

Vous devez utiliser la méthode SendAsync à la place. Il s'agit d'une méthode générique, qui sérialise l'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 concrète, vous pouvez le faire avec la classe FormUrlEncodedContent

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 définir votre identifiant comme un int nullable (int?).

99
dunston

Notez que si vous utilisez une bibliothèque de classes portable, HttpClient n'aura pas de méthode PostAsJsonAsync. Pour publier un contenu au format JSON à l'aide d'une bibliothèque de classes portable, vous devez procéder comme suit:

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());
73
Fabiano

Si vous voulez les types de méthodes de commodité mentionnés dans d'autres réponses mais que vous avez besoin de portabilité (ou même si vous n'en avez pas besoin), vous pouvez vérifier Flurl [divulgation: je suis l'auteur]. Il enveloppe (finement) HttpClient et Json.NET et ajoute un peu de sucre fluide et d'autres friandises, y compris des éléments cuits au four aides au test .

Poster en JSON:

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

ou encodé en URL:

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

Les deux exemples ci-dessus renvoient un HttpResponseMessage, mais Flurl inclut des méthodes d'extension pour renvoyer d'autres éléments si vous souhaitez simplement passer à l'action:

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
4
Todd Menier

Après avoir étudié de nombreuses alternatives, je suis tombé sur une autre approche, adaptée à la version 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!).

Cordialement, Peter

1
user2366741

Je pense que tu peux faire ça:

var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
    .ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });
1
Marius Stănescu

Au cas où quelqu'un comme moi ne comprendrait pas vraiment de quoi parle tout ce qui précède, je donne un exemple simple qui fonctionne pour moi. Si vous avez une API Web dont l'URL est " http://somesite.com/verifyAddress ", il s'agit d'une méthode de publication et vous devez lui transmettre un objet d'adresse. Vous voulez appeler cette API dans votre code. Voici ce que vous pouvez faire.

    public Address verifyAddress(Address address)
    {
        this.client = new HttpClient();
        client.BaseAddress = new Uri("http://somesite.com/");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var urlParm = URL + "verifyAddress";
        response = client.PostAsJsonAsync(urlParm,address).Result;
        var dataObjects = response.IsSuccessStatusCode ? response.Content.ReadAsAsync<Address>().Result : null;
        return dataObjects;
    }
0
user3293338

C'est le code avec lequel j'ai fini, basé sur les autres réponses ici. Ceci est pour un HttpPost qui reçoit et répond avec des types complexes:

Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(
                       strMyHttpPostURL,
                       new MyComplexObject { Param1 = param1, Param2 = param2}).ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
                    //debug:
                    //String s = response.Result.Content.ReadAsStringAsync().Result;
                    MyOtherComplexType moct = (MyOtherComplexType)JsonConvert.DeserializeObject(response.Result.Content.ReadAsStringAsync().Result, typeof(MyOtherComplexType));
0
Lodlaiden