Jak używać System. Net. HttpClient do publikowania złożonego typu?

Mam niestandardowy typ złożony, z którym chcę pracować przy użyciu Web API.

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

A oto moja metoda kontrolera web API. Chcę opublikować ten obiekt w ten sposób:

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

A teraz chciałbym użyć System. Net. HttpClient, aby wywołać metodę. Nie jestem jednak pewien, jakiego typu obiekt przekazać do metody PostAsync i jak go skonstruować. Oto przykładowy kod klienta.

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

Jak utworzyć obiekt HttpContent w taki sposób, aby web API rozumiesz?

Author: indot_brad, 2012-04-24

9 answers

Ogólny HttpRequestMessage<T> został usunięty. To:

new HttpRequestMessage<Widget>(widget)

Nie będzie już działać .

Zamiast z tego postu , ASP.NET zespół dodał kilka nowych połączeń do obsługi tej funkcjonalności:

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

Tak więc nowy kod (z dunston ) staje się:

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() );
 128
Author: Joshua Ball,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Powinieneś zamiast tego użyć metody SendAsync, jest to metoda ogólna, która serializuje dane wejściowe do usługi

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

Jeśli nie chcesz tworzyć klasy concrete, możesz to zrobić za pomocą klasy 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();
    });

Uwaga: musisz dodać id do nullable int (int?)

 99
Author: dunston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-28 11:05:12

Zauważ, że jeśli używasz przenośnej biblioteki klas, HttpClient nie będzie miał metody PostAsJsonAsync. Aby opublikować zawartość jako JSON za pomocą przenośnej biblioteki klas, musisz to zrobić:

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
Author: Fabiano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-15 22:21:25

Jeśli chcesz typów metod wygody wymienionych w innych odpowiedziach, ale potrzebujesz przenośności (a nawet jeśli nie), możesz sprawdzić Flurl [disclosure: jestem autorem]. To (cienko) owija HttpClient i Json.NET i dodaje trochę płynnego cukru i innych smakołyków, w tym kilka pieczonych pomocników testujących.

Post jako JSON:

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

Lub zakodowany URL:

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

Oba powyższe przykłady zwracają HttpResponseMessage, ale Flurl zawiera metody rozszerzenia dla zwracanie innych rzeczy, jeśli tylko chcesz przejść do sedna:

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

Flurl jest dostępny na NuGet:

PM> Install-Package Flurl.Http
 4
Author: Todd Menier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 14:23:36

Po zbadaniu wielu alternatyw, natknąłem się na inne podejście, odpowiednie dla wersji API 2.0.

(VB.NET to moje ulubione, 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
Powodzenia! Dla mnie to się udało (w końcu!).

Pozdrawiam, Piotr

 1
Author: user2366741,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-10 18:27:34

Myślę, że możesz to zrobić:

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
Author: Marius Stănescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-27 12:38:36

Oto kod, z którym skończyłem, oparty na innych odpowiedziach tutaj. Jest to dla HttpPost, który odbiera i odpowiada złożonymi typami:

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
Author: Lodlaiden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-26 14:56:41

Na wypadek, gdyby ktoś taki jak ja nie do końca rozumiał, o czym wszyscy wyżej mówią, podaję prosty przykład, który działa dla mnie. Jeśli masz web api którego url jest " http://somesite.com/verifyAddress", jest to metoda post i wymaga podania obiektu adresu. Chcesz wywołać ten api w swoim kodzie. Tutaj, co możesz zrobić.

    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
Author: user3293338,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-24 19:36:35

Wykonaj połączenie serwisowe w ten sposób:

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

I metoda serwisowa taka:

public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}

PutAsJsonAsync zajmuje się Serializacją i deserializacją przez sieć

 -1
Author: Nitin Nayyar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-14 22:25:51