जटिल प्रकार पोस्ट करने के लिए System.Net.HttpClient का उपयोग कैसे करें?


102

मेरे पास एक कस्टम जटिल प्रकार है जिसे मैं वेब एपीआई का उपयोग करके काम करना चाहता हूं।

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

और यहाँ मेरा वेब एपीआई नियंत्रक विधि है। मैं इस वस्तु को इस तरह पोस्ट करना चाहता हूं:

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

और अब मैं System.Net.HttpClientविधि को कॉल करने के लिए उपयोग करना चाहूंगा । हालाँकि, मैं इस बारे में अनिश्चित हूं कि किस प्रकार की वस्तु को PostAsyncविधि में पारित किया जाए , और इसका निर्माण कैसे किया जाए। यहाँ कुछ नमूना ग्राहक कोड है।

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

मैं इस HttpContentतरह से ऑब्जेक्ट कैसे बनाऊंगा कि वेब एपीआई इसे समझ जाएगा?


क्या आपने सर्विस एंडपॉइंट के लिए अपनी ऑब्जेक्ट का XML क्रमांकित संस्करण सबमिट करने का प्रयास किया है?
जोशुआ ड्रेक

जवाबों:


132

जेनेरिक HttpRequestMessage<T>को हटा दिया गया है । यह :

new HttpRequestMessage<Widget>(widget)

अब काम नहीं करेगा ।

इस पोस्ट के बजाय, ASP.NET टीम ने इस कार्यक्षमता का समर्थन करने के लिए कुछ नए कॉल शामिल किए हैं :

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

तो, नया कोड ( डंस्टन से ) बन जाता है:

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

1
हाँ, लेकिन क्या होगा यदि आपके पास विजेट वर्ग तक पहुंच नहीं है?
contactmatt

13
नए HttpClient.PostAsXXXAsync<T>( T value ) methods are great, but what about one for application/x-www-form-urlencoded format? Is there a simple / short way for that or do we still need to create elaborate KeyValuePair` सूचियों?
जान्स

1
@Jans Flurl.Http के माध्यम से एक सरल / संक्षिप्त तरीका प्रदान करता है PostUrlEncodedAsync
टोड मेनियर

16
ध्यान दें कि आपको System.Net.Http पर एक संदर्भ जोड़ने की आवश्यकता है। उपयोग करने में सक्षम होने के लिए PostAsJsonAsyncया PostAsXmlAsync
पीट

6
PostAsJsonAcync का उपयोग करने के लिए, NuGet पैकेज Microsoft.AspNet.WebApi.Client जोड़ें!
डेनिस

99

आपको SendAsyncइसके बजाय विधि का उपयोग करना चाहिए , यह एक सामान्य विधि है, जो सेवा के लिए इनपुट को क्रमबद्ध करती है

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

यदि आप कंक्रीट क्लास बनाना नहीं चाहते हैं, तो आप इसे 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();
    });

नोट: आपको अपनी आईडी को एक अशक्त int ( int?) बनाने की आवश्यकता है


1
यह एक बाहरी परियोजना से बुलाया जाएगा, जहां मेरे पास विधानसभा का संदर्भ नहीं होगा जिसमें विजेट ऑब्जेक्ट शामिल है। मैंने एक गुमनाम टाइप की गई वस्तु बनाने की कोशिश की जिसमें सही गुण हैं, इस पद्धति का उपयोग करके इसे क्रमबद्ध करना और इसे इस तरह से पारित करना, लेकिन मुझे 500 आंतरिक सर्वर त्रुटि मिलती है। यह वेब एपीआई नियंत्रक विधि को कभी नहीं मारता है।
indot_brad

ओह - तो आपको xml, या json को webapi सेवा में पोस्ट करने की आवश्यकता है, और यह इसे डिसेर्बलाइज करेगा - यह वही करता है, SendAsync, सेवा के लिए ऑब्जेक्ट को क्रमबद्ध कर रहा है
dunston

1
अभी-अभी अपडेट किया है - मेरे पास कोड है, लेकिन कुछ सरल कोड के साथ, लेकिन मुझे काम करना चाहिए
dunston

8
मुझे "गैर-सामान्य प्रकार का सिस्टम 'मिल रहा है। System.Net.Http.HttpRequestMessage' का उपयोग टाइप तर्कों के साथ नहीं किया जा सकता है"। क्या यह अभी भी वैध है?
user10479

5
हाँ पहला समाधान अब काम नहीं करता है: aspnetwebstack.codeplex.com/discussions/350492
Giovanni B

74

ध्यान दें कि यदि आप पोर्टेबल क्लास लाइब्रेरी का उपयोग कर रहे हैं, तो HttpClient में PostAsJsonAsync विधि नहीं होगी । पोर्टेबल क्लास लाइब्रेरी का उपयोग करके JSON के रूप में एक सामग्री पोस्ट करने के लिए, आपको यह करना होगा:

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

जब argsAsJson एक क्रमबद्ध ऑब्जेक्ट से आता है, और इस ऑब्जेक्ट की एक संपत्ति है। सामग्री = "डोमेन \ उपयोगकर्ता", फिर दो बार एन्कोड किया जाएगा। एक बार जब argsAsJson के लिए serialized और दूसरी बार जब PostAsync कंटेंटपोस्ट पोस्ट करता है। डबल एन्कोडिंग से कैसे बचें?
क्रिज़ीस्तोफ़ मोरीस्क

3
बहुत बढ़िया @fabiano! यह वास्तव में चाल चली गई। इस प्रकार की परियोजनाओं में दो अतिरिक्त तर्क आवश्यक हैं।
पीटर क्लेन

बहुत अच्छा @PeterKlein! मुझे यह जानकारी वेब पर Microsoft के दस्तावेज़ों में नहीं मिली, इसलिए इससे दूसरों को समान समस्या में मदद मिल सकती है। मेरी परियोजना बस इस चाल के बिना डेटा नहीं भेजती है।
फाबियानो

1
ध्यान दें कि आपको अनुरोध के एक्सेप्ट हेडर, " stackoverflow.com/a/40375351/3063273
मैट थॉमस

4

यदि आप अन्य उत्तरों में वर्णित सुविधा विधियों के प्रकार चाहते हैं, लेकिन पोर्टेबिलिटी की आवश्यकता है (या यहां तक ​​कि अगर आप नहीं भी हैं), तो आप फ्लूरल [प्रकटीकरण: मैं लेखक हूं] की जांच करना चाहता हूं। यह (पतले) लपेटता है HttpClientऔर Json.NET और कुछ धाराप्रवाह परीक्षण सहायकों सहित कुछ धाराप्रवाह चीनी और अन्य अच्छाइयों को जोड़ता है ।

JSON के रूप में पोस्ट करें:

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

या URL- एन्कोडेड:

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

उपरोक्त दोनों उदाहरण रिटर्न करते हैं HttpResponseMessage, लेकिन फ्लूर में अन्य चीजों को वापस करने के लिए विस्तार विधियां शामिल हैं यदि आप केवल पीछा करना चाहते हैं:

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

फ्लूर नूगेट पर उपलब्ध है:

PM> Install-Package Flurl.Http

1

बहुत सारे विकल्पों की जांच करने के बाद, मैं एक और दृष्टिकोण भर में आया हूं, जो एपीआई 2.0 संस्करण के लिए उपयुक्त है।

(VB.NET मेरा पसंदीदा है, 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

सौभाग्य! मेरे लिए यह (अंत में!) काम कर गया।

सादर, पीटर


1
@ फैबियानो द्वारा ऊपर दिए गए सुझावों के साथ यह चीजें घटित होती हैं।
पीटर क्लेन

2
VB.NET किसी का पसंदीदा नहीं है :)
आलसी कोडर

1

मुझे लगता है कि आप यह कर सकते हैं:

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

यदि मेरे जैसा कोई व्यक्ति वास्तव में यह नहीं समझ पा रहा है कि उपरोक्त सभी किस बारे में बात कर रहे हैं, तो मैं एक आसान उदाहरण देता हूं जो मेरे लिए काम कर रहा है। यदि आपके पास एक वेब एप है जो url " http://somesite.com/verifyAddress " है, तो यह एक पोस्ट विधि है और आपको इसे एक एड्रेस ऑब्जेक्ट पास करने की आवश्यकता है। आप अपने कोड में इस एपि को कॉल करना चाहते हैं। यहाँ आप क्या कर सकते हैं।

    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

यह वह कोड है जिसके साथ मैं यहां अन्य उत्तरों के आधार पर घाव कर रहा हूं। यह एक HttpPost के लिए है जो जटिल प्रकारों के साथ प्राप्त करता है और प्रतिक्रिया करता है:

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

-1

इस तरह एक सेवा कॉल करें:

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

और सेवा पद्धति इस प्रकार है:

public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}

PutAsJsonAsync नेटवर्क पर Serialization और deserialization का ख्याल रखता है


यह HTTP PUT संदेश भेजेगा, अनुरोध के रूप में पोस्ट नहीं। जैसा कि अन्य लोगों ने कहा है कि PostAsJsonAsyncJSON में POST के रूप में डेटा की आवश्यकता होगी।
ज़ाफ - बेन डुगुइद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.