2014-11-15 8 views
11

वेब एपीआई 2.2 का उपयोग करके, मान लीजिए कि मैं HttpContent से दो बार अलग-अलग प्रकार के रूप में पढ़ना चाहता हूं।HttpContent के लिए एकाधिक कॉल ReadAsAsync

await httpContent.LoadIntoBufferAsync(); //necessary to buffer content for multiple reads 
var X = await httpContent.ReadAsAsync<T>(); //read as first type 
var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>(); //read as second type 

जब मैं ऊपर कोड चलाने के लिए, X की T जबकि Y बातिल है एक गैर-शून्य उदाहरण है। अगर मैं ऑर्डर स्विच करता हूं, Y एक गैर-शून्य शब्दकोश होगा जबकि X शून्य होगा। दूसरे शब्दों में, ReadAsAsync पर दूसरी और बाद की कॉल हमेशा शून्य हो जाएगी जब तक कि उन्हें समान जेनेरिक प्रकार पैरामीटर के साथ बुलाया न जाए। स्वतंत्र रूप से, या तो ReadAsAsync पर कॉल की अपेक्षा की जाती है (भले ही LoadIntoBufferAsync को कॉल करने की आवश्यकता हो)।

यह मेरे लिए अप्रत्याशित है - ऐसा लगता है कि मुझे बफर सामग्री को कई बार अलग-अलग प्रकार के रूप में पढ़ने में सक्षम होना चाहिए। मैं एक और लाइन जोड़ देते हैं तो:

var Z = await httpContent.ReadAsString(); 

परिणाम Z एक गैर-शून्य स्ट्रिंग, कोई फर्क नहीं पड़ता X, Y, Z असाइनमेंट के आदेश हो जाएगा।

तो यह कैसे होता है, और HttpContent से ReadAsAsync का उपयोग करके मैं कई प्रकार के साथ क्यों नहीं पढ़ सकता?

+0

नोट: आपको आश्चर्य हो सकता है कि मैं ऐसा क्यों कर रहा हूं। मैं वेब एपीआई में आंशिक अपडेट/'पैच' को लागू करने के लिए अंततः किन संपत्तियों को 'टी' से बांधने के लिए एक सरल विधि तैयार करने की कोशिश कर रहा हूं। एक शब्दकोश में पढ़ने का दूसरा दौर मुझे सबमिट किए गए डेटा के साथ ओवरराइट करने के लिए कुंजी (संपत्ति नाम) की एक सूची देता है। मुझे ओडाटा 'डेल्टा ' कक्षा से अवगत है, लेकिन दुर्भाग्यवश यह ओडाटा नियंत्रकों के बाहर सही ढंग से काम नहीं कर रहा है। http://stackoverflow.com/questions/15561874/deltat-in-patch-actions-not-tracking-primitive-types –

उत्तर

4

प्रलेखन प्रश्न पर स्पैस है, लेकिन यह मुझे आश्चर्य की बात नहीं है कि HttpContent स्ट्रीम की तरह कार्य करता है, जिसमें आप इसे एक बार पढ़ सकते हैं। नाम में "पढ़ने" के साथ .NET में बहुत अधिक विधि इस तरह से कार्य करती है।

मुझे कोई विचार नहीं है कि यह संभवतः डीबगिंग उद्देश्यों को छोड़कर, प्रत्येक बार अलग-अलग डेटा को पढ़ने के लिए क्यों समझ में आता है। आपका उदाहरण मेरे लिए प्रतीत होता है। लेकिन यदि आप वास्तव में ऐसा करना चाहते हैं, तो आप ReadAsStreamAsync() को आजमा सकते हैं, जिसे आप सीधे Stream से पढ़ सकते हैं, Position प्रॉपर्टी को 0 बार रीसेट कर प्रत्येक बार जब आप इसे फिर से पढ़ना चाहते हैं, या ReadAsByteArrayAsync(), आपको एक बाइट सरणी देकर आप पढ़ सकते हैं जितनी बार आप चाहें उतनी बार।

बेशक, आपको वांछित प्रकार में रूपांतरित करने के लिए स्पष्ट रूप से प्रारूपकों का उपयोग करना होगा। लेकिन यह एक बाधा का ज्यादा नहीं होना चाहिए।

+0

उदाहरण के बारे में समेकित होने के संबंध में, क्या आपके पास यह सुझाव है कि यह निर्धारित करने के लिए कि कौन से गुण वास्तव में प्रदान किए गए थे 'ReadAsynyn'' के लिए एक एकल कॉल का उपयोग कर? –

+0

मुझे यकीन नहीं है कि यहां "गुण" से आपका क्या मतलब है। लेकिन अगर आपका मतलब है कि आप बस यह निर्धारित करने की कोशिश कर रहे हैं कि किस प्रकार की वस्तु प्रदान की गई थी, तो मुझे ऐसा लगता है कि इसे संदर्भ द्वारा परिभाषित किया जाना चाहिए। दुर्भाग्यवश, इस प्रश्न में कोई संदर्भ नहीं है, इसलिए मैं वास्तव में कोई सलाह नहीं दे सकता कि यह कैसे काम कर सकता है। –

+0

गुणों से मेरा मतलब है कि मैं जानना चाहता हूं कि मेरे मॉडल के कौन से गुण वास्तव में अनुरोध में सबमिट किए गए थे, क्योंकि यह संभव है कि उनमें से केवल एक सबसेट को अपडेट किया जा सके। हालांकि यह व्याख्या नहीं करता है कि क्यों 'ReadAsynyn' विफल रहता है, बाइट सरणी के रूप में पढ़ने के लिए आपका सुझाव और स्पष्ट रूप से फ़ॉर्मेटर्स का उपयोग करके पढ़ने के लिए अपेक्षित कार्य करता है। धन्यवाद। –

5

@ पीटर सही है। यदि आप बार-बार पढ़ना चाहते हैं, तो आप शायद स्ट्रीम के रूप में पढ़ना चाहेंगे और हर बार स्ट्रीम पढ़ने के लिए शुरुआत करना चाहते हैं। लेकिन फिर यदि आप करना चाहते हैं तो अब आप क्या करना चाहते हैं, लेकिन दूसरे पढ़ने के काम को प्राप्त करें, आप पहले पढ़ने के बाद, स्ट्रीम की शुरुआत की तलाश कर सकते हैं।

await httpContent.LoadIntoBufferAsync(); 
var X = await httpContent.ReadAsAsync<T>(); 

Stream stream = await httpContent.ReadAsStreamAsync(); 
stream.Seek(0, SeekOrigin.Begin); 

var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>(); 
+1

दिलचस्प। तो 'ReadAsStreamAsync()' द्वारा वापस 'स्ट्रीम' वास्तव में डेटा के लिए अंतर्निहित धारा है? और उस स्ट्रीम की तलाश वास्तव में 'HttpContent' ऑब्जेक्ट से डेटा तक पहुंचने की किसी भी अन्य विधि को प्रभावित करती है? निश्चित रूप से अच्छा होगा अगर माइक्रोसॉफ्ट _document_ होगा। जैसा कि है, यह "कार्यान्वयन रिसाव" का थोड़ा सा गंध करता है और मुझे चिंता है कि तकनीक भविष्य में टूट सकती है।:( –

+0

+1 यह एक दिलचस्प अवलोकन है। मुझे आश्चर्य है, लेकिन कोशिश नहीं की गई है, अगर कार्यान्वयन अनुरोध से अनुक्रमिक रूप से कई प्रकारों को पढ़ने का समर्थन करना चाहता है (पूरे अनुरोध को विभिन्न प्रकार के रूप में पढ़ने के बजाय)। अनुरोध धारा हो सकती है [टाइप ए] का एक अनुक्रम [टाइप बी] [टाइप सी] ... –

+2

उन लोगों के लिए जो तलाश के बारे में चिंतित हैं: "हालांकि, यदि आप कई बार सामग्री को पढ़ने में सक्षम होना चाहते हैं तो आप LoadIntoBufferAsync विधि का उपयोग कर सकते हैं यह सामग्री को आंतरिक बफर में पढ़ने का कारण बन जाएगा ताकि यह नेटवर्क पर फिर से इसे पुनः प्राप्त किए बिना कई बार उपभोग कर सके। "(स्रोत: https://blogs.msdn.microsoft.com/henrikn/2012/02/17/httpclient-download-to-a-local-file /) –

4

मैं इस के लिए एक काम कर समाधान मिल गया, लेकिन यह ReadAsync का अधिभार कि स्पष्ट रूप से मीडिया formatters की एक सूची लेता है उपयोग करने के लिए की आवश्यकता है। यह एक बुरा हैक के रूप में बहुत सुंदर दिखता है लेकिन यह काम करता है।

वास्तव में, HttpContent हुड के नीचे एक धारा के रूप में कार्य करता है, और एक बार जब यह फ़ॉर्मेटर द्वारा पढ़ा जाता है, तो यह स्वचालित रूप से रिवाइंड नहीं होता है। लेकिन मैनुअल रिवाइंड करने का एक तरीका है, और यहां यह किया जा सकता है कि यह कैसे किया जा सकता है।

सबसे पहले, इस प्रकार मीडिया प्रकार formatters के लिए एक डेकोरेटर बनाएँ:

public class RewindStreamFormatterDecorator : MediaTypeFormatter 
{ 
    private readonly MediaTypeFormatter formatter; 

    public RewindStreamFormatterDecorator(MediaTypeFormatter formatter) 
    { 
     this.formatter = formatter; 

     this.SupportedMediaTypes.Clear(); 
     foreach(var type in formatter.SupportedMediaTypes) 
      this.SupportedMediaTypes.Add(type); 

     this.SupportedEncodings.Clear(); 
     foreach(var encoding in formatter.SupportedEncodings) 
      this.SupportedEncodings.Add(encoding); 
    } 

    public override bool CanReadType(Type type) 
    { 
     return formatter.CanReadType(type); 
    } 

    public override Task<object> ReadFromStreamAsync(
     Type type, 
     Stream readStream, 
     HttpContent content, 
     IFormatterLogger formatterLogger, 
     CancellationToken cancellationToken) 
    { 
     var result = formatter.ReadFromStreamAsync 
      (type, readStream, content, formatterLogger, cancellationToken); 
     readStream.Seek(0, SeekOrigin.Begin); 
     return result; 
    } 

    //There are more overridable methods but none seem to be used by ReadAsAsync 
} 

दूसरा, सजाया formatters की एक सूची के लिए formatters की सूची परिवर्तित:

formatters = formatters.Select(f => new RewindStreamFormatterDecorator(f)).ToArray(); 

... और अब आप ReadAsAsync रूप में कई बार आह्वान कर सकते हैं आप चाहते हैं:

var X = await httpContent.ReadAsAsync<T>(formatters); 
var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>(formatters); 

मैं इस solut इस्तेमाल किया आयन एक कस्टम मॉडल बाइंडर में है इसलिए मुझे HttpParameterDescriptor के उदाहरण से फ़ॉर्मेटर्स संग्रह मिला है जो कि कन्स्ट्रक्टर को पास किया गया है। आप शायद कहीं निष्पादन संदर्भ में से हाथ में ऐसे ही एक संग्रह है, लेकिन यदि नहीं, सिर्फ एक डिफ़ॉल्ट संग्रह में उसी तरह के रूप में ASP.NET करता है बनाने के लिए:

formatters = new MediaTypeFormatter[] 
{ 
    new JsonMediaTypeFormatter(), 
    new XmlMediaTypeFormatter(), 
    new FormUrlEncodedMediaTypeFormatter() 
}; 
2

आप एक स्ट्रिंग में सामग्री पढ़ना चाहिए, तो deserialize कि जो कुछ भी डेटाटाइप्स में आप की जरूरत:

var content = await httpContent.ReadAsString(); 

// read as first type 
var X = JsonConvert.DeserializeObject<T>(content); 

// read as second type 
var Y = JsonConvert.DeserializeObject<Dictionary<string, object>>(content); 

यह कोई मतलब सामग्री एसिंक्रोनस रूप से दो बार पढ़ने के लिए नहीं है।

+0

यह केवल तभी काम करता है जब आप पहले से जानते हैं कि JSON में सामग्री – Konamiman

+0

@ कोनामीमन यह सच है, धन्यवाद। अच्छा पकड़। –

संबंधित मुद्दे