Created
March 22, 2019 01:59
-
-
Save zhengchun/1ae317ee3fb623da4ae3fd9faa52d6a0 to your computer and use it in GitHub Desktop.
ASP.NET fast upload file to AWS using multipart/form-data without take memory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | |
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter | |
{ | |
public void OnResourceExecuting(ResourceExecutingContext context) | |
{ | |
var factories = context.ValueProviderFactories; | |
factories.RemoveType<FormValueProviderFactory>(); | |
factories.RemoveType<JQueryFormValueProviderFactory>(); | |
} | |
public void OnResourceExecuted(ResourceExecutedContext context) | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form action="upload" method="post" enctype="multipart/form-data"> | |
<input type="file" name="file" /> | |
<input type="submit" value="Upload" /> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UploadController : Controller | |
{ | |
[HttpPost] | |
[DisableFormValueModelBinding] | |
public async Task<IActionResult> Index() | |
{ | |
if (!MediaTypeHeaderValue.TryParse(Request.ContentType, out var mt) || | |
!mt.MediaType.Equals("multipart/form-data", StringComparison.OrdinalIgnoreCase)) | |
{ | |
return BadRequest(); | |
} | |
var boundary = HeaderUtilities.RemoveQuotes(mt.Boundary); | |
var multipartReader = new MultipartReader(boundary.ToString(), Request.Body); | |
var section = await multipartReader.ReadNextSectionAsync(HttpContext.RequestAborted); | |
if (section == null) | |
{ | |
return BadRequest($"No found any multipart section data."); | |
} | |
if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition) || | |
!contentDisposition.IsFileDisposition()) | |
{ | |
return BadRequest(); | |
} | |
// Geting current position in request body. | |
var bufferOffsetield = typeof(BufferedReadStream).GetField("_bufferOffset", BindingFlags.NonPublic | BindingFlags.Instance); | |
var innerStreamField = section.Body.GetType().GetField("_innerStream", BindingFlags.NonPublic | BindingFlags.Instance); | |
var bufferedReadStream = innerStreamField.GetValue(section.Body); | |
var offset = (int)bufferOffsetield.GetValue(bufferedReadStream); | |
// the last line of boundary. | |
var discardLength = "\r\n--".Length + boundary.Length + "--\r\n".Length; | |
var fileLength = Request.ContentLength.Value - offset - discardLength; | |
// Upload file to AWS3 Using a Presigned URL feature. | |
// https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLDotNetSDK.html | |
var endpointUrl = CreatePreSignedURL(contentDisposition.FileName.ToString()); | |
var request = new HttpRequestMessage(HttpMethod.Put, endpointUrl); | |
request.Content = new StreamContent(section.Body); | |
request.Content.Headers.ContentLength = fileLength; | |
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); | |
var response = await new HttpClient().SendAsync(request); | |
if (response.StatusCode != System.Net.HttpStatusCode.OK) | |
{ | |
throw new AmazonS3Exception($"Upload file failed.{response.StatusCode}."); | |
} | |
return Ok(); | |
} | |
private string CreatePreSignedURL(string key) | |
{ | |
var request = new GetPreSignedUrlRequest() | |
{ | |
BucketName = "BucketName", | |
Key = key, | |
Verb = HttpVerb.PUT, | |
Expires = DateTime.Now.AddMinutes(5), | |
}; | |
return new AmazonS3Client().GetPreSignedURL(request); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uploading large files with streaming