2016-04-05 12 views
25

पर बड़ी फ़ाइल अपलोड से निपटने के दौरान जब मैं एएसपी.नेट कोर में अपने वेब एपीआई में बड़ी फाइलें अपलोड कर रहा हूं, तो रनटाइम फाइल को प्रसंस्करण और भंडारण के लिए मेरे फ़ंक्शन से पहले स्मृति में लोड करेगा । बड़े अपलोड के साथ यह एक मुद्दा बन जाता है क्योंकि यह धीमा है और अधिक स्मृति की आवश्यकता है। अनुरोधों के बफरिंग को अक्षम करने के तरीके पर ASP.NET there are some articles के पिछले संस्करणों के लिए, लेकिन मुझे एएसपी.NET कोर के साथ ऐसा करने के तरीके के बारे में कोई जानकारी नहीं मिल रही है। क्या अनुरोधों के बफरिंग को अक्षम करना संभव है, इसलिए मैं हर समय अपने सर्वर पर स्मृति से बाहर नहीं निकलता?एएसपी.नेट कोर 1.0

+0

मैं [fljs] (https://github.com/flowjs/flow.js) – jltrem

+0

हैलो @jltrem के लिए एपीआई के अनुसार छोटे भाग में फ़ाइलों को अपलोड करने के समर्थन के लिए अपनी फ़ाइल अपलोड बैकएंड लिखता हूं, क्या आप एएसपीनेट कोर साझा कर सकते हैं नियंत्रक और कोणीय कोड जो फ़्लोज का उपयोग करके अपलोड की गई फ़ाइलों को संभालता है? –

उत्तर

18

उपयोग Microsoft.AspNetCore.WebUtilities.MultipartReader क्योंकि यह ...

न्यूनतम बफरिंग [साथ] किसी भी स्ट्रीम पार्स कर सकते हैं। यह आपको एक समय में प्रत्येक अनुभाग के शीर्षलेख और शरीर देता है और फिर आप उस खंड के शरीर (बफर, त्याग, डिस्क पर लिखने आदि) के साथ जो चाहते हैं वह करते हैं।

यहां एक मिडलवेयर उदाहरण है।

app.Use(async (context, next) => 
{ 
    if (!IsMultipartContentType(context.Request.ContentType)) 
    { 
     await next(); 
     return; 
    } 

    var boundary = GetBoundary(context.Request.ContentType); 
    var reader = new MultipartReader(boundary, context.Request.Body); 
    var section = await reader.ReadNextSectionAsync(); 

    while (section != null) 
    { 
     // process each image 
     const int chunkSize = 1024; 
     var buffer = new byte[chunkSize]; 
     var bytesRead = 0; 
     var fileName = GetFileName(section.ContentDisposition); 

     using (var stream = new FileStream(fileName, FileMode.Append)) 
     { 
      do 
      { 
       bytesRead = await section.Body.ReadAsync(buffer, 0, buffer.Length); 
       stream.Write(buffer, 0, bytesRead); 

      } while (bytesRead > 0); 
     } 

     section = await reader.ReadNextSectionAsync(); 
    } 

    context.Response.WriteAsync("Done."); 
}); 

यहां सहायक हैं।

private static bool IsMultipartContentType(string contentType) 
{ 
    return 
     !string.IsNullOrEmpty(contentType) && 
     contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0; 
} 

private static string GetBoundary(string contentType) 
{ 
    var elements = contentType.Split(' '); 
    var element = elements.Where(entry => entry.StartsWith("boundary=")).First(); 
    var boundary = element.Substring("boundary=".Length); 
    // Remove quotes 
    if (boundary.Length >= 2 && boundary[0] == '"' && 
     boundary[boundary.Length - 1] == '"') 
    { 
     boundary = boundary.Substring(1, boundary.Length - 2); 
    } 
    return boundary; 
} 

private string GetFileName(string contentDisposition) 
{ 
    return contentDisposition 
     .Split(';') 
     .SingleOrDefault(part => part.Contains("filename")) 
     .Split('=') 
     .Last() 
     .Trim('"'); 
} 

बाहरी संदर्भ

+1

ऐसा प्रतीत होता है कि यह कोड पूरी तरह से dnx451 पर काम करता है लेकिन इसमें dnxcore50 पर मेमोरी लीक है। कुछ ऐसा हो सकता है जो आरसी 2 के लिए तय किया जा रहा हो। उपरोक्त स्निपेट से – Martin

+1

GetFileName() सर्वर को पूरी फ़ाइल को बफर करने का कारण बनता है। मैंने इसे यादृच्छिक फ़ाइल नाम से बदल दिया, लेकिन फ़ाइल में सभी हिस्सों को लिखने के बाद मुझे लगता है कि मेमोरी उपयोग फ़ाइल आकार के बराबर राशि के अनुसार बढ़ गया है। यह वास्तव में ठीक हो सकता है, अगर आगे जीसी इससे छुटकारा पायेगा। लेकिन ठीक नहीं लगता है – EvAlex

+0

@EvAlex 'GetFileName' बस एक स्ट्रिंग को पार करता है। क्या ऐसा कुछ और है जो पहले या बाद में हो रहा है जिससे सर्वर पूरी फाइल को बफर कर सकता है? कोड साझा करने के लिए –

2

में अपने Controller आप बस फ़ाइलों तक पहुँचने की Request.Form.Files उपयोग कर सकते हैं:

[HttpPost("upload")] 
public async Task<IActionResult> UploadAsync(CancellationToken cancellationToken) 
{ 
    if (!Request.HasFormContentType) 
     return BadRequest(); 

    var form = Request.Form; 
    foreach(var formFile in form.Files) 
    { 
     using(var readStream = formFile.OpenReadStream()) 
     { 
      // Do something with the uploaded file 
     } 
    } 


    return Ok(); 
} 
संबंधित मुद्दे