using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.ViewModels;
using IRaCIS.Core.API.Controllers.Common;
using IRaCIS.Core.API.Filter;
using IRaCIS.Core.API.Utility;
using IRaCIS.Core.Application.Contracts.RequestAndResponse;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace IRaCIS.Api.Controllers
{
///
/// 文件上传
///
[Route("file")]
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")]
public class FileController : ControllerBase
{
private readonly IFileService _fileService;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IHostEnvironment _hostEnvironment;
private ILogger _logger;
private string _targetFilePath;
private readonly long _fileSizeLimit;
private readonly string[] _permittedExtensions = { ".pdf", ".doc", ".docx" };
public string trustedFileNameForFileStorage = "";
// Get the default form options so that we can use them to set the default
// limits for request body data.
private static readonly FormOptions _defaultFormOptions = new FormOptions();
private string defaultUploadFilePath = string.Empty;
public FileController(IFileService fileService, IConfiguration config,
IHostEnvironment hostEnvironment, ILogger logger,
IWebHostEnvironment webHostEnvironment)
{
_fileService = fileService;
_hostEnvironment = hostEnvironment;
_webHostEnvironment = webHostEnvironment;
_fileSizeLimit = config.GetValue("FileSizeLimit");
defaultUploadFilePath = Directory.GetParent(_hostEnvironment.ContentRootPath).FullName;
_logger = logger;
_logger.LogError("File Path:"+ defaultUploadFilePath);
// To save physical files to a path provided by configuration:
//_targetFilePath = config.GetValue("StoredFilesPath");
// To save physical files to the temporary files folder, use:
//_targetFilePath = Path.GetTempPath();
}
///
/// 上传文件[FileUpload]
///
/// 附件类型
/// 医生Id
/// 返回文件信息
[HttpPost, Route("uploadFile/{attachmentType}/{doctorId}")]
[DisableFormValueModelBinding]
public async Task UploadOrdinaryFile(string attachmentType, Guid doctorId)
{
_logger.LogError("aaaa");
#region 官方文档方式
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
ModelState.AddModelError("File",
$"The request couldn't be processed (Error 1).");
// Log error
return BadRequest(ModelState);
}
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(Request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
var hasContentDispositionHeader =
ContentDispositionHeaderValue.TryParse(
section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
// This check assumes that there's a file
// present without form data. If form data
// is present, this method immediately fails
// and returns the model error.
if (!MultipartRequestHelper
.HasFileContentDisposition(contentDisposition))
{
ModelState.AddModelError("File",
$"The request couldn't be processed (Error 2).");
// Log error
return BadRequest(ModelState);
}
else
{
// Don't trust the file name sent by the client. To display
// the file name, HTML-encode the value.
var trustedFileNameForDisplay = WebUtility.HtmlEncode(
contentDisposition.FileName.Value);
//var trustedFileNameForFileStorage = Path.GetRandomFileName();
trustedFileNameForFileStorage = contentDisposition.FileName.Value;
// **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, _fileSizeLimit);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//实际文件处理
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile/" + doctorId + "/");
var doctorAttachmentUploadFolder = Path.Combine(uploadFolderPath, attachmentType);
_targetFilePath = doctorAttachmentUploadFolder;
if (!Directory.Exists(doctorAttachmentUploadFolder)) Directory.CreateDirectory(doctorAttachmentUploadFolder);
using (var targetStream = System.IO.File.Create(
Path.Combine(_targetFilePath, trustedFileNameForFileStorage)))
{
await targetStream.WriteAsync(streamedFileContent);
var attachmentPath = $"/UploadFile/{doctorId}/{attachmentType}/{trustedFileNameForFileStorage}";
return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath }));
}
}
}
// 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(FileTestController), null);
#endregion
}
///
/// 上传文件( 不是医生个人的文件)[FileUpload]
/// 例如:阅片章程等
///
/// 文件类型
///
[HttpPost, Route("uploadNonDoctorFile/{type}")]
[DisableFormValueModelBinding]
public async Task UploadNonDoctorFile(string type)
{
#region New Test 实测OK
//上传根路径
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile");
if (uploadFolderPath != null)
{
//文件类型路径处理
var uploadTypePath = Path.Combine(uploadFolderPath, type);
if (!Directory.Exists(uploadTypePath)) Directory.CreateDirectory(uploadTypePath);
////实际文件处理
_targetFilePath = uploadTypePath;
//获取boundary
#region 方式二
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(Request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
#endregion
#region 方式一
//var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
#endregion
//得到reader
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
//{ BodyLengthLimit = 2000 };//
var section = await reader.ReadNextSectionAsync();
//读取section
while (section != null)
{
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
trustedFileNameForFileStorage = contentDisposition.FileName.Value;
await WriteFileAsync(section.Body, Path.Combine(_targetFilePath, trustedFileNameForFileStorage));
#region 方式二
//using (var targetStream = System.IO.File.Create(
// Path.Combine(_targetFilePath, trustedFileNameForFileStorage)))
//{
// using (var memoryStream = new MemoryStream())
// {
// await section.Body.CopyToAsync(memoryStream);
// await targetStream.WriteAsync(memoryStream.ToArray());
// }
//}
#endregion
var attachmentPath = $"/UploadFile/{type}/{trustedFileNameForFileStorage}";
return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath }));
}
section = await reader.ReadNextSectionAsync();
}
return Created(nameof(FileController), null);
}
return new JsonResult(ResponseOutput.NotOk("服务器端映射路径操作失败"));
#endregion
}
///
/// 写文件导到磁盘
///
/// 流
/// 文件保存路径
///
public static async Task WriteFileAsync(System.IO.Stream stream, string path)
{
const int FILE_WRITE_SIZE = 84975;//写出缓冲区大小
int writeCount = 0;
using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true))
{
byte[] byteArr = new byte[FILE_WRITE_SIZE];
int readCount = 0;
while ((readCount = await stream.ReadAsync(byteArr, 0, byteArr.Length)) > 0)
{
await fileStream.WriteAsync(byteArr, 0, readCount);
writeCount += readCount;
}
}
return writeCount;
}
#region 上传无影响部分
///
/// 下载多个医生的所有附件
///
///
///
[HttpPost, Route("downloadDoctorAttachments")]
public IResponseOutput DownloadAttachment(Guid[] doctorIds)
{
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = _fileService.CreateDoctorsAllAttachmentZip(doctorIds)
});
}
///
/// 下载医生官方简历
///
///
///
[HttpPost, Route("downloadOfficialCV")]
public IResponseOutput DownloadOfficialResume(Guid[] doctorIds)
{
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = _fileService.CreateOfficialResumeZip(doctorIds)
});
}
///
/// 下载指定医生的指定附件
///
/// 医生Id
/// 要下载的附件Id
///
[HttpPost, Route("downloadByAttachmentId/{doctorId}")]
public IResponseOutput DownloadAttachmentById(Guid doctorId, Guid[] attachmentIds)
{
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds)
});
}
#endregion
}
}