gpt4 book ai didi

c# - ASP.NET Core Web 应用程序 - 如何上传大文件

转载 作者:行者123 更新时间:2023-12-05 04:41:23 24 4
gpt4 key购买 nike

问题

我正在尝试创建一个 ASP.NET Core (3.1) Web 应用程序,它接受文件上传,然后将其分成 block 以通过 MS Graph API 发送到 Sharepoint。这里还有一些其他帖子解决了类似的问题,但它们假设我具有一定程度的 .NET 知识,而我还没有。所以我希望有人能帮我拼凑一些东西。

配置 Web 服务器和应用以接受大文件

我已完成以下操作以允许 IIS Express 上传最多 2GB 的文件:

a) 使用以下代码创建一个 web.config 文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

<location path="Home/UploadFile">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<security>
<requestFiltering>
<!--unit is bytes => 2GB-->
<requestLimits maxAllowedContentLength="2147483647" />
</requestFiltering>
</security>
</system.webServer>
</location>
</configuration>

B) 我的 Startup.cs 配置部分有以下内容:

        //Add support for uploading large files  TODO:  DO I NEED THIS?????
services.Configure<FormOptions>(x =>
{

x.ValueLengthLimit = int.MaxValue; // Limit on individual form values
x.MultipartBodyLengthLimit = int.MaxValue; // Limit on form body size
x.MultipartHeadersLengthLimit = int.MaxValue; // Limit on form header size
});

services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = int.MaxValue; //2GB
});

我的表单如下所示,它允许用户选择文件并提交:

@{
ViewData["Title"] = "Messages";
}
<h1>@ViewData["Title"]</h1>

<p></p>
<form id="uploadForm" action="UploadFile" method="post" enctype="multipart/form-data">
<dl>
<dt>
<label for="file">File</label>
</dt>
<dd>
<input id="file" type="file" name="file" />
</dd>
</dl>

<input class="btn" type="submit" value="Upload" />

<div style="margin-top:15px">
<output form="uploadForm" name="result"></output>
</div>
</form>

这是 Controller 的样子:

    [HttpPost]
[RequestSizeLimit(2147483647)] //unit is bytes => 2GB
[RequestFormLimits(MultipartBodyLengthLimit = 2147483647)]
public async void UploadFile()
{
User currentUser = null;
currentUser = await _graphServiceClient.Me.Request().GetAsync();
//nothing have to do with the file has been written yet.

}

当用户单击文件按钮并选择一个大文件时,我不再收到 IIS 413 错误消息。伟大的。逻辑在我的 Controller 中找到了正确的方法。

但是我对这部分代码有如下疑问:

  • 当用户选择文件时……背后到底发生了什么?该文件是否确实已填充到我的表单中并且可以从我的 Controller 访问?

  • 它是流吗?

  • 我如何获取文件?

  • 如果最终,我需要使用 this type 将此文件发送到 Sharepoint一种方法(关于分块的最后一个示例),似乎最好的方法是将文件保存在我的服务器上的某个地方......然后复制示例代码并尝试将其分块?示例代码似乎指的是文件路径和文件大小,我假设我需要先将它保存到我的网络服务器的某个地方,然后再从那里获取。

  • 如果我确实需要保存它,您能否为我指出正确的方向 - 也许是一些示例代码可以告诉我如何在我的表单中获取 POSTed 数据并保存它?

  • 最终,这将需要重构没有 GUI 的操作系统...但它只是一个接受大文件上传到某处的 API。但我想我会先尝试学习如何以这种方式进行...然后重构以将我的代码更改为仅 API。

很抱歉提出新手问题。在此处发布之前,我曾尝试进行研究。但有些地方还是有点模糊。

编辑 1

根据其中一个已发布答案中的建议,我已经下载了 sample code这演示了如何绕过保存到 Web 服务器上的本地文件。它基于 this article

我再次创建了一个 web.config 文件 - 以避免来自 IIS 的 413 错误。我还编辑了允许的文件扩展名列表以支持 .pdf、.docx 和 .mp4。

当我尝试运行示例项目,并在“物理存储上传示例”部分下选择“使用 AJAX 将文件流式传输到 Controller 端点”时,它死在这里:

                // 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))
if (!MultipartRequestHelper
.HasFileContentDisposition(contentDisposition))
{
ModelState.AddModelError("File",
$"The request couldn't be processed (Error 2).");
// Log error

return BadRequest(ModelState);
}

正如代码上方的评论中所提到的,它正在检查表单数据,然后当它找到它时......它就死了。所以我一直在玩弄看起来像这样的 HTML 页面:

<form id="uploadForm" action="Streaming/UploadPhysical" method="post" 
enctype="multipart/form-data" onsubmit="AJAXSubmit(this);return false;">
<dl>
<dt>
<label for="file">File</label>
</dt>
<dd>
<input id="file" type="file" name="file" />asdfasdf
</dd>
</dl>

<input class="btn" type="submit" value="Upload" />

<div style="margin-top:15px">
<output form="uploadForm" name="result"></output>
</div>
</form>

我试过像这样删除表单:

<dl>
<dt>
<label for="file">File</label>
</dt>
<dd>
<input id="file" type="file" name="file" />
</dd>
</dl>

<input class="btn" type="button" asp-controller="Streaming" asp-action="UploadPhysical" value="Upload" />

<div style="margin-top:15px">
<output form="uploadForm" name="result"></output>
</div>

但是当我点击它时,这个按钮现在没有做任何事情。

此外,如果您想知道/它有帮助,我将一个文件手动复制到我计算机上的 c:\files 文件夹中,当示例应用程序打开时,它会列出该文件 - 证明它可以读取该文件夹.我添加了读/写权限,希望网络应用程序可以在我到达那一步时写入它。

最佳答案

我实现了一个类似的大文件 Controller ,但使用的是 mongoDB GridFS。

无论如何,流式传输是处理大文件的方式,因为它速度快且重量轻。是的,最好的选择是在发送之前将文件保存在服务器存储中。一个建议是,添加一些验证以允许特定扩展并限制执行权限。

回到你的问题:

The entire file is read into an IFormFile, which is a C# representation of the file used to process or save the file.

The resources (disk, memory) used by file uploads depend on the number and size of concurrent file uploads. If an app attempts to buffer too many uploads, the site crashes when it runs out of memory or disk space. If the size or frequency of file uploads is exhausting app resources, use streaming.

source 1

The CopyToAsync method enables you to perform resource-intensive I/O operations without blocking the main thread.

source 2

这里有例子。

示例 1:

using System.IO;
using Microsoft.AspNetCore.Http;
//...

[HttpPost]
[Authorize]
[DisableRequestSizeLimit]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
[Route("upload")]
public async Task<ActionResult> UploadFileAsync(IFormFile file)
{
if (file == null)
return Ok(new { success = false, message = "You have to attach a file" });

var fileName = file.FileName;
// var extension = Path.GetExtension(fileName);

// Add validations here...

var localPath = $"{Path.Combine(System.AppContext.BaseDirectory, "myCustomDir")}\\{fileName}";

// Create dir if not exists
Directory.CreateDirectory(Path.Combine(System.AppContext.BaseDirectory, "myCustomDir"));

using (var stream = new FileStream(localPath, FileMode.Create)){
await file.CopyToAsync(stream);
}

// db.SomeContext.Add(someData);
// await db.SaveChangesAsync();

return Ok(new { success = true, message = "All set", fileName});
}

使用 GridFS 的示例 2:

[HttpPost]
[Authorize]
[DisableRequestSizeLimit]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
[Route("upload")]
public async Task<ActionResult> UploadFileAsync(IFormFile file)
{
if (file == null)
return Ok(new { success = false, message = "You have to attach a file" });

var options = new GridFSUploadOptions
{
Metadata = new BsonDocument("contentType", file.ContentType)
};

using (var reader = new StreamReader(file.OpenReadStream()))
{
var stream = reader.BaseStream;
await mongo.GridFs.UploadFromStreamAsync(file.FileName, stream, options);
}

return Ok(new { success = true, message = "All set"});
}

关于c# - ASP.NET Core Web 应用程序 - 如何上传大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70102558/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com