Last active
October 28, 2019 11:28
-
-
Save Legends/5f458941913a7546f16adc5756e8a9a6 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // UploadController Action: | |
| [HttpPost] | |
| [DisableFormValueModelBinding] | |
| [ValidateAntiForgeryToken] | |
| [DisableRequestSizeLimit] | |
| public async Task<IActionResult> UploadPhysicalStreamed() | |
| { | |
| if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) | |
| { | |
| ModelState.AddModelError("File", $"The request couldn't be processed (Error 1)."); | |
| // Log error | |
| return BadRequest(ModelState); | |
| } | |
| var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), | |
| _defaultFormOptions.MultipartBoundaryLengthLimit); | |
| var reader = new MultipartReader(boundary, HttpContext.Request.Body); | |
| var section = await reader.ReadNextSectionAsync(); | |
| while (section != null) | |
| { | |
| var hasContentDispositionHeader = | |
| ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); | |
| if (hasContentDispositionHeader) | |
| { | |
| // This check assumes that there's a file | |
| // present without form data. If form data | |
| // is present, this method immediately fails | |
| // and returns the model error. | |
| if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) | |
| { | |
| ModelState.AddModelError("File", $"The request couldn't be processed (Error 2)."); | |
| // Log error | |
| return BadRequest(ModelState); | |
| } | |
| else | |
| { | |
| // Don't trust the file name sent by the client. To display | |
| // the file name, HTML-encode the value. | |
| var trustedFileNameForDisplay = WebUtility.HtmlEncode(contentDisposition.FileName.Value); | |
| var trustedFileNameForFileStorage = Path.GetRandomFileName(); | |
| if (!ModelState.IsValid) | |
| { | |
| return BadRequest(ModelState); | |
| } | |
| using (var targetStream = System.IO.File.Create(Path.Combine(_targetFilePath, trustedFileNameForFileStorage))) | |
| { | |
| //await targetStream.WriteAsync(streamedFileContent); | |
| await section.Body.CopyToAsync(targetStream); | |
| _logger.LogInformation( | |
| "Uploaded file '{TrustedFileNameForDisplay}' saved to " + | |
| "'{TargetFilePath}' as {TrustedFileNameForFileStorage}", | |
| trustedFileNameForDisplay, _targetFilePath, | |
| trustedFileNameForFileStorage); | |
| } | |
| } | |
| } | |
| // Drain any remaining section body that hasn't been consumed and | |
| // read the headers for the next section. | |
| section = await reader.ReadNextSectionAsync(); | |
| }// end while loop | |
| return Created(nameof(StreamingController), null); | |
| } | |
| // Resource FIlter Attribute | |
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | |
| public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter | |
| { | |
| public void OnResourceExecuting(ResourceExecutingContext context) | |
| { | |
| var factories = context.ValueProviderFactories; | |
| factories.RemoveType<FormValueProviderFactory>(); | |
| factories.RemoveType<FormFileValueProviderFactory>(); | |
| factories.RemoveType<JQueryFormValueProviderFactory>(); | |
| } | |
| public void OnResourceExecuted(ResourceExecutedContext context) | |
| { | |
| } | |
| } | |
| // Upload-Ajax-View.cshtml -without progress | |
| @page | |
| @model StreamedSingleFileUploadPhysicalModel | |
| @{ | |
| ViewData["Title"] = "Streamed Single File Upload with AJAX (Physical)"; | |
| } | |
| <h1>Stream a file with AJAX to physical storage with a controller endpoint</h1> | |
| <p>The following form's <code>action</code> points to a controller endpoint that only recieves the file and saves it to disk. If additional form data is added to the form, the additional data is ignored by the controller action.</p> | |
| <form id="uploadForm" action="Streaming/UploadPhysical" method="post" | |
| enctype="multipart/form-data" onsubmit="AJAXSubmit(this);return false;"> | |
| <dl> | |
| <dt> | |
| <label for="file">File</label> | |
| </dt> | |
| <dd> | |
| <input id="file" type="file" name="file" /> | |
| </dd> | |
| </dl> | |
| <input class="btn" type="submit" value="Upload" /> | |
| <div style="margin-top:15px"> | |
| <output form="uploadForm" name="result"></output> | |
| </div> | |
| </form> | |
| @section Scripts { | |
| <script> | |
| "use strict"; | |
| async function AJAXSubmit (oFormElement) { | |
| const formData = new FormData(oFormElement); | |
| try { | |
| const response = await fetch(oFormElement.action, { | |
| method: 'POST', | |
| headers: { | |
| 'RequestVerificationToken': getCookie('RequestVerificationToken') | |
| }, | |
| body: formData | |
| }); | |
| oFormElement.elements.namedItem("result").value = 'Result: ' + response.status + ' ' + response.statusText; | |
| } catch (error) { | |
| console.error('Error:', error); | |
| } | |
| } | |
| function getCookie(name) { | |
| var value = "; " + document.cookie; | |
| var parts = value.split("; " + name + "="); | |
| if (parts.length == 2) return parts.pop().split(";").shift(); | |
| } | |
| </script> | |
| } | |
| // Upload script updated to show upload progress (upload progress currently not supported on fetch, but download progress is!) | |
| @section Scripts { | |
| <script> | |
| "use strict"; | |
| function AJAXSubmit(thisForm) { | |
| const formData = new FormData(thisForm); | |
| var xhr = new XMLHttpRequest(); | |
| xhr.onload = function (e) { | |
| if (xhr.readyState === 4) { | |
| if (xhr.status === 200) { | |
| console.log(xhr.responseText); | |
| } else { | |
| console.error(xhr.statusText); | |
| } | |
| } | |
| }; | |
| xhr.upload.addEventListener("progress", updateProgress); | |
| xhr.onerror = function (e) { | |
| console.error(xhr.statusText); | |
| }; | |
| xhr.open("POST", thisForm.action, true); | |
| xhr.setRequestHeader("RequestVerificationToken", getCookie('RequestVerificationToken')); | |
| xhr.send(formData); | |
| } | |
| // progress on transfers from the server to the client (downloads) | |
| function updateProgress(oEvent) { | |
| if (oEvent.lengthComputable) { | |
| var percentComplete = oEvent.loaded / oEvent.total * 100; | |
| console.log("percentComplete: " + percentComplete); | |
| // ... | |
| } else { | |
| // Unable to compute progress information since the total size is unknown | |
| console.log("Unable to compute progress information since the total size is unknown"); | |
| } | |
| } | |
| function getCookie(name) { | |
| var value = "; " + document.cookie; | |
| var parts = value.split("; " + name + "="); | |
| if (parts.length == 2) return parts.pop().split(";").shift(); | |
| } | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment