using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc;
return Ok(new { title = model.Title, date = model.Date.ToString("yyyy/MM/dd"), photoCount = model.Photos.Count, photoSize = model.Photos.Sum(f => f.Length) }) } }
2.4. 執行結果
3. 大型檔案上傳
透過 IFormFile 上傳檔案,是由 ASP.NET Core 幫你控制緩衝記憶體,如果檔案太大或很頻繁耗用緩衝記憶體,當 ASP.NET Core 能使用的緩衝記憶體到達上限,它就會死給你看了。 所以,如果你的系統會有上傳大檔的需求,又或者是會很頻繁的上傳檔案,強烈建議改用串流的方式,自己實作寫入硬碟位置,避免 ASP.NET Core 幫你控制緩衝記憶體。
using System; using System.Globalization; using System.IO; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Net.Http.Headers;
namespaceMyWebsite { publicstaticclassFileStreamingHelper { privatestaticreadonly FormOptions _defaultFormOptions = new FormOptions();
publicstaticasync Task<FormValueProvider> StreamFile(this HttpRequest request, Func<FileMultipartSection, Stream> createStream) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { thrownew Exception($"Expected a multipart request, but got {request.ContentType}"); }
// 把 request 中的 Form 依照 Key 及 Value 存到此物件 var formAccumulator = new KeyValueAccumulator();
var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body);
var section = await reader.ReadNextSectionAsync(); while (section != null) { // 把 Form 的欄位內容逐一取出 ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { // 若此欄位是檔案,就寫入至 Stream; using (var targetStream = createStream(section.AsFileSection())) { await section.Body.CopyToAsync(targetStream); } } elseif (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // 若此欄位不是檔案,就把 Key 及 Value 取出,存入 formAccumulator var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { varvalue = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value);
// 取得 Form 的下一個欄位 section = await reader.ReadNextSectionAsync(); }
// Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture);
return formValueProvider; }
privatestatic Encoding GetEncoding(MultipartSection section) { MediaTypeHeaderValue mediaType; var hasMediaTypeHeader = MediaTypeHeaderValue.TryParse(section.ContentType, out mediaType); // UTF-7 is insecure and should not be honored. UTF-8 will succeed in // most cases. if (!hasMediaTypeHeader || Encoding.UTF7.Equals(mediaType.Encoding)) { return Encoding.UTF8; } return mediaType.Encoding; } } }