2012-11-23 18 views
6

से सभी बाइट्स नहीं पढ़ता है मेरे पास एक वेबसाइट है जो मेरी वेबसाइट पर एक एएसपी.Net वेब एपीआई स्थापित है जिसका उपयोग WPF डेस्कटॉप एप्लिकेशन के साथ संवाद करने के लिए किया जाता है। मेरे पास क्लाइंट एप्लिकेशन से बाइनरी फाइलें प्राप्त करने के लिए एपीआई पर एक एक्शन सेटअप है। हालांकि कुछ (प्रतीत होता है यादृच्छिक) मामलों में जब मुझे अनुरोध से सभी बाइट मिलते हैं तो सभी बाइट पढ़े नहीं जाते हैं। उम्मीद है कि आप मुझे इस तरह से ऐसा करने का विचार दे सकते हैं कि हर समय काम करेगा।एएसपी.Net वेब एपीआई स्ट्रीमकंटेंट

क्लाइंट साइड: कोड यह

public static SubmitTurnResult SubmitTurn(int turnId, Stream fileStream) 
{ 
    HttpClient client = CreateHttpClient(); 

    HttpContent content = new StreamContent(fileStream); 
    content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
    content.Headers.ContentDisposition.FileName = "new-turn.Civ5Save"; 
    content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
    content.Headers.ContentLength = fileStream.Length; 

    HttpResponseMessage response = client.PostAsync(
     string.Format("SubmitTurn?authKey={0}&turnId={1}", 
         LocalSettings.Instance.AuthenticationKey, 
         turnId 
         ), 
     content 
    ).Result; 

    response.EnsureSuccessStatusCode(); 

    return response.Content.ReadAsAsync<SubmitTurnResult>().Result; 
} 

SubmitTurnResult एक enum कि सर्वर पर परिणाम को परिभाषित करता है, turnId इकाई इस फ़ाइल से जुड़ा हुआ है के लिए आईडी है, और फ़ाइलस्ट्रीम एक वास्तविक फ़ाइलस्ट्रीम डिस्क के बाइट्स को पढ़ रहा है।

सर्वर साइड:

[HttpGet, HttpPost] 
public SubmitTurnResult SubmitTurn(string authKey, int turnId) 
{ 

    try 
    { 
     bool worked = false; 
     int gameId = 0; 

     using (GmrEntities gmrDb = new GmrEntities()) 
     { 
      var player = gmrDb.Users.FirstOrDefault(u => u.AuthKey == authKey); 
      if (player != null) 
      { 
       var turn = player.Turns.FirstOrDefault(t => t.TurnID == turnId); 
       if (turn != null) 
       { 
        byte[] saveFileBytes = null; 

        using (MemoryStream tempStream = new MemoryStream()) 
        { 
         var task = this.Request.Content.CopyToAsync(tempStream); 
         task.Wait(); 

         saveFileBytes = tempStream.ToArray(); 
         tempStream.Close(); 
        } 

        if (saveFileBytes.Length != this.Request.Content.Headers.ContentLength.Value) 
        { 
         throw new Exception(string.Format("Byte array length ({0}) not equal to HTTP content-length header ({1}). This is not good!", 
            saveFileBytes.Length, this.Request.Content.Headers.ContentLength.Value)); 
        } 

        worked = GameManager.SubmitTurn(turn, saveFileBytes, gmrDb); 

        if (worked) 
        { 
         gameId = turn.Game.GameID; 

         gmrDb.SaveChanges(); 
        } 
       } 
      } 
     } 


     return SubmitTurnResult.OK; 
    } 
    catch (Exception exc) 
    { 
     DebugLogger.WriteExceptionWithComments(exc, string.Format("Diplomacy: Sumbitting turn for turnId: {0}", turnId)); 

     return SubmitTurnResult.UnexpectedError; 
    } 
} 
+0

क्या यह 32-बिट विंडोज सर्वर 2003 या विंडोज एक्सपी पर था? हम StreamContent के साथ इसी व्यवहार में भाग रहे हैं, लेकिन जब Windows Server 2003 वेब API सेवा से प्रतिक्रिया स्ट्रीम करते हैं। यह 2008 में repro नहीं करता है। साथ ही, हमने पाया है कि यह केवल एक फ़ाइलस्ट्रीम के साथ repros। फ़ाइलस्ट्रीम को मेमोरीस्ट्रीम में कनवर्ट करना समस्या को छोड़ देता है (पाठ्यक्रम की स्मृति के खर्च पर)। हमने पाया है कि जब प्रतिक्रिया धारा जल्दी समाप्त हो जाती है, तो यह हमेशा 4096-बाइट सीमा पर होती है, और यह लगभग 3.5 एमबी पर कैप हिट करती है। –

उत्तर

11

मेरी पिछली टिप्पणी में बताया गया है, हम StreamContent के साथ इस एक ही व्यवहार में भाग है, लेकिन जब एक Windows Server 2003 वेब एपीआई सेवा से एक प्रतिक्रिया स्ट्रीमिंग। यह 2008 पर repro नहीं करता है। दरअसल, यह विंडोज सर्वर 2008 पर भी repros अगर मैं वीएम को एक छोटी राशि रैम (712 एमबी) के साथ कॉन्फ़िगर करता है, लेकिन 4 जीबी रैम के साथ यह repro नहीं करता है। साथ ही, हमने पाया कि यह केवल एक फ़ाइलस्ट्रीम के साथ repros। फ़ाइलस्ट्रीम को मेमोरीस्ट्रीम में कनवर्ट करना समस्या को छोड़ देता है (पाठ्यक्रम की स्मृति के खर्च पर)। हमने पाया कि जब प्रतिक्रिया धारा जल्दी समाप्त हो जाती है, तो यह हमेशा 4096-बाइट सीमा पर होती है, और यह लगभग 3.5 एमबी पर कैप हिट करती है।

public static SubmitTurnResult SubmitTurn(int turnId, Stream fileStream) 
{ 
    HttpClient client = CreateHttpClient(); 

    var memoryStream = new MemoryStream((int)fileStream.Length); 
    fileStream.CopyTo(memoryStream); 
    fileStream.Close(); 
    memoryStream.Seek(0, SeekOrigin.Begin); 
    HttpContent content = new StreamContent(memoryStream); 

अगर वांछित, आप सशर्त MemoryStream कॉपी केवल जब स्ट्रीम एक FileStream है कर सकते हैं:

यहाँ वैकल्पिक हल है कि मेरे लिए चीजें तय, अपने कोड उदाहरण के अनुरूप है।

+0

आपके सुझाव के लिए धन्यवाद, दुर्भाग्य से यह मेरे लिए इस मुद्दे को हल नहीं करता है। कोड का क्लाइंट हिस्सा WinXP से Win8.1 तक सैकड़ों मशीनों पर चल रहा है और मैंने इसे फ़ाइलस्ट्रीम के बजाय मेमोरीस्ट्रीम का उपयोग करने के लिए बदल दिया है। इसका सर्वर हिस्सा WinServer 2012R2 पर चल रहा है। मुझे अब भी समस्या का अनुभव है और फिर सर्वर द्वारा सामग्री स्ट्रीम से पढ़ने वाले बाइट्स की मात्रा क्लाइंट = \ –

+0

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