Загрузка файла из Angular в ASP.NET Core
Впервые я пытаюсь загрузить файл из компонента Angular на веб-страницу ASPNET Core и просто не могу заставить его работать. Надеюсь, следующих фрагментов кода будет достаточно, чтобы показать основную часть того, что происходит. Проблема в том, что хотя я подтверждаю, что переданный параметр методу post HttpClient (frmData) действителен, метод действия ASPNet Core никогда его не видит и сообщает, что IFormFile всегда имеет значение null.
РЕДАКТИРОВАТЬ: я ранее пробовал использовать multipart / form-data в качестве типа содержимого, но я дал необработанное исключение в кишках Kestrel. Теперь я понимаю, что это правильный способ сделать это, и использование типа содержимого json было источником моей ОРИГИНАЛЬНОЙ проблемы. Но я не знаю, что делать дальше. Я вижу из некоторых поисковых запросов, что существует около \ миллиарда различных причин возникновения этого исключения.
POST Выполняющая конечная точка 'JovenesA.Controllers.StudentssController.PostStudentGradesReport (JAWebAPI)' 04: 55: 38.4853 Информация ControllerActionInvoker Маршрут POST соответствует {action = "PostStudentGradesReport", controller = "Becas"}. Выполнение действия JovenesA.Controllers.BecasController.PostStudentGradesReport (JAWebAPI) 04: 55: 38.5032 Ошибка DeveloperExceptionPageMiddleware POST При выполнении запроса возникло необработанное исключение. 04: 55: 38.5333 Информация WebHost POST-запрос завершился за 48,1225 мс 500 текст / HTML; charset = utf-8 04: 55: 38.5333 Информация Пустельга Идентификатор соединения «0HM4UHGE85O17», идентификатор запроса «0HM4UHGE85O17: 00000006»: приложение завершено без чтения всего тела запроса.
Любая помощь будет принята с благодарностью!
Угловой компонент:
fileEntry.file((file: File) => {
console.log('fileEntry relativePath: ' + currFile.relativePath);
console.log('filEntry.name: ', file.name);
console.log('filEntry.size: ', file.size);
const frmData = new FormData();
frmData.append(file.name, file);
this.studentData.uploadStudentGradesReport(file.name, frmData).subscribe(
() => {
this.successMessage = 'Changes were saved successfully.';
window.scrollTo(0, 0);
window.setTimeout(() => {
this.successMessage = '';
}, 3000);
},
(error) => {
this.errorMessage = error;
}
);
});
Угловая служба:
public uploadStudentGradesReport(filename: string, frmData: FormData): Observable<any> {
const url = this.WebApiPrefix + 'students/' + 'student-grades-report';
const headers = new HttpHeaders().set('Content-Type', 'application/json');
if (frmData) {
console.log('ready to post ' + url + ' filename: ' + filename + ' options ' + headers);
return this.http.post(url, frmData, { headers });
}
}
Элемент управления ASPNET Core
// POST api/students/student-grades-report
[HttpPost("student-grades-report", Name = "PostStudentGradseReportRoute")]
//[ValidateAntiForgeryToken]
[ProducesResponseType(typeof(GradesGivenEntryApiResponse), 200)]
[ProducesResponseType(typeof(GradesGivenEntryApiResponse), 400)]
public async Task<ActionResult> PostStudentGradesReport([FromForm] IFormFile myFile)
{
_Logger.LogInformation("Post StudentGradesReport ");
if (myFile != null)
{
var totalSize = myFile.Length;
var fileBytes = new byte[myFile.Length];
Если это поможет, вот данные, которые отправляются в запросе POST.
ЗАПИСЬ http://192.168.0.16:1099/api/students/student-grades-report HTTP / 1.1 Хост: 192.168.0.16:1099 Подключение: keep-alive Длина содержимого: 13561 Принять: application / json, text / plain, * / * DNT: 1 Пользовательский агент: Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, как Gecko) Chrome / 87.0.4280.88 Safari / 537.36 Тип содержимого: приложение / json Происхождение: http: // localhost: 3000 Ссылка: http: // localhost: 3000 / Принятие кодировки: gzip, deflate Accept-Language: en-US, en; q = 0,9, es-MX; q = 0,8, es; q = 0,7 ------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a Content-Disposition: форма-данные; name = "test1.PNG"; filename = "test1.PNG" Тип содержимого: изображение / png PNG [двоичное содержимое файла изображения] ------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a--
Ответы
Вы отправляете файл как данные формы, поэтому вам необходимо указать правильный заголовок типа содержимого. В настоящее время ваша отправка application/json
в Content-Type
заголовке. Это верно даже при вызове API, что, по понятным причинам, поначалу может сбивать с толку. Правильный тип контента в этом случае - multipart/form-data
. Ваш API не видит, IFormFile
потому что считает, что запрос - это JSON. Я изменил ваш код Angular, указав правильное значение заголовка типа содержимого.
Изменить: оказывается, что указание Content-Type
заголовка вручную приведет к тому, что граничные значения не будут автоматически установлены в значении заголовка. Вместо этого простое решение - не добавлять заголовок самостоятельно, что приведет к автоматической установке надлежащего типа содержимого и граничных значений. Если вы установите заголовок самостоятельно, вам также придется установить граничные значения. В большинстве случаев лучшим решением будет оставить значение по умолчанию. Ссылка на вопрос / ответ, указывающий на это. FormData, как получить или установить границу в multipart / form-data - Angular
public uploadStudentGradesReport(filename: string, frmData: FormData): Observable<any> {
const url = this.WebApiPrefix + 'students/' + 'student-grades-report';
const headers = new HttpHeaders().set('Content-Type', 'multipart/form-data');
if (frmData) {
console.log('ready to post ' + url + ' filename: ' + filename + ' options ' + headers);
return this.http.post(url, frmData, { headers });
}
}
Вы также можете отметить расположение содержимого в предоставленном вами HTTP-запросе, которое показывает данные формы вместе с типом прикрепленного файла. Надеюсь это поможет. Я не запускал проект Angular для тестирования вашего кода, но тип содержимого должен исправить вашу проблему.
Изменить : я заметил, что вы используете имя файла в качестве ключа для поля формы с файлом. Вам нужно использовать такой ключ, как просто «файл» для поля формы, который должен соответствовать имени параметра в вашем коде контроллера. Вы можете получить фактическое имя файла в коде вашего контроллера, ключ просто указывает, к какому полю формы прикреплены файлы. пример
frmData.append('file', file);
А затем для действия вашего контроллера
public async Task<IActionResult> PostStudentGradesReport([FromForm] IFormFile file)
{
if (file.Length <= 0 || file.ContentType is null) return BadRequest();
var actualFileName = file.FileName;
using (var stream = file.OpenReadStream())
{
// Process file...
}
return Ok();
}
Я не могу гарантировать, что это сработает, но вы можете попробовать использовать Angular HttpRequest. Итак, в вашем сервисе angular попробуйте следующее:
const request = new HttpRequest (
'POST',
url, // http://localhost/your_endpoint
frmData,
{ withCredentials: false }
);
return this.http.request(request);
Также обратите внимание, что вам не следует выполнять проверку данных в функции, вызывающей backend Api. Что ваша функция вернет, если if(frmData)
она ложна?