【发布时间】:2018-05-28 13:12:36
【问题描述】:
我正在设计一个需要处理大文件的文件上传 API。我想远离传递字节数组。文件的端点存储将是第三方,例如 Azure 或 Rackspace 文件存储。
我有以下项目结构,遵循 DDD:
- Web API(Netcore - 接受上传的文件)
- 业务服务(调用 Azure 以保存文件并将记录保存到数据库)
- 域(EF 域模型)
- 持久性(存储库 EFCore - 保存数据库更改)
我希望在每个方法中都有可以在上传开始后立即开始通过上传文件流的方法。我不确定这是否可能?
之前我们使用 byte[] 将文件通过层传递,但对于大文件,这似乎需要大量内存来执行此操作并给我们带来了问题。
是否可以通过ntier应用优化文件的上传,这样就不用复制大字节数组了,如果可以,怎么做?
为了澄清,代码结构如下所示。存储库的东西已被排除:
namespace Project.Controllers
{
[Produces("application/json")]
[Route("api/{versionMNumber}/")]
public class DocumentController : Controller
{
private readonly IAddDocumentCommand addDocumentCommand;
public DocumentController(IAddDocumentCommand addDocumentCommand)
{
this.addDocumentCommand = addDocumentCommand;
}
[Microsoft.AspNetCore.Mvc.HttpPost("application/{applicationId}/documents", Name = "PostDocument")]
public IActionResult UploadDocument([FromRoute] string applicationId)
{
var addDocumentRequest = new AddDocumentRequest();
addDocumentRequest.ApplicationId = applicationId;
addDocumentRequest.FileStream = this.Request.Body;
var result = new UploadDocumentResponse { DocumentId = this.addDocumentCommand.Execute(addDocumentRequest).DocumentId };
return this.Ok(result);
}
}
}
namespace Project.BusinessProcess
{
public interface IAddDocumentCommand
{
AddDocumentResponse Execute(AddDocumentRequest request);
}
public class AddDocumentRequest
{
public string ApplicationId { get; set; }
public Stream FileStream { get; set; }
}
public class AddDocumentResponse
{
public Guid DocumentId { get; set; }
}
public class AddDocumentCommand : IAddDocumentCommand
{
private readonly IDocuentRepository documentRepository;
private readonly IMessageBus bus;
public AddDocumentCommand(IDocumentRepository documentRepository, IMessageBus bus)
{
this.documentRepository = documentRepository;
this.bus = bus;
}
public AddDocumentResponse Execute(AddDocumentRequest request)
{
/// We need the file to be streamed off somewhere else, fileshare, Azure, Rackspace etc
/// We need to save a record to the db that the file has been saved successfully
/// We need to trigger the background workers to process the uploaded file
var fileUri = AzureStorageProvider.Save(request.FileStream);
var documentId = documentRepository.Add(new Document { FileUri = fileUri });
bus.AddMessage(new DocumentProcessingRequest { documentId = documentId, fileUri = fileUri });
return new AddDocumentResponse { DocumentId = documentId };
}
}
}
【问题讨论】:
-
这个文件究竟需要什么处理?此处理是否涉及完全读取该文件?
-
@Evk 不,我只需要将它传递给我们使用的任何文件存储提供商。例如,Rackspace Cloud 文件有方法:'cloudFiles.CreateObject(containerName, stream, fileUri);'和 Azure Blob 存储有方法 'blockBlob.UploadFromStream(fileStream);'
-
但是你说“但是文件需要先在我们的业务层进行一些处理”?
-
编辑后我仍然不清楚问题是什么。您可以在示例中的层之间传递
Stream,就像您想要的那样。它没有按您的预期工作还是什么? -
基本上你需要流式传输文件,尽管我认为这确实限制了你可以做些什么来“处理”它。这里有一些信息docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads
标签: c# asp.net-core asp.net-core-webapi n-tier-architecture