Hoe gebruik je System.Net.HttpClient om een ​​complex type te posten?

Ik heb een aangepast complex type waarmee ik wil werken met behulp van Web API.

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

En hier is mijn web-API-controllermethode. Ik wil dit object als volgt posten:

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;
    }
}

En nu wil ik System.Net.HttpClientgebruiken om de methode aan te roepen. Ik weet echter niet zeker welk type object ik moet doorgeven aan de PostAsync-methode en hoe ik het moet construeren. Hier is een voorbeeld van een klantcode.

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();
    });

Hoe maak ik het HttpContent-object zodanig dat de web-API het begrijpt?


Antwoord 1, autoriteit 100%

De generieke HttpRequestMessage<T>is verwijderd. Dit :

new HttpRequestMessage<Widget>(widget)

zal niet meer werken.

In plaats daarvan heeft het ASP.NET-team uit dit berichtenkele nieuwe oproepenom deze functionaliteit te ondersteunen:

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

Dus de nieuwe code (van dunston) wordt:

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

Antwoord 2, autoriteit 74%

U moet in plaats daarvan de SendAsync-methode gebruiken, dit is een generieke methode die de invoer naar de service serialiseert

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

Als u de concrete klasse niet wilt maken, kunt u deze maken met de klasse 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();
    });

Opmerking: u moet van uw id een nullable int (int?) maken


Antwoord 3, autoriteit 57%

Houd er rekening mee dat als u een Portable Class Library gebruikt, HttpClient geen PostAsJsonAsync-methode heeft.
Om inhoud als JSON te posten met een Portable Class Library, moet je dit doen:

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

Antwoord 4, autoriteit 3%

Als je de soorten gemaksmethoden wilt die in andere antwoorden worden genoemd, maar draagbaarheid nodig hebt (of zelfs als je dat niet doet), wil je misschien eens kijken naar Flurl[openbaarmaking: ik ben de auteur]. Het omhult (dun) HttpClienten Json.NET en voegt wat vloeiende suiker en andere goodies toe, waaronder wat ingebakken helpers testen.

Post als JSON:

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

of URL-gecodeerd:

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

Beide voorbeelden hierboven retourneren een HttpResponseMessage, maar Flurl bevat extensiemethoden om andere dingen terug te sturen als je gewoon tot de ontdekking wilt komen:

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

Flurl is beschikbaar op NuGet:

PM> Install-Package Flurl.Http

Antwoord 5

Na veel alternatieven te hebben onderzocht, ben ik een andere benadering tegengekomen, geschikt voor de API 2.0-versie.

(VB.NET is mijn favoriet, zooo…)

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

Veel succes! Voor mij is dit gelukt (uiteindelijk!).

Met vriendelijke groet,
Pieter


Antwoord 6

Ik denk dat je dit kunt doen:

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

Antwoord 7

In het geval dat iemand zoals ik niet echt begreep waar al het bovenstaande over gaat, geef ik een eenvoudig voorbeeld dat voor mij werkt.
Als u een web-API heeft met de url “http://somesite.com/verifyAddress“, is dit een post-methode en je moet er een adresobject aan doorgeven. Deze api wil je in je code aanroepen. Hier wat u kunt doen.

   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;
    }

Antwoord 8

Dit is de code waarmee ik eindigde, gebaseerd op de andere antwoorden hier. Dit is voor een HttpPost die complexe typen ontvangt en reageert:

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));

Antwoord 9

Breng een serviceverzoek als volgt:

public async void SaveActivationCode(ActivationCodes objAC)
{
    var client = new HttpClient();
    client.BaseAddress = new Uri(baseAddress);
    HttpResponseMessage response = await client.PutAsJsonAsync(serviceAddress + "/SaveActivationCode" + "?apiKey=445-65-1216", objAC);
} 

En servicemethode als volgt:

public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}

PutAsJsonAsync zorgt voor serialisatie en deserialisatie via het netwerk

Other episodes