Я выполнил поиск в Интернете и добавил ограничение на размер запроса: -
[HttpPost]
[RequestSizeLimit(107374182400)]
public async Task PostFormData(List files, CancellationToken cancellationToken = default)
Я также пытался настроить ограничение в настройках приложения, json: -
"Kestrel": {
"Limits": {
"MaxRequestBodySize": 107374182400 // 100 GB example (1024*1024*1024)
}
}
Мне нужно сделать что-то еще?
Это JS-клиент: -
const abortControl = new AbortController();
const signal = abortControl.signal;
const fetchOpts = {signal:signal, method:'POST', body: fileHolder, cache:"no-cache"};
const response = fetch("https://localhost:7196/upload/PostFormData", fetchOpts).catch(
err => {
console.log("Upload failed: " + err.message);
return
})
if (signal.aborted) {
alert("Cancelled")
return
}
Размер файла — 10 737 418 240 байт — bigfile.txt
Тип контента по-прежнему представляет собой многочастный поток.
РЕДАКТИРОВАТЬ 1
Я хотел бы иметь возможность обрабатывать несколько файлов одновременно (полный код ниже). Тест на 10 ГБ был просто «тестом», чтобы доказать это. можно было бы сделать. Это редкое исключение, которое можно настроить.
Если я не могу использовать привязку [FromBody], что мне нужно изменить, если я выберу маршрут «Set MultipartBodyLengthLimit»?
[HttpPost]
[RequestSizeLimit(107374182400)]
public async Task PostFormData(List files, CancellationToken cancellationToken = default)
{
if (!Request.ContentType?.Contains("multipart/form-data") == true)
{
return BadRequest("Unsupported media type.");
}
if (files == null || files.Count maxTotalSize)
break;
}
if (totalBytes > maxTotalSize)
{
return BadRequest("Total File Size exceeds limit.");
}
var copyResults = new List();
var fileOptions = new FileStreamOptions()
{
Mode = FileMode.Create,
Access = FileAccess.ReadWrite,
Options = FileOptions.Asynchronous,
};
var loopOptions = new ParallelOptions { MaxDegreeOfParallelism = 3 };
await Parallel.ForEachAsync(files, loopOptions, async (file, _) =>
{
if (file.Length maxFileSize)
{
lock (_resultsLock)
{
copyResults.Add(new FileCopyStatus
{
FileName = file.FileName,
UploadStatus = (int)CopyStatus.Invalid,
Message = "File Size"
});
}
_logger.LogError("Invalid file copy for {file} prevented due to File Size", file.FileName);
}
// Check file.contentType and file.filename type
try
{
var filePath = Path.Combine(folder, file.FileName);
fileOptions.PreallocationSize = file.Length;
using (var stream = new FileStream(filePath, fileOptions))
{
await file.CopyToAsync(stream, cancellationToken);
}
lock (_resultsLock)
{
lock (_resultsLock)
{
copyResults.Add(new FileCopyStatus
{
FileName = file.FileName,
UploadStatus = (int)CopyStatus.Success
});
}
}
}
catch (TaskCanceledException)
{
lock (_resultsLock)
{
copyResults.Add(new FileCopyStatus
{
FileName = file.FileName,
UploadStatus = (int)CopyStatus.Cencelled
});
}
_logger.LogError("File copy for {file} cancelled.", file.FileName);
}
catch (Exception ex)
{
lock (_resultsLock)
{
copyResults.Add(new FileCopyStatus
{
FileName = file.FileName,
UploadStatus = (int)CopyStatus.Error,
Message = ex.Message
});
}
_logger.LogError(ex, "Error saving {file}", file.FileName);
}
});
if (cancellationToken.IsCancellationRequested)
{
}
return Ok(copyResults);
}
РЕДАКТИРОВАТЬ 2
Это поведение можно воспроизвести по желанию. Вот клиентский код, который я использую. Поместите код сервера в какой-нибудь контроллер и посмотрите, что я имею в виду.
СТОП: Моя ошибка: я работаю над новой версией кода, которая использует XHR вместо FETCH для получения событий прогресса. К сожалению, «рабочий» код, который я использовал для демонстрации большой загрузки, по-прежнему имел ОТМЕНУ через 10 секунд. Да, я чувствую себя глупо. Моя вина
body {
font-size: 14px;
}
#container {
position: relative;
display: flex;
width: 10em;
height: 10em;
padding: 0.9em;;
border: 1px solid black;
}
#div1 {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: lightblue;
}
#div2 {
--fade-time: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-image: url("data:image/svg+xml;utf8,
");
animation: pulseImage var(--fade-time) infinite;
}
body > p {
color: red;
font-size: 1.2em;
}
div > p {
font-weight: bold;
}
@keyframes pulseImage {
from {
opacity: 0;
}
to {
opacity: 0.7;
}
}
document.addEventListener("DOMContentLoaded", (e) => {
document.addEventListener('drop', function(e){ e.preventDefault() })
document.addEventListener('dragenter', function(e){ e.preventDefault(); e.dataTransfer.dropEffect = "none" })
document.addEventListener('dragover', function(e){ e.preventDefault(); e.dataTransfer.dropEffect = "none" })
const dropZone = document.getElementById("div2")
dropZone.addEventListener("dragenter", (e) => {
console.log("In enter " + e.target.id)
e.dataTransfer.dropEffect = "copy"
e.preventDefault()
e.stopPropagation()
document.getElementById("div2").style.setProperty("--fade-time","2.0s")
}, {capture: true})
dropZone.addEventListener("dragover", (e) => {
console.log("In over " + dropZone.id)
e.dataTransfer.dropEffect = "copy"
e.stopPropagation()
e.preventDefault()
})
dropZone.addEventListener("dragleave", (e) => {
console.log("In leave")
e.dataTransfer.dropEffect = "none"
e.preventDefault();
e.stopPropagation()
document.getElementById("div2").style.removeProperty("--fade-time")
}, {capture: true})
dropZone.addEventListener("drop", catchFiles)
})
async function catchFiles(e) {
e.preventDefault()
e.stopPropagation()
document.getElementById("div2").style.removeProperty("--fade-time")
console.log("File(s) dropped");
let fileHolder = new FormData()
let fileCount = 0
if (e.dataTransfer.items) {
[...e.dataTransfer.items].forEach((item, i) => {
if (item.kind === "file") {
const file = item.getAsFile()
console.log(`… file[${i}].name = ${file.name}`)
fileHolder.append("files", file, file.name)
fileCount++
}
});
} else {
[...e.dataTransfer.files].forEach((file, i) => {
console.log(`… file[${i}].name = ${file.name}`);
fileHolder.append("files", file, file.name)
fileCount++
});
}
if (fileCount == 0) {
alert("Zero files received")
return
}
alert("got " + fileCount + " files")
const abortControl = new AbortController();
const signal = abortControl.signal;
(function(ac){
var x = ac
setTimeout(
() => {
x.abort();
console.log("$*")
}, 10000)
})(abortControl)
const fetchOpts = {signal:signal, method:'POST', body: fileHolder, cache:"no-cache"};
const response = await fetch("https://localhost:7196/upload/PostFormData", fetchOpts).catch(
err => {
console.log("Upload failed: " + err.message);
return
});
if (signal.aborted) {
alert("Cancelled")
return
}
let resp
if (response.ok) {
resp = await response.json()
} else {
resp = await response.text()
}
console.log(resp)
}
File Drop Upload Example
Drag your file(s) into the Drop Zone
File Drop Zone
Подробнее здесь: https://stackoverflow.com/questions/798 ... le-at-will
Мобильная версия