public async Task <IActionResult> upload() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } StringValues UserName; SiteConfig.HttpContextAccessor.HttpContext.Request.Headers.TryGetValue("UName", out UserName); // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); // string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); var uploadPath = SiteConfig.Environment.ContentRootPath + UtilityBLL.ParseUsername(DirectoryPaths.UserVideosDefaultDirectoryPath, UserName.ToString()); if (!Directory.Exists(uploadPath)) { Directory_Process.CreateRequiredDirectories(SiteConfig.Environment.ContentRootPath + UtilityBLL.ParseUsername(SystemDirectoryPaths.UserDirectory, UserName.ToString())); } /*if (!Directory.Exists(uploadPath)) * { * return Ok(new { jsonrpc = "2.0", result = "Error", fname = uploadPath, message = "Main Directory Not Exist" }); * } * * if (!Directory.Exists(uploadPath + "default/")) * { * return Ok(new { jsonrpc = "2.0", result = "Error", fname = uploadPath + "default/", message = "Default Directory Not Exist" }); * }*/ var fileName = ""; try { while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { var output = formAccumulator.GetResults(); var chunk = "0"; foreach (var item in output) { if (item.Key == "name") { fileName = item.Value; } else if (item.Key == "chunk") { chunk = item.Value; } } var Path = uploadPath + "" + fileName; using (var fs = new FileStream(Path, chunk == "0" ? FileMode.Create : FileMode.Append)) { await section.Body.CopyToAsync(fs); fs.Flush(); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } var result = formAccumulator.GetResults(); // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } } catch (Exception ex) { return(Ok(new { jsonrpc = "2.0", result = "Error", fname = uploadPath, message = ex.Message })); } string url = VideoUrlConfig.Source_Video_Url(UserName.ToString()) + "/" + fileName; string fileType = System.IO.Path.GetExtension(fileName); string fileIndex = fileName.Replace(fileType, ""); return(Ok(new { jsonrpc = "2.0", result = "OK", fname = fileName, url = url, filetype = fileType, filename = fileName, fileIndex = fileIndex })); }
public static async Task <string> StreamFilesAsync(this HttpRequest request, string directory) { string result = "0"; if (!UpFileValidation.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } //用于累加请求中所有表单url编码的键值对数量。 KeyValueAccumulator formAccumulator = new KeyValueAccumulator(); //获取请求的ContentType并model化 MediaTypeHeaderValue contentType = MediaTypeHeaderValue.Parse(request.ContentType); //表单默认的分界线最大长度 int boundaryLength = _FormOptions.MultipartBoundaryLengthLimit; //验证并得到分界线 var boundary = UpFileValidation.GetBoundary(contentType, boundaryLength); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync();//用于读取Http请求中的第一个section数据 while (section != null) { ContentDispositionHeaderValue content; var isHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out content); if (isHeader) { //文件数据处理 if (UpFileValidation.IsFormFile(content)) { Dictionary <string, StringValues> dic = formAccumulator.GetResults(); string filepath = dic["filepath"]; string fileMd5 = dic["fileMd5"]; string chunk = dic["chunk"]; string chunks = dic["chunks"]; string save_filepath = directory + "\\" + filepath + "\\" + fileMd5; if (!Directory.Exists(save_filepath)) { Directory.CreateDirectory(save_filepath); } var fileName = UpFileValidation.GetFileName(content); //这个是每一次从Http请求的section中读出文件数据的大小,单位是Byte即字节,这里设置为1024的意思是, //每次从Http请求的section数据流中读取出1024字节的数据到服务器内存中,然后写入下面targetFileStream的文件流中 //,可以根据服务器的内存大小调整这个值。这样就避免了一次加载所有上传文件的数据到服务器内存中,导致服务器崩溃。 var loadBufferBytes = 10 * 1024 * 1024; using (var targetFileStream = System.IO.File.Create(save_filepath + "\\" + chunk)) { await section.Body.CopyToAsync(targetFileStream, loadBufferBytes); result = "1"; } } //额外表单参数处理 else if (UpFileValidation.IsFormData(content)) { // 这里不要限制键名的长度,因为多部分头的长度限制已经生效。 var key = HeaderUtilities.RemoveQuotes(content.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // 获取键的值 var value = await streamReader.ReadToEndAsync(); //如果值为undefined,则替换为空 if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value, value); //参数键值对不能大于默认数量,否则异常 if (formAccumulator.ValueCount > _FormOptions.ValueCountLimit) { throw new InvalidDataException($"键值对参数最大不能超过{ _FormOptions.ValueCountLimit}"); } } } } //用于读取Http请求中的下一个section数据 section = await reader.ReadNextSectionAsync(); } return(result); }
public async Task <IActionResult> StreamUpload() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; 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) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); //_logger.LogInformation( $"Copied the uploaded file '{targetFilePath}'" ); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var requestedFileUpload = new FileUploadRequest(); var formValueProvider = new FormValueProvider(BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(requestedFileUpload, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } var uploadedData = new FileUploadRequestResult() { Name = requestedFileUpload.Name, Age = requestedFileUpload.Age, Zipcode = requestedFileUpload.Zipcode, FilePath = targetFilePath }; return(Json(uploadedData)); }
/// <summary> /// Handle multi-part form data file streams. /// </summary> public static async Task <string> StreamFile(this HttpRequest request, string filename, ILogger log) { var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var defaultFormOptions = new FormOptions(); // Boundary is required by the MultipartReader, but we'll auto generate one in the helper, it // doesn't need to be provided in the request header. var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(request.ContentType), defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); log.LogDebug("Processing file stream..."); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); var dispositionParameters = contentDisposition.Parameters.Aggregate("", (current, parameter) => $"{current},{parameter}"); log.LogDebug($"Processing section '{contentDisposition.DispositionType}:{dispositionParameters}'"); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.Combine(Path.GetTempPath(), filename); log.LogDebug($"Writing stream to '{targetFilePath}'"); using (var targetStream = File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Do not limit the key name length here because the multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = section.GetEncoding(); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } log.LogDebug("Completed processing request body."); return(targetFilePath); }
public static async Task <FormValueProvider> StreamFile(this HttpRequest request, Func <FileMultipartSection, Stream> createStream) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new 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); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // 若此欄位不是檔案,就把 Key 及 Value 取出,存入 formAccumulator var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // 取得 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); }
public async Task <IFormCollection> ReadFormAsync(CancellationToken cancellationToken) { if (Form != null) { return(Form); } if (!HasFormContentType) { throw new InvalidOperationException("Incorrect Content-Type: " + _request.ContentType); } cancellationToken.ThrowIfCancellationRequested(); _request.EnableRewind(); IDictionary <string, string[]> formFields = null; var files = new FormFileCollection(); // Some of these code paths use StreamReader which does not support cancellation tokens. using (cancellationToken.Register(_request.HttpContext.Abort)) { var contentType = ContentType; // Check the content-type if (HasApplicationFormContentType(contentType)) { var encoding = FilterEncoding(contentType.Encoding); formFields = await FormReader.ReadFormAsync(_request.Body, encoding, cancellationToken); } else if (HasMultipartFormContentType(contentType)) { var formAccumulator = new KeyValueAccumulator <string, string>(StringComparer.OrdinalIgnoreCase); var boundary = GetBoundary(contentType); var multipartReader = new MultipartReader(boundary, _request.Body); var section = await multipartReader.ReadNextSectionAsync(cancellationToken); while (section != null) { var headers = new HeaderDictionary(section.Headers); ContentDispositionHeaderValue contentDisposition; ContentDispositionHeaderValue.TryParse(headers.Get(HeaderNames.ContentDisposition), out contentDisposition); if (HasFileContentDisposition(contentDisposition)) { // Find the end await section.Body.DrainAsync(cancellationToken); var file = new FormFile(_request.Body, section.BaseStreamOffset.Value, section.Body.Length) { Headers = headers, }; files.Add(file); } else if (HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); MediaTypeHeaderValue mediaType; MediaTypeHeaderValue.TryParse(headers.Get(HeaderNames.ContentType), out mediaType); var encoding = FilterEncoding(mediaType?.Encoding); using (var reader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await reader.ReadToEndAsync(); formAccumulator.Append(key, value); } } else { System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + headers.Get(HeaderNames.ContentDisposition)); } section = await multipartReader.ReadNextSectionAsync(cancellationToken); } formFields = formAccumulator.GetResults(); } } Form = new FormCollection(formFields, files); return(Form); }
public async Task <IActionResult> Upload() { try { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; 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) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, true, 1024, true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > DefaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {DefaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } if (string.IsNullOrEmpty(targetFilePath) || !System.IO.File.Exists(targetFilePath)) { _logger.LogError("File not created!"); return(StatusCode(500, "Internal server error")); } // Import the file Stopwatch sw = new Stopwatch(); sw.Start(); await _fileImport.ImportAsync(targetFilePath); sw.Stop(); TimeSpan ts = sw.Elapsed; _logger.LogInformation(string.Format("Import run time: {0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)); return(Ok(true)); } catch (Exception ex) { _logger.LogError(ex.Message); return(StatusCode(500, "Internal server error")); } }
public async Task <IActionResult> Upload() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. string targetFilePath = null; string boundary = MediaTypeHeaderValue.Parse(Request.ContentType).GetBoundary(FormOptions.MultipartBoundaryLengthLimit); KeyValueAccumulator formAccumulator = new KeyValueAccumulator(); MultipartReader reader = new MultipartReader(boundary, HttpContext.Request.Body); MultipartSection section = await reader.ReadNextSectionAsync(); while (section != null) { bool hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition); if (hasContentDispositionHeader) { if (contentDisposition.HasFileContentDisposition()) { targetFilePath = Path.GetTempFileName(); await using (FileStream targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); } } else if (contentDisposition.HasFileContentDisposition()) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. StringSegment key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); Encoding encoding = GetEncoding(section); using (StreamReader streamReader = new StreamReader(section.Body, encoding, true, Constants.BUFFER_KB, true)) { // The value length limit is enforced by MultipartBodyLengthLimit string value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > FormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {FormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } if (string.IsNullOrWhiteSpace(targetFilePath)) { return(BadRequest("File could not be read or content disposition header is invalid.")); } FormValueProvider formValueProvider = new FormValueProvider(BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(await FileUploaded(targetFilePath, formValueProvider)); }
public static Dictionary <string, StringValues> ParseNullableQuery(string queryString, string ignoreTrimKey = "sign") { var accumulator = new KeyValueAccumulator(); if (string.IsNullOrEmpty(queryString) || queryString == "?") { return(null); } var scanIndex = 0; if (queryString[0] == '?') { scanIndex = 1; } var textLength = queryString.Length; var equalIndex = queryString.IndexOf('='); if (equalIndex == -1) { equalIndex = textLength; } while (scanIndex < textLength) { var delimiterIndex = queryString.IndexOf('&', scanIndex); if (delimiterIndex == -1) { delimiterIndex = textLength; } if (equalIndex < delimiterIndex) { while (scanIndex != equalIndex && char.IsWhiteSpace(queryString[scanIndex])) { ++scanIndex; } var name = queryString.Substring(scanIndex, equalIndex - scanIndex); var value = queryString.Substring(equalIndex + 1, delimiterIndex - equalIndex - 1); if (name == ignoreTrimKey) { accumulator.Append( Uri.UnescapeDataString(name), Uri.UnescapeDataString(value)); equalIndex = queryString.IndexOf('=', delimiterIndex); } else { accumulator.Append( Uri.UnescapeDataString(name), Uri.UnescapeDataString(value.Replace('+', ' '))); equalIndex = queryString.IndexOf('=', delimiterIndex); } if (equalIndex == -1) { equalIndex = textLength; } } else { if (delimiterIndex > scanIndex) { accumulator.Append(queryString.Substring(scanIndex, delimiterIndex - scanIndex), string.Empty); } } scanIndex = delimiterIndex + 1; } if (!accumulator.HasValues) { return(null); } return(accumulator.GetResults()); }
public DeviceFile() { formAccumulator = new KeyValueAccumulator(); memoryStream = new MemoryStream(); }
public async Task <IActionResult> Upload([FromRoute] string uploadName, [FromQuery(Name = "k")] string apiKeyQuery) { var apiKeys = HttpContext.Request.Headers["ApiKey"]; var apiKey = apiKeys.Count == 1 ? apiKeys[0] : apiKeyQuery; var uploader = _options.Uploader.FirstOrDefault( s => s.WebBasePath.Equals(uploadName, StringComparison.OrdinalIgnoreCase) && (s.ApiKey.Equals(apiKey) || string.IsNullOrEmpty(s.ApiKey))); if (uploader == null) { return(BadRequest("Uploader not found, invalid upload path or invalid API key.")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); string fileExtension = null; while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { fileExtension = Path.GetExtension(contentDisposition.FileName.Value).ToLower(); targetFilePath = Path.GetTempFileName(); if (!uploader.FileExtensions.Contains(fileExtension) && !uploader.FileExtensions.Contains("*")) { return(BadRequest( $"File does not meet the requirements. Invalid extension ({fileExtension}), allowed extensions: [{string.Join(", ", uploader.FileExtensions)}]")); } try { using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } } catch (Exception) { _logger.LogError("An error occured while streaming the File. Did the client cancel?"); DeleteFileIfExists(targetFilePath); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var model = new PostFileModel(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(model, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful && !ModelState.IsValid) { return(BadRequest(ModelState)); } var file = new FileInfo(targetFilePath ?? throw new InvalidOperationException()); if (!ValidateFileSize(uploader.MaxFileSize, file.Length)) { file.Delete(); return(BadRequest($"File does not meet the Requirements. Maximum size {uploader.MaxFileSize}MB.")); } Directory.CreateDirectory(uploader.LocalBasePath); var fileName = GetRandomFileName(fileExtension); var filePath = Path.Combine(uploader.LocalBasePath, fileName); var fileSize = file.Length; if (uploader.MaxFolderSize > 0) { if (fileSize > uploader.MaxFolderSize * 1024 * 1024) { file.Delete(); return(BadRequest("File bigger than max foldersize")); } while (GetDirectorySize(uploader.LocalBasePath) + fileSize > uploader.MaxFolderSize * 1024 * 1024) { DeleteOldestFile(uploader.LocalBasePath); } } while (System.IO.File.Exists(filePath)) { fileName = GetRandomFileName(fileExtension); filePath = Path.Combine(uploader.LocalBasePath, fileName); } file.MoveTo(filePath); if (uploader.ResponseType == ApiResponseType.Redirect) { return(LocalRedirect($"/{uploader.WebBasePath}/{fileName}")); } return(Ok(new ResultModel { FileUrl = ToAbsoluteUrl(Url.Content(uploader.WebBasePath + "/" + fileName)), DeleteUrl = ToAbsoluteUrl(Url.Action("Delete", "Uploader", new { uploadName = uploader.WebBasePath, fileName })) })); }
//[ValidateAntiForgeryToken] public async Task <IActionResult> Upload() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), DefaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var links = new List <string>(); var section = await reader.ReadNextSectionAsync(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { var url = await _imageUploadService.UploadImage(contentDisposition.FileName.Value, section.Body); links.Add(url); } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > DefaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {DefaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } return(Ok(links)); }
public async Task <ResultEntityBase> UploadVideo(CancellationToken cancellationToken) { var result = new ResultEntityBase(); var video = new Video(); if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { result.Status = CommonEntity.StatusCode.Error; result.Message = "请求数据类型出错"; return(await Task.FromResult(result)); } var formAccumulator = new KeyValueAccumulator(); string videoUid = Guid.NewGuid().ToString("N"); video.Uid = videoUid; video.State = 1; string targetFilePath = Path.Combine(Directory.GetCurrentDirectory(), $"{_iconfiguration.GetValue<string>("VirtualPath")}/{videoUid}"); //检查相应目录 if (!Directory.Exists(targetFilePath)) { Directory.CreateDirectory(targetFilePath); } var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); try { var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { var fileName = section.AsFileSection().FileName; video.FileName = fileName; video.Name = fileName; video.UpdateUser = "******"; video.CreateUser = "******"; targetFilePath = Path.Combine(targetFilePath, fileName); if (System.IO.File.Exists(targetFilePath)) { result.Status = CommonEntity.StatusCode.Error; result.Message = "文件已存在"; break; } using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); _ilogger.LogInformation($"复制文件到该路径下 '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } video.Name = formAccumulator.GetResults()["name"]; video.Title = formAccumulator.GetResults()["title"]; video.SecertKey = videoUid; video.State = Convert.ToInt32(formAccumulator.GetResults()["state"]); return(await Task.FromResult(await _ivideoService.InsertVideoAsync(video))); } catch (OperationCanceledException) { if (System.IO.File.Exists(targetFilePath)) { System.IO.File.Delete(targetFilePath); } result.Status = CommonEntity.StatusCode.Error; result.Message = "用户取消上传操作"; return(await Task.FromResult(result)); } catch (Exception ex) { if (System.IO.File.Exists(targetFilePath)) { System.IO.File.Delete(targetFilePath); } result.Status = CommonEntity.StatusCode.Error; result.Message = "取消上传操作"; _ilogger.LogError(new EventId(), ex, ex.Message); return(await Task.FromResult(result)); } }
public static async Task <(FormValueProvider fvp, List <BasicImage> bi)> StreamFile(this HttpRequest request) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); int positionCounter = 1; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); List <BasicImage> images = new List <BasicImage>(); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { string fileext = System.IO.Path.GetExtension(contentDisposition.FileName.ToString()); string guid = Guid.NewGuid().ToString(); string pathUID = guid + fileext; using (var stream = System.IO.File.Create("c:\\temp\\" + pathUID)) { await section.Body.CopyToAsync(stream); BasicImage bi = new BasicImage { //Initialise as -1 prior to autogeneration of PropertyID image is bound to PropertyRef = -1, Position = positionCounter++, Path = pathUID }; images.Add(bi); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new System.IO.StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value, value); // For .NET Core <2.0 remove ".Value" from key if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new System.IO.InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider, images); }
protected async Task <KeyValueAccumulator> BuildMultiPartFormAccumulator <TModel>() where TModel : class, new() { var httpContextRequest = HttpContext.Request; // Used to accumulate all the form url encoded key value pairs in the request var formAccumulator = new KeyValueAccumulator(); var boundary = Request.GetBoundary(_defaultFormOptions); var reader = new MultipartReader(boundary, httpContextRequest.Body); Logger.LogDebug("Reading next section"); var section = await reader.ReadNextSectionAsync(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { Logger.LogDebug("Content Disposition Header: {0}", section.ContentDisposition); if (contentDisposition.IsFileContentDisposition()) { var fileName = contentDisposition.FileName.Value; var formFileNames = FormFileAttributeHelper.GetFormFileNames(typeof(TModel)); if (!formFileNames.Contains(contentDisposition.Name.Value)) { Logger.LogWarning($"Unknown file '{contentDisposition.Name.Value}' with fileName: '{fileName}' is being ignored."); // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); continue; } formAccumulator.Append(contentDisposition.Name.Value, fileName); var path = await TempFileService.CreateFromStreamAsync(fileName, section.Body); Logger.LogInformation($"Copied the uploaded file '{fileName}' to path: '{path}'"); } else if (contentDisposition.IsFormDataContentDisposition()) { // Content-Disposition: form-data; name="key" // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); Logger.LogDebug("Retrieving value for {0}", key); var encoding = section.GetEncoding(); var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true); using (streamReader) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException( $"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } return(formAccumulator); }
public async Task <IActionResult> Post() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; string targetFileContentType = null; 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) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); targetFileContentType = section.ContentType; var fileName = GetFileName(section.ContentDisposition); using (var targetStream = new FileStream(fileName, FileMode.Append)) { await _storage.StoreAndGetFile(fileName, "talentcontest", targetFileContentType, targetStream); //await section.Body.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > DefaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {DefaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var entry = new SubmissionViewModel(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(entry, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } var uploadedData = new Submission { FirstName = entry.FirstName, LastName = entry.LastName, Email = entry.Email, ManagerName = entry.ManagerName, LocationId = entry.LocationId, PhoneNumber = entry.PhoneNumber, FileName = entry.FileName, Talent = entry.Talent, ImageConsent = entry.ImageConsent, ContestConsent = entry.ContestConsent, EmployeeId = entry.EmployeeId }; return(Json(uploadedData)); }
public async Task <IActionResult> Upload() { //StringValues UniqueUploadId = default(StringValues); //StringValues UploadType = default(StringValues); //Request.Headers.TryGetValue("unique-upload-id", out UniqueUploadId); //Request.Headers.TryGetValue("upload-type", out UploadType); Request.Headers.TryGetValue("X-Upload-Title", out StringValues uploadTitle); Request.Headers.TryGetValue("X-Date-Taken", out StringValues dateTaken); var user = await _userManager.GetUserAsync(User); if (user == null) { return(BadRequest()); } if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); var objectKey = Guid.NewGuid().ToString(); var thumbObjectKey = $"{Guid.NewGuid()}.jpg"; FileStorage parent = null; 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 ContentDispositionHeaderValue contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { var targetFilePath = Path.GetTempFileName(); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } var partName = contentDisposition.Name; var strippedFileName = contentDisposition.FileName.Replace("\"", string.Empty); var mimeType = MimeTypesHelper.GetMimeType(strippedFileName); var fileExtension = $".{strippedFileName.Split('.').LastOrDefault()}"; var originalFileName = strippedFileName.Replace(fileExtension, string.Empty); var type = FileStorageType.Thumb; var isFile = partName.Replace("\"", string.Empty) == "file"; if (mimeType.Contains("image") && isFile) { type = FileStorageType.Image; } else if (mimeType.Contains("video") && isFile) { type = FileStorageType.Video; } if (isFile) { objectKey = $"{objectKey}{fileExtension}"; } try { using (var amazonClient = new AmazonS3Helper(_amazonS3, "attorney-journal-dev")) { await amazonClient.UploadFileAsync(targetFilePath, isFile?objectKey : thumbObjectKey); } var date = new DateTime(); try { date = DateTime.Parse(dateTaken); } catch (System.Exception) { } var newFile = new FileStorage { Parent = parent, AmazonObjectKey = isFile ? objectKey : thumbObjectKey, CreatedAt = DateTime.UtcNow, FileExtension = fileExtension, OriginalName = originalFileName, MimeType = mimeType, Owner = user, Type = type, Title = uploadTitle.FirstOrDefault() ?? string.Empty, DateTaken = date }; _context.Files.Add(newFile); parent = isFile ? newFile : null; } catch (AmazonS3Exception s3Exception) { Console.WriteLine(s3Exception.Message, s3Exception.InnerException); } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var formValueProvider = new FormValueProvider(BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(new { }, string.Empty, formValueProvider); if (!bindingSuccessful || !ModelState.IsValid) { return(BadRequest(ModelState)); } await _context.SaveChangesAsync(CancellationToken.None); return(Json(new { fileUrl = AmazonS3Helper.GenerateUrl(objectKey), thumbUrl = AmazonS3Helper.GenerateUrl(thumbObjectKey), result = true })); }
public async Task <ActionResult <UploadResult> > Upload() { var multipartBoundary = Request.GetMultipartBoundary(); if (string.IsNullOrEmpty(multipartBoundary)) { return(BadRequest($"Expected a multipart request, but got '{Request.ContentType}'.")); } var formAccumulator = new KeyValueAccumulator(); var reader = new MultipartReader(multipartBoundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); var fileGuid = Guid.NewGuid(); var userId = _userManager.GetUserId(HttpContext.User); var fileExtension = string.Empty; while (section != null) { var fileSection = section.AsFileSection(); if (fileSection != null) { var fileName = fileSection.FileName; fileExtension = Path.GetExtension(fileName); var targetFolderPath = Path.Combine(_hostingEnvironment.WebRootPath, _appSettings.UploadsFolder, userId); var targetFilePath = Path.Combine(_hostingEnvironment.WebRootPath, _appSettings.UploadsFolder, userId, $"{fileGuid}{fileExtension}"); if (!Directory.Exists(targetFolderPath)) { Directory.CreateDirectory(targetFolderPath); } using (var targetStream = System.IO.File.Create(targetFilePath)) { await fileSection.FileStream.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{fileName}' to '{targetFilePath}'."); } } else { var formSection = section.AsFormDataSection(); if (formSection != null) { var name = formSection.Name; var value = await formSection.GetValueAsync(); formAccumulator.Append(name, value); if (formAccumulator.ValueCount > FormReader.DefaultValueCountLimit) { throw new InvalidDataException($"Form key count limit {FormReader.DefaultValueCountLimit} exceeded."); } } } section = await reader.ReadNextSectionAsync(); } return(Ok(new UploadResult { Succeeded = true, Description = "File was uploaded successfully", FileUrl = $"{_appSettings.Domain}/{_appSettings.UploadsFolder}/{userId}/{fileGuid}{fileExtension}", FileName = $"{fileGuid}{fileExtension}" })); }
public async Task <IActionResult> PostAppFileStream() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 1)."); // Log error return(BadRequest(ModelState)); } // Accumulate the form data key-value pairs in the request (formAccumulator). var formAccumulator = new KeyValueAccumulator(); var trustedFileNameForDisplay = string.Empty; var untrustedFileNameForStorage = string.Empty; var streamedFileContent = new byte[0]; 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) { if (MultipartRequestHelper .HasFileContentDisposition(contentDisposition)) { untrustedFileNameForStorage = contentDisposition.FileName.Value; // Don't trust the file name sent by the client. To display // the file name, HTML-encode the value. trustedFileNameForDisplay = WebUtility.HtmlEncode( contentDisposition.FileName.Value); streamedFileContent = await FileHelpers.ProcessStreamedFile(section, contentDisposition, ModelState, _permittedExtensions, _fileSizeLimit); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } else if (MultipartRequestHelper .HasFormDataContentDisposition(contentDisposition)) { // Don't limit the key name length because the // multipart headers length limit is already in effect. var key = HeaderUtilities .RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); if (encoding == null) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 2)."); // Log error return(BadRequest(ModelState)); } using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by // MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { // Form key count limit of // _defaultFormOptions.ValueCountLimit // is exceeded. ModelState.AddModelError("File", $"The request couldn't be processed (Error 3)."); // Log error return(BadRequest(ModelState)); } } } } // Drain any remaining section body that hasn't been consumed and // read the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to the model var formData = new FormData(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(formData, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { ModelState.AddModelError("File", "The request couldn't be processed (Error 5)."); // Log error return(BadRequest(ModelState)); } // **WARNING!** // In the following example, the file is saved without // scanning the file's contents. In most production // scenarios, an anti-virus/anti-malware scanner API // is used on the file before making the file available // for download or for use by other systems. // For more information, see the topic that accompanies // this sample app. var file = new AppFile() { Content = streamedFileContent, UntrustedName = untrustedFileNameForStorage, Note = formData.Note, Size = streamedFileContent.Length, UploadDT = DateTime.UtcNow }; _context.File.Add(file); await _context.SaveChangesAsync(); return(Created($"api/AppFiles/{file.Id}", null)); }
/// <summary> /// 以流的形式保存文件 /// </summary> /// <param name="request"></param> /// <param name="targetDirectory">e:\ws\music\files</param> /// <returns></returns> public static async Task <FormValueProvider> StreamFiles(this HttpRequest request, string targetDirectory) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. 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();//用于读取Http请求中的第一个section数据 while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { /* * 用于处理上传文件类型的的section * -----------------------------99614912995 * Content - Disposition: form - data; name = "files"; filename = "Misc 002.jpg" * * ASAADSDSDJXCKDSDSDSHAUSAUASAASSDSDFDSFJHSIHFSDUIASUI+/== * -----------------------------99614912995 */ if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { var fileName = MultipartRequestHelper.GetFileName(contentDisposition); var fileGuid = Guid.NewGuid().ToString(); var fileExt = System.IO.Path.GetExtension(fileName); var destFileName = fileGuid + fileExt; var relDir = ""; switch (section.ContentType.Split("/")[0]) { case "video": relDir += "\\Video"; break; case "audio": relDir += "\\Audio"; break; case "image": relDir += "\\Image"; break; case "text": relDir += "\\Text"; break; default: relDir += "\\Other"; break; } var relPath = relDir + "\\" + destFileName; var path = targetDirectory + relDir + "\\" + destFileName; var dir = System.IO.Path.GetDirectoryName(path); if (!System.IO.Directory.Exists(dir)) { System.IO.Directory.CreateDirectory(dir); } var now = DateTime.Now; // 文件保存成功后保存文件信息到数据库 var fileInfo = new FileInfo { FileGuid = fileGuid, Path = path, Url = "/file" + relDir.Replace("\\", "/").ToLower() + "/" + destFileName, // /Files/Images/guid.ext | /Files/Audios/guid.ext RelPath = relPath, SrcPath = fileName, ContentType = section.ContentType, FileExt = fileExt, Length = section.Body.Length, CreateTime = now, UpdateTime = now, VisitTime = now }; Console.WriteLine("[FileStreamingHelper] [StreamFiles] FileInfo: " + Newtonsoft.Json.JsonConvert.SerializeObject(fileInfo)); formAccumulator.Append("fileInfo", Newtonsoft.Json.JsonConvert.SerializeObject(fileInfo)); var loadBufferBytes = 1024;//这个是每一次从Http请求的section中读出文件数据的大小,单位是Byte即字节,这里设置为1024的意思是,每次从Http请求的section数据流中读取出1024字节的数据到服务器内存中,然后写入下面targetFileStream的文件流中,可以根据服务器的内存大小调整这个值。这样就避免了一次加载所有上传文件的数据到服务器内存中,导致服务器崩溃。 using (var targetFileStream = System.IO.File.Create(path)) { //section.Body是System.IO.Stream类型,表示的是Http请求中一个section的数据流,从该数据流中可以读出每一个section的全部数据,所以我们下面也可以不用section.Body.CopyToAsync方法,而是在一个循环中用section.Body.Read方法自己读出数据,再将数据写入到targetFileStream // 注意一个section是否是一个文件的片段 await section.Body.CopyToAsync(targetFileStream, loadBufferBytes); } } /* * 用于处理表单键值数据的section * -----------------------------99614912995 * Content - Disposition: form - data; name = "SOMENAME" * * Formulaire de Quota * -----------------------------99614912995 */ else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new System.IO.StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value, value); // For .NET Core <2.0 remove ".Value" from key if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new System.IO.InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync();//用于读取Http请求中的下一个section数据 } // Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider); }
public static async Task <FormValueProvider> StreamFiles(this HttpRequest request, string targetDirectory) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. 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();//用于读取Http请求中的第一个section数据 while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { /* * 用于处理上传文件类型的的section * -----------------------------99614912995 * Content - Disposition: form - data; name = "files"; filename = "Misc 002.jpg" * * ASAADSDSDJXCKDSDSDSHAUSAUASAASSDSDFDSFJHSIHFSDUIASUI+/== * -----------------------------99614912995 */ if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { if (!Directory.Exists(targetDirectory)) { Directory.CreateDirectory(targetDirectory); } var fileName = MultipartRequestHelper.GetFileName(contentDisposition); var loadBufferBytes = 1024;//这个是每一次从Http请求的section中读出文件数据的大小,单位是Byte即字节,这里设置为1024的意思是,每次从Http请求的section数据流中读取出1024字节的数据到服务器内存中,然后写入下面targetFileStream的文件流中,可以根据服务器的内存大小调整这个值。这样就避免了一次加载所有上传文件的数据到服务器内存中,导致服务器崩溃。 using (var targetFileStream = System.IO.File.Create(targetDirectory + "\\" + fileName)) { using (section.Body) { //section.Body是System.IO.Stream类型,表示的是Http请求中一个section的数据流,从该数据流中可以读出每一个section的全部数据,所以我们下面也可以不用section.Body.CopyToAsync方法,而是在一个循环中用section.Body.Read方法自己读出数据(如果section.Body.Read方法返回0,表示数据流已经到末尾,数据已经全部都读取完了),再将数据写入到targetFileStream await section.Body.CopyToAsync(targetFileStream, loadBufferBytes); } } } /* * 用于处理表单键值数据的section * -----------------------------99614912995 * Content - Disposition: form - data; name = "SOMENAME" * * Formulaire de Quota * -----------------------------99614912995 */ else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value, value); // For .NET Core <2.0 remove ".Value" from key if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync();//用于读取Http请求中的下一个section数据 } // Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider); }
public async Task <IActionResult> PostImage(string nihii) { try { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), 52000); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { using (var targetStream = new MemoryStream()) { await section.Body.CopyToAsync(targetStream); var imageName = contentDisposition.FileName.ToString(); bool isImage = false; foreach (var ext in imageExtensions) { if (imageName.ToLower().EndsWith(ext)) { isImage = true; } } imageName = $"{nihii}/" + imageName; //imageName = isImage ? $"{nihii}/images/" + imageName : $"{nihii}/documents/" + imageName; var photoUriResponse = await _storageService.Post(imageName, targetStream.ToArray()); if (!photoUriResponse.Success) { return(BadRequest(photoUriResponse.Error)); } return(Json($"{imageName}.jpg")); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); using (var streamReader = new StreamReader(section.Body, Encoding.UTF8, true, 1024, true)) { var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); } } } section = await reader.ReadNextSectionAsync(); } return(NoContent()); } catch (Exception ex) { return(BadRequest(ex.Message + " ---" + ex.StackTrace)); } }
private async Task <IFormCollection> InnerReadFormAsync(CancellationToken cancellationToken) { if (!HasFormContentType) { throw new InvalidOperationException("Incorrect Content-Type: " + _request.ContentType); } cancellationToken.ThrowIfCancellationRequested(); if (_request.ContentLength == 0) { return(FormCollection.Empty); } if (_options.BufferBody) { _request.EnableRewind(_options.MemoryBufferThreshold, _options.BufferBodyLengthLimit); } FormCollection formFields = null; FormFileCollection files = null; // Some of these code paths use StreamReader which does not support cancellation tokens. using (cancellationToken.Register((state) => ((HttpContext)state).Abort(), _request.HttpContext)) { var contentType = ContentType; // Check the content-type if (HasApplicationFormContentType(contentType)) { var encoding = FilterEncoding(contentType.Encoding); using (var formReader = new FormReader(_request.Body, encoding) { ValueCountLimit = _options.ValueCountLimit, KeyLengthLimit = _options.KeyLengthLimit, ValueLengthLimit = _options.ValueLengthLimit, }) { formFields = new FormCollection(await formReader.ReadFormAsync(cancellationToken)); } } else if (HasMultipartFormContentType(contentType)) { var formAccumulator = new KeyValueAccumulator(); var boundary = GetBoundary(contentType, _options.MultipartBoundaryLengthLimit); var multipartReader = new MultipartReader(boundary, _request.Body) { HeadersCountLimit = _options.MultipartHeadersCountLimit, HeadersLengthLimit = _options.MultipartHeadersLengthLimit, BodyLengthLimit = _options.MultipartBodyLengthLimit, }; var section = await multipartReader.ReadNextSectionAsync(cancellationToken); while (section != null) { // Parse the content disposition here and pass it further to avoid reparsings if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition)) { throw new InvalidDataException("Form section has invalid Content-Disposition value: " + section.ContentDisposition); } if (contentDisposition.IsFileDisposition()) { var fileSection = new FileMultipartSection(section, contentDisposition); // Enable buffering for the file if not already done for the full body section.EnableRewind( _request.HttpContext.Response.RegisterForDispose, _options.MemoryBufferThreshold, _options.MultipartBodyLengthLimit); // Find the end await section.Body.DrainAsync(cancellationToken); var name = fileSection.Name; var fileName = fileSection.FileName; FormFile file; if (section.BaseStreamOffset.HasValue) { // Relative reference to buffered request body file = new FormFile(_request.Body, section.BaseStreamOffset.GetValueOrDefault(), section.Body.Length, name, fileName); } else { // Individually buffered file body file = new FormFile(section.Body, 0, section.Body.Length, name, fileName); } file.Headers = new HeaderDictionary(section.Headers); if (files == null) { files = new FormFileCollection(); } if (files.Count >= _options.ValueCountLimit) { throw new InvalidDataException($"Form value count limit {_options.ValueCountLimit} exceeded."); } files.Add(file); } else if (contentDisposition.IsFormDisposition()) { var formDataSection = new FormMultipartSection(section, contentDisposition); // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the multipart headers length limit is already in effect. var key = formDataSection.Name; var value = await formDataSection.GetValueAsync(); formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _options.ValueCountLimit) { throw new InvalidDataException($"Form value count limit {_options.ValueCountLimit} exceeded."); } } else { System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + section.ContentDisposition); } section = await multipartReader.ReadNextSectionAsync(cancellationToken); } if (formAccumulator.HasValues) { formFields = new FormCollection(formAccumulator.GetResults(), files); } } } // Rewind so later readers don't have to. if (_request.Body.CanSeek) { _request.Body.Seek(0, SeekOrigin.Begin); } if (formFields != null) { Form = formFields; } else if (files != null) { Form = new FormCollection(null, files); } else { Form = FormCollection.Empty; } return(Form); }
/// <summary> /// 这个特性能让这个页面带上验证信息,令牌 /// /// </summary> /// <returns></returns> //[HttpGet] //[GenerateAntiforgeryTokenCookieForAjax] //public IActionResult Index() //{ // return View(); //} #region --上传方法, 不自动绑定,可上传大文件-- /// <summary> /// 上传方法 /// </summary> /// <returns></returns> // 1. Disable the form value model binding here to take control of handling // potentially large files. // 禁止了表单到模型自动绑定,以便能控制好大文件 // 2. Typically antiforgery tokens are sent in request body, but since we // do not want to read the request body early, the tokens are made to be // sent via headers. The antiforgery token filter first looks for tokens // in the request header and then falls back to reading the body. //[HttpPost] //[DisableFormValueModelBinding]//不进行表单到模型的绑定 //[ValidateAntiForgeryToken]//检查令牌 protected async Task <IActionResult> Upload(Func <IDictionary <string, StringValues>, string> filePathFunc) { // 检查是否多部分数据类型 if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; //目标文件路经 //这里应该是获取http提交的分段信息 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) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); // 是否有内容配置头值 if (hasContentDispositionHeader) { // 是否文件内容配置 if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { // 一个临时文件名 section.Headers.Keys.Foreach(key => { LogInfo($"{key}:{section.Headers[key]}"); }); var file_ex = section.ContentDisposition.LastIndexOfRight(".").RemoveFileNameIllegalChar(); targetFilePath = Constant.CurrDir + "temp" + DateTime.Now.DataStr("") + "." + file_ex;//Path.GetTempFileName(); targetFilePath = filePathFunc(section.Headers); // 写入文件到临时文件 using (var targetStream = System.IO.File.Create(targetFilePath)) { // 此方法接收数据不全 await section.Body.CopyToAsync(targetStream); //LogInfo($"Copied the uploaded file '{targetFilePath}'"); } } // 是否有表单,这一段用于处理所有键值对 else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 5120000, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit // 值长度被MultipartBodyLengthLimit强制限制了 var value = await streamReader.ReadToEndAsync();//读取流 if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); LogInfo($"key={key.ToString()} | {value}"); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. // 读取下一个节点头(部分) section = await reader.ReadNextSectionAsync(); } //这里绑定表单数据到 // Bind form data to a model //var user = new User(); //var formValueProvider = new FormValueProvider( // BindingSource.Form, // new FormCollection(formAccumulator.GetResults()), // CultureInfo.CurrentCulture); //var bindingSuccessful = await TryUpdateModelAsync(user, prefix: "", // valueProvider: formValueProvider); //if (!bindingSuccessful) //{ // if (!ModelState.IsValid) // { // return BadRequest(ModelState); // } //} //var uploadedData = new UploadedData() //{ // Name = user.Name, // Age = user.Age, // Zipcode = user.Zipcode, // FilePath = targetFilePath //}; return(Json("success")); }
public async Task <FormDataUploadAccumulator> UploadFormAsync(MultipartReader reader) { try { var section = await reader.ReadNextSectionAsync(); var filename = Guid.NewGuid().ToString(); var formAccumulator = new KeyValueAccumulator(); using (var destinationStream = await _context.GetBucket().OpenUploadStreamAsync(filename)) { var id = destinationStream.Id; // the unique Id of the file being uploaded while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition); if (hasContentDispositionHeader) { if (_requestHelper.HasFileContentDisposition(contentDisposition)) { filename = HeaderUtilities.RemoveQuotes(contentDisposition.FileName).ToString(); // write the contents of the file to stream using asynchronous Stream methods await section.Body.CopyToAsync(destinationStream); } else if (_requestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).ToString(); var encoding = _requestHelper.GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); //if (formAccumulator.ValueCount > 4)//Todo get default value //{ // throw new InvalidDataException($"Form key count limit exceeded."); //} } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } await destinationStream.CloseAsync(); // optional but recommended so Dispose does not block var extension = Path.GetExtension(filename); var newName = Guid.NewGuid().ToString() + extension; _context.GetBucket().Rename(id, newName); return(new FormDataUploadAccumulator { FileId = id.ToString(), Filename = newName, Accumulator = formAccumulator }); } } catch (Exception ex) { // log or manage the exception throw ex; } }
public async Task <IActionResult> UploadFile([FromRoute] string username, [FromRoute] string directoryPath) { //string requestContentType = Request.ContentType; //bool hasFormContentType = Request.HasFormContentType; // Accumulate all form key-value pairs in the request (in case we want to do something with other form-fields that are not only files) KeyValueAccumulator formAccumulator = new KeyValueAccumulator(); Dictionary <string, string> sectionDictionary = new Dictionary <string, string>(); // get off the boundary appended by the form-post string boundary = GetBoundary(Request.ContentType); try // FIX THIS HUGE TRY BLOCK { var reader = new MultipartReader(boundary, Request.Body); MultipartSection section = null; section = await reader.ReadNextSectionAsync(); while (section != null) { // Get the conten header disposition for checking if we are handling a file-form-field or just any other type of field ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (contentDisposition.IsFileDisposition()) { // Fetch data from header (Delete this after we implement authentication) var appId = Request.Headers["AppId"]; var phonenumber = Request.Headers["OwnerPhoneNumber"]; var firstname = Request.Headers["OwnerFirstName"]; var lastname = Request.Headers["OwnerLastName"]; // Here we handle file fields string fileName = contentDisposition.FileName.ToString().Replace(" ", ""); string UploadsDir = Path.Combine(appEnv.WebRootPath, $"dataspace/{username}"); // If the BASE dir doesn't exist, create it Directory.CreateDirectory(UploadsDir); string physicalPath; string url; // Check for subdir if (String.IsNullOrWhiteSpace(directoryPath)) { physicalPath = Path.Combine(UploadsDir, fileName); // Prepare file name and path for writing url = $"{Request.Scheme}://{Request.Host}/dataspace/{username}/files/{fileName}"; directoryPath = ""; } else { physicalPath = Path.Combine(UploadsDir, directoryPath, fileName); // Prepare file name and path for writing url = $"{Request.Scheme}://{Request.Host}/dataspace/{username}/files/{directoryPath}/{fileName}"; } //// We can also use a temp location for now eg. AppData on Windows //var targetFilePath = Path.GetTempFileName(); // Createa a stream and write the request (section-field) body/data using (var targetStream = System.IO.File.Create(physicalPath)) { // Copy file to disk await section.Body.CopyToAsync(targetStream); // TODO: Generate metadata and save the path into a FileMicroservice with SignalR (db handler) FileDto newFile = new FileDto { Name = fileName, Path = directoryPath, Url = url, MimeType = section.ContentType, FileSizeInKB = (int)(targetStream.Length / 1024) // Test }; dataSpaceSignalRClient.SaveFileMetadata(phonenumber, newFile); // rename stuff like this to nodePath } } else if (contentDisposition.IsFormDisposition()) { // Remove this (?) // Here we handle other form fields StringSegment fieldName = HeaderUtilities.RemoveQuotes(contentDisposition.Name); FormMultipartSection formMultipartSection = section.AsFormDataSection(); string fieldValue = await formMultipartSection.GetValueAsync().ConfigureAwait(false); sectionDictionary.Add(formMultipartSection.Name, fieldValue); using (var streamReader = new StreamReader(section.Body)) { if (String.Equals(fieldValue, "undefined", StringComparison.OrdinalIgnoreCase)) { fieldValue = String.Empty; } formAccumulator.Append(fieldName.ToString(), fieldValue); } } } // Read next section/field section = await reader.ReadNextSectionAsync(); } } catch (Exception e) { // handle any unread or errors on errors while streaming and writing received data return(BadRequest()); } //// Remove this (?) //// Handle all the non-file fields either here, or above while reading the streams already eg. chosen parent directory //var result = sectionDictionary; //var frmResults = formAccumulator.GetResults(); return(Ok()); }
public static async Task <FormValueProvider> StreamFile(this HttpRequest request, Stream targetStream) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { await section.Body.CopyToAsync(targetStream); } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value, value); // For .NET Core <2.0 remove ".Value" from key if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider); }
private async Task <(MemberDto, ImageDto?)> UploadUserImageMultipartContent(Guid targetUserId, Stream requestBody, byte[] rowVersion, string?contentType, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var now = _systemClock.UtcNow.UtcDateTime; var defaultFormOptions = new FormOptions(); // Create a Collection of KeyValue Pairs. var formAccumulator = new KeyValueAccumulator(); // Determine the Multipart Boundary. var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(contentType), defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, requestBody); var section = await reader.ReadNextSectionAsync(cancellationToken); ImageDto? imageDto = null; MemberDto userDto = new MemberDto(); // Loop through each 'Section', starting with the current 'Section'. while (section != null) { // Check if the current 'Section' has a ContentDispositionHeader. var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { if (contentDisposition != null) { var sectionFileName = contentDisposition.FileName.Value; // use an encoded filename in case there is anything weird var encodedFileName = WebUtility.HtmlEncode(Path.GetFileName(sectionFileName)); // read the section filename to get the content type var fileExtension = Path.GetExtension(sectionFileName); // now make it unique var uniqueFileName = $"{Guid.NewGuid()}{fileExtension}"; if (!_acceptedFileTypes.Contains(fileExtension.ToLower())) { _logger.LogError("file extension:{0} is not an accepted image file", fileExtension); throw new ValidationException("Image", "The image is not in an accepted format"); } var compressedImage = _imageService.TransformImageForAvatar(section.Body); try { await _blobStorageProvider.UploadFileAsync(compressedImage.Image, uniqueFileName, MimeTypesMap.GetMimeType(encodedFileName), cancellationToken); } catch (Exception ex) { _logger.LogError(ex, "An error occurred uploading file to blob storage"); throw; } // trick to get the size without reading the stream in memory var size = section.Body.Position; imageDto = new ImageDto { FileSizeBytes = size, FileName = uniqueFileName, Height = compressedImage.Height, Width = compressedImage.Width, IsDeleted = false, MediaType = compressedImage.MediaType, CreatedBy = targetUserId, CreatedAtUtc = now }; var imageValidator = new ImageValidator(MaxFileSizeBytes); var imageValidationResult = await imageValidator.ValidateAsync(imageDto, cancellationToken); if (imageValidationResult.Errors.Count > 0) { await _blobStorageProvider.DeleteFileAsync(uniqueFileName); _logger.LogError("File size:{0} is greater than the max allowed size:{1}", size, MaxFileSizeBytes); throw new ValidationException(imageValidationResult); } } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // if for some reason other form data is sent it would get processed here var key = HeaderUtilities.RemoveQuotes(contentDisposition?.Name.ToString().ToLowerInvariant()); var encoding = GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > defaultFormOptions.ValueCountLimit) { _logger.LogError("UserEdit: Form key count limit {0} exceeded.", defaultFormOptions.ValueCountLimit); throw new FormatException($"Form key count limit { defaultFormOptions.ValueCountLimit } exceeded."); } } } } // Begin reading the next 'Section' inside the 'Body' of the Request. section = await reader.ReadNextSectionAsync(cancellationToken); } if (formAccumulator.HasValues) { var formValues = formAccumulator.GetResults(); // Check if users been updated // Unable to place in controller due to disabling form value model binding var user = await _userCommand.GetMemberAsync(targetUserId, cancellationToken); if (!user.RowVersion.SequenceEqual(rowVersion)) { _logger.LogError($"Precondition Failed: UpdateUserAsync - User:{0} has changed prior to submission", targetUserId); throw new PreconditionFailedExeption("Precondition Failed: User has changed prior to submission"); } var firstNameFound = formValues.TryGetValue("firstName", out var firstName); if (firstNameFound is false || string.IsNullOrEmpty(firstName)) { throw new ArgumentNullException($"First name was not provided"); } formValues.TryGetValue("lastName", out var surname); var pronoundsFound = formValues.TryGetValue("pronouns", out var pronouns); if (pronoundsFound is false) { throw new ArgumentNullException($"Pronouns were not provided"); } formValues.TryGetValue("imageid", out var image); var imageId = Guid.TryParse(image, out var imageGuid) ? (Guid?)imageGuid : null; if (imageId.HasValue) { if (imageId == new Guid()) { throw new ArgumentOutOfRangeException($"Incorrect Id provided"); } } userDto = new MemberDto { Id = targetUserId, FirstName = firstName, Surname = surname, Pronouns = pronouns, ImageId = imageId, ModifiedAtUTC = now, ModifiedBy = targetUserId, }; } return(userDto, imageDto); }
public async Task <IActionResult> StreamingUpload(Int32 id) { Debug.WriteLine("In Streaming Upload for Trip Number: " + id); if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); string newFileName = ""; DateTime FileDateTime = new DateTime(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { //targetFilePath = Path.GetTempFileName(); string fileName = contentDisposition.FileName.ToString().Trim('"'); newFileName = FileHelper.newFileName(id, fileName, out FileDateTime); targetFilePath = Path.Combine(_newPath, newFileName); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); // _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } //add the Trip File Object to the database //TripFile TripFileItem = new TripFile //{ // TripID = id, // TripFileName = newFileName, // FilePath = targetFilePath, // FileDateTime = FileDateTime.ToString() //}; //_context.Add(TripFileItem); //_context.SaveChanges(); // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } /// Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(new JsonResult(formValueProvider)); }
/// based on microsoft example https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/mvc/models/file-uploads/samples/ /// and large file streaming example https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-5.0#upload-large-files-with-streaming private async Task <(GroupDto, ImageDto?)> UploadGroupImageMultipartContent(GroupData groupData, Guid userId, string slug, Stream requestBody, byte[] rowVersion, string?contentType, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // Check if HttpRequest (Form Data) is a Multipart Content Type if (!MultipartRequestHelper.IsMultipartContentType(contentType)) { throw new InvalidDataException($"Expected a multipart request, but got {contentType}"); } var now = _systemClock.UtcNow.UtcDateTime; var defaultFormOptions = new FormOptions(); // Create a Collection of KeyValue Pairs. var formAccumulator = new KeyValueAccumulator(); // Determine the Multipart Boundary. var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(contentType), defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, requestBody); var section = await reader.ReadNextSectionAsync(cancellationToken); ImageDto?imageDto = null; GroupDto groupDto = new GroupDto(); // Loop through each 'Section', starting with the current 'Section'. while (section != null) { // Check if the current 'Section' has a ContentDispositionHeader. var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { if (contentDisposition != null) { var sectionFileName = contentDisposition.FileName.Value; // use an encoded filename in case there is anything weird var encodedFileName = WebUtility.HtmlEncode(Path.GetFileName(sectionFileName)); // read the section filename to get the content type var fileExtension = Path.GetExtension(sectionFileName); // now make it unique var uniqueFileName = $"{Guid.NewGuid()}{fileExtension}"; if (!_acceptedFileTypes.Contains(fileExtension.ToLower())) { _logger.LogError("file extension:{0} is not an accepted image file", fileExtension); throw new ValidationException("Image", "The image is not in an accepted format"); } var compressedImage = _imageService.TransformImageForGroupHeader(section.Body); try { await _blobStorageProvider.UploadFileAsync(compressedImage.Image, uniqueFileName, MimeTypesMap.GetMimeType(encodedFileName), cancellationToken); } catch (Exception ex) { _logger.LogError(ex, "An error occurred uploading file to blob storage"); throw; } // trick to get the size without reading the stream in memory var size = section.Body.Position; // TODO MimeDetective does not work when stream has already been uploaded - figure out a solution //if (fileContentTypeMatchesExtension is false) //{ // await _blobStorageProvider.DeleteFileAsync(uniqueFileName); // _logger.LogError("File extension:{0} does not match the file signature", fileExtension); // throw new FormatException("File extension} does not match the file signature"); //} imageDto = new ImageDto { FileSizeBytes = size, FileName = uniqueFileName, Height = compressedImage.Height, Width = compressedImage.Width, IsDeleted = false, MediaType = compressedImage.MediaType, CreatedBy = userId, CreatedAtUtc = now }; var imageValidator = new ImageValidator(MaxFileSizeBytes); var imageValidationResult = await imageValidator.ValidateAsync(imageDto, cancellationToken); if (imageValidationResult.Errors.Count > 0) { await _blobStorageProvider.DeleteFileAsync(uniqueFileName); _logger.LogError("File size:{0} is greater than the max allowed size:{1}", size, MaxFileSizeBytes); throw new ValidationException(imageValidationResult); } } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // if for some reason other form data is sent it would get processed here var key = HeaderUtilities.RemoveQuotes(contentDisposition?.Name.ToString().ToLowerInvariant()); var encoding = GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key.Value, value); if (formAccumulator.ValueCount > defaultFormOptions.ValueCountLimit) { _logger.LogError("GroupEdit: Form key count limit {0} exceeded.", defaultFormOptions.ValueCountLimit); throw new FormatException($"Form key count limit { defaultFormOptions.ValueCountLimit } exceeded."); } } } } // Begin reading the next 'Section' inside the 'Body' of the Request. section = await reader.ReadNextSectionAsync(cancellationToken); } if (formAccumulator.HasValues) { var formValues = formAccumulator.GetResults(); // Get values from multipart form var nameFound = formValues.TryGetValue("name", out var name); if (nameFound is false) { throw new ValidationException("Name", "Name was not provided"); } var straplineFound = formValues.TryGetValue("strapline", out var strapline); if (straplineFound is false) { throw new ValidationException("Strapline", "Strapline was not provided"); } formValues.TryGetValue("themeid", out var theme); if (Guid.TryParse(theme, out var themeId) is false || themeId == new Guid()) { throw new ValidationException(nameof(GroupDto.ThemeId), "Theme was not provided"); } formValues.TryGetValue("imageid", out var image); var imageId = Guid.TryParse(image, out var imageGuid) ? (Guid?)imageGuid : null; if (imageId.HasValue) { if (imageId == new Guid()) { throw new ArgumentOutOfRangeException($"Incorrect Id provided"); } } formValues.TryGetValue("isPublic", out var publicGroup); var isPublic = bool.TryParse(publicGroup, out var isPublicBool) ? isPublicBool : false; if (!groupData.IsPublic) { if (isPublic != groupData.IsPublic) { throw new ValidationException("isPublic", "Cannot make a private group public"); } } groupDto = new GroupDto { Slug = slug, Name = _htmlSanitizer.Sanitize(name), Strapline = _htmlSanitizer.Sanitize(strapline), ThemeId = themeId, ImageId = imageId, ModifiedBy = userId, ModifiedAtUtc = now, IsPublic = isPublic, RowVersion = rowVersion }; } return(groupDto, imageDto); }