Ejemplo n.º 1
0
        //[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
        //[RequestSizeLimit(209715200)]
        public async Task <IActionResult> UploadPhysical([ModelBinder(BinderType = typeof(JsonModelBinder))] List <FileTag> tags)
        {
            Program.CleanAppMre.WaitOne();
            Program.CleanChatMre.WaitOne();
            Program.StreamingMre.Reset();

            try
            {
                _logger.LogInformation("File tags: {FileTags}", tags);

                var i = 0;
                var successUploads = new List <UploadInfoDto>();
                var failedUploads  = new List <UploadInfoDto>();

                if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
                {
                    throw new ClientException("上传失败", new List <string> {
                        "Not multipart content type."
                    });
                }

                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)
                    {
                        // 1. This check assumes that there's a file
                        // present without form data. If form data
                        // is present, this method immediately fails
                        // and returns the model error.
                        // 2. also check there is a tag correspond to the file
                        if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition) || (tags != null && i >= tags.Count))
                        {
                            if (tags != null && i >= tags.Count)
                            {
                                _logger.LogError($"Upload file {contentDisposition.FileName.Value} failed, no conresponding tag.");
                            }
                            else
                            {
                                _logger.LogError($"Upload file {contentDisposition.FileName.Value} failed, no file content disposition.");
                            }

                            // 记录上传失败的文件
                            failedUploads.Add(new UploadInfoDto {
                                Name = contentDisposition.FileName.Value, Index = i
                            });
                        }
                        else
                        {
                            _logger.LogInformation($"Uploading file {contentDisposition.FileName.Value} with tag {tags?[i].ToString() ?? "N/A"}.");

                            // Don't trust the file name sent by the client. To display
                            // the file name, HTML-encode the value.
                            var trustedFileNameForDisplay = WebUtility.HtmlEncode(contentDisposition.FileName.Value);
                            //var trustedFileNameForFileStorage = Path.GetRandomFileName();
                            var trustedFileNameForFileStorage = trustedFileNameForDisplay;

                            var fileInfo = tags == null ? null : await _fileInfoRepository.GetFileInfoAsync(trustedFileNameForFileStorage, tags[i]);

                            if (fileInfo == null)
                            {
                                // 文件不存在,保存文件并记录到数据库
                                // **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.

                                var streamedFileContent = await FileHelpers.ProcessStreamedFile(
                                    section, contentDisposition, ModelState,
                                    _permittedExtensions, _streamingSettings.Value.FileSizeLimit);

                                if (!ModelState.IsValid)
                                {
                                    // 记录上传失败的文件
                                    failedUploads.Add(new UploadInfoDto {
                                        Name = trustedFileNameForFileStorage, Index = i
                                    });
                                    ModelState.Clear();

                                    _logger.LogError($"Upload file {contentDisposition.FileName.Value} failed.");
                                }
                                else
                                {
                                    var folder = tags == null ? _streamingSettings.Value.StoredFilesPath : GetFolderByTag(tags[i]);
                                    //var folder = Path.Combine(_streamingSettings.Value.StoredFilesPath, tags?[i].ToString().ToLower() ?? string.Empty);

                                    _logger.LogInformation("folder: {folder}", folder);

                                    //Directory.CreateDirectory(folder);
                                    var filePath = Path.Combine(folder, trustedFileNameForFileStorage);

                                    _logger.LogInformation("Save file at path: {filePath}", filePath);

                                    // 文件写入文件系统
                                    using (var targetStream = System.IO.File.Create(filePath))
                                    {
                                        await targetStream.WriteAsync(streamedFileContent);
                                    }

                                    // 文件信息存入到数据库中
                                    var command = new CreateFileInfoCommand {
                                        Name = trustedFileNameForFileStorage, FileTag = tags[i]
                                    };
                                    await _mediator.Send(command);

                                    // 记录上传成功的文件
                                    successUploads.Add(new UploadInfoDto {
                                        Name = trustedFileNameForFileStorage, Index = i
                                    });

                                    // 向前兼容:拷贝文件
                                    if (tags == null)
                                    {
                                        //var distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.App.ToString().ToLower());
                                        var distFolder = GetFolderByTag(FileTag.App);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.AppOriginal.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.AppOriginal);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.AppThumbnail.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.AppThumbnail);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.AppVideo.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.AppVideo);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.Chat.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.Chat);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.ChatThumbnail.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.ChatThumbnail);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");

                                        //distFolder = Path.Combine(_streamingSettings.Value.StoredFilesPath, FileTag.ChatVideo.ToString().ToLower());
                                        distFolder = GetFolderByTag(FileTag.ChatVideo);
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");
                                    }
                                    else
                                    {
                                        var distFolder = _streamingSettings.Value.StoredFilesPath;
                                        System.IO.File.Copy(filePath, Path.Combine(distFolder, trustedFileNameForFileStorage), true);
                                        _logger.LogInformation($"Copied file {filePath} to {distFolder}");
                                    }

                                    _logger.LogInformation(
                                        "Uploaded file '{TrustedFileNameForDisplay}' saved to " +
                                        "'{TargetFilePath}' as {TrustedFileNameForFileStorage}",
                                        trustedFileNameForDisplay, folder,
                                        trustedFileNameForFileStorage);
                                }
                            }
                            else
                            {
                                // 文件已存在,直接记录为上传成功
                                successUploads.Add(new UploadInfoDto {
                                    Name = trustedFileNameForFileStorage, Index = i
                                });
                                _logger.LogInformation($"File {trustedFileNameForFileStorage} already exists in database, skip.");
                            }
                        }
                    }

                    i++;
                    // Drain any remaining section body that hasn't been consumed and
                    // read the headers for the next section.
                    section = await reader.ReadNextSectionAsync();
                }

                //return Created(nameof(StreamingController), null);
                var uploadStatus = new UploadStatusDto {
                    SuccessUploads = successUploads, FailedUploads = failedUploads
                };
                if (failedUploads.Count > 0)
                {
                    return(StatusCode((int)HttpStatusCode.BadRequest,
                                      ResponseWrapper.CreateErrorResponseWrapper(Arise.DDD.API.Response.StatusCode.ClientError, "Upload Failed.", null, uploadStatus)));
                }
                else
                {
                    return(Ok(ResponseWrapper.CreateOkResponseWrapper(uploadStatus)));
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                Program.StreamingMre.Set();
            }
        }