2016-04-05 20 views
25

Khi tôi tải các tệp lớn lên api web của mình trong ASP.NET Core, thời gian chạy sẽ tải tệp vào bộ nhớ trước khi chức năng xử lý và lưu trữ tải lên được kích hoạt . Với tải lên lớn, điều này trở thành một vấn đề vì nó chậm và đòi hỏi nhiều bộ nhớ hơn. Đối với các phiên bản trước của ASP.NET there are some articles về cách vô hiệu hóa việc đệm yêu cầu, nhưng tôi không thể tìm thấy bất kỳ thông tin nào về cách thực hiện việc này với ASP.NET Core. Là nó có thể vô hiệu hóa các bộ đệm của yêu cầu vì vậy tôi không chạy ra khỏi bộ nhớ trên máy chủ của tôi tất cả các thời gian?Xử lý các tệp tải lên lớn trên ASP.NET Core 1.0

+0

Tôi viết phụ đề tải lên tệp của mình để hỗ trợ tải lên tệp theo các phần nhỏ theo api cho [flowjs] (https://github.com/flowjs/flow.js) – jltrem

+0

Xin chào @jltrem, bạn có thể chia sẻ lõi asp.net không điều khiển và mã góc xử lý các tệp được tải lên bằng flowjs? –

Trả lời

18

Sử dụng Microsoft.AspNetCore.WebUtilities.MultipartReader vì nó ...

có thể phân tích bất kỳ dòng [với] đệm tối thiểu. Nó cung cấp cho bạn các tiêu đề và phần thân của mỗi phần tại một thời điểm và sau đó bạn làm những gì bạn muốn với phần thân của phần đó (bộ đệm, loại bỏ, ghi vào đĩa, vv).

Đây là ví dụ trung gian.

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

Dưới đây là những người trợ giúp.

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

Tài liệu tham khảo bên ngoài

+1

Có vẻ như mã này hoạt động hoàn hảo trên dnx451 nhưng nó có rò rỉ bộ nhớ trên dnxcore50. Có thể là một cái gì đó đang được cố định cho RC2 mặc dù. – Martin

+1

GetFileName() từ đoạn mã trên làm cho máy chủ đệm toàn bộ tệp. Tôi thay thế nó bằng tên tập tin ngẫu nhiên, nhưng sau khi viết tất cả các khối để tập tin tôi thấy rằng việc sử dụng bộ nhớ tăng lên bởi số tiền bằng với kích thước tập tin. Nó có thể được thực sự ok, nếu GC tiếp tục sẽ thoát khỏi nó. Nhưng có vẻ như không ok – EvAlex

+0

@EvAlex 'GetFileName' chỉ phân tích một chuỗi. Có cái gì khác đang xảy ra trước hoặc sau đó có thể gây ra các máy chủ để đệm toàn bộ tập tin? –

2

Trong bạn Controller bạn chỉ có thể sử dụng Request.Form.Files để truy cập các tập tin:

[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(); 
} 
Các vấn đề liên quan