FormData не поступает в метод Post контроллера API

Я пытаюсь отправить файл из приложения Angular 5 на свой контроллер веб-API в .NET Core 2, но моя модель всегда пуста.

Если я смотрю инструменты Chrome, я вижу в запросе следующую полезную нагрузку формы:

------WebKitFormBoundaryHbjYM4AKAkl6rQFo
Content-Disposition: form-data; name = "quotationId"

4
------WebKitFormBoundaryHbjYM4AKAkl6rQFo
Content-Disposition: form-data; name = "quotationFile"; filename = "Analisis y Oferta E3M-v1.1.pdf"
Content-Type: application/pdf

------WebKitFormBoundaryHbjYM4AKAkl6rQFo--

Угловой POST:

  quotationFileUpload(files: FileList, quotationId: number) {
    if (files && files[0].size > 0) {
      const formData = new FormData();

      formData.append('quotationId', quotationId.toString());
      formData.append('quotationFile', files[0]);

      this.projectService.uploadQuotation(formData).subscribe(
        response => {
          this.alertService.success('Proyecto', 'Presupuesto subido correctamente.');
        },
        error => {
          this.alertService.error('Proyecto', error.error);
        }
      );
    }
  }

Угловой метод обслуживания:

  public uploadQuotation(quotation: FormData) {
    return this.http.post(this.config.apiUrl + '/projects/quotations/file', quotation);
  }

Код .NET:

/// <summary>
/// Upload a Quotation document.
/// </summary>
/// <param name = "model"></param>
[HttpPost("quotations/file")]
[ProducesResponseType(200, Type = typeof(Quotation))]
[ProducesResponseType(400, Type = typeof(string))]
[ProducesResponseType(404, Type = typeof(string))]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<ActionResult> UploadQuotation([FromForm] QuotationUploadViewModel model)
{
    try
    {
        var quotation = await _context.Quotations
                                      .AsNoTracking()
                                      .SingleOrDefaultAsync(c => c.QuotationId == System.Convert.ToInt32(model.QuotationId));

        if (quotation == null)
        {
            return NotFound($"Presupuesto con Id {model.QuotationId} no encontrado.");
        }

        _context.Quotations.Update(quotation);

        // Save file
        var filePath = Path.Combine(_hostingEnvironment.ContentRootPath, @"Uploads", model.QuotationFile.FileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await model.QuotationFile.CopyToAsync(stream);
        }

        quotation.FileName = model.QuotationFile.FileName;
        await _context.SaveChangesAsync();

        return Ok(quotation);
    }
    catch (System.Exception ex)
    {
        _errorResponseMsg = $"No se pudo subir el Presupuesto {model.QuotationId}: {ex.Message}";
        _logger.LogError(_errorResponseMsg);
    }

    return BadRequest(_errorResponseMsg);
}

ЦИТАТА ЗАГРУЗКАМОДЕЛЬ

using Microsoft.AspNetCore.Http;

namespace E3m.Api.ViewModels.E3m
{
    public class QuotationUploadViewModel
    {
        public string QuotationId { get; set; }
        public IFormFile QuotationFile { get; set; }
    }
}

В этом коде свойства модели всегда равны нулю в методе веб-API.

Есть идеи о том, как эта проблема? С Уважением

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
0
982
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Не уверен, что это поможет вам, но именно так я отправляю файлы в ASP.NET и сохраняю их в базе данных MSSQL.

Angular part:

MyService.ts:

SendFile(filescan, id: number) {
    if (filescan == null) { return Observable.of(0); }
    let fileList: FileList = filescan.target.files;
    if (fileList.length > 0) {
        let file: File = fileList[0];
        let formData: FormData = new FormData();
        formData.append('uploadFile', file, file.name);
        formData.append('id', id.toString());
        let headers = new HttpHeaders();
        return this._http.post<number>('faktura/savefile', formData, { headers: headers });
        }
    }

MyComponent.ts:

let answer: number;
this._Service.SendFile(this.fileScan, this.zr.ID)
    .takeUntil(this.ngUnsubscribe)
    .subscribe(
        result => { answer = result; },
        error => { this.errorMessage = <any>error; },
        () => {});

ASP.NET part

Контроллер:

[HttpPost]
    public IHttpActionResult savefile()
    {
        var httpRequest = HttpContext.Current.Request;
        if (httpRequest.Files.Count > 0)
        {
            foreach (string file in httpRequest.Files)
            {
                var postedFile = httpRequest.Files[file];
                var contentType = postedFile.FileName.Substring(postedFile.FileName.LastIndexOf(".") + 1);
                var id = Convert.ToInt32(httpRequest["id"]);
                byte[] Content = new byte[(int)postedFile.InputStream.Length];
                postedFile.InputStream.Read(Content, 0, (int)postedFile.InputStream.Length);                    
                var message = "";
                var r = _fileService.SaveFile(id, Content, contentType, ref message);
                if (message.Length > 0)
                {
                    return InternalServerError(new Exception(message));
                }
                else
                {
                    return Ok(r);
                }
            }
        }
        return Ok();
    }

Услуга:

public int SaveFile(int id, byte[] content, string contentType, ref string message)
{
    int result = 0;
    ConnectionStringSettings mySetting = ConfigurationManager.ConnectionStrings["MyConnection"];
    SqlConnection con = new SqlConnection(mySetting.ConnectionString);
    using (con)
    {
        con.Open();
        SqlTransaction transaction = con.BeginTransaction();
        try
        {           
            var query = "spSaveFiles";
            var parametri = new SQLHelper.SQLParametri
            {
                { "@ID", id },
                { "@ScanPrilog", content },
                { "@ContentType", contentType }
            };
            result = SQLHelper.ExecuteNonQuery(CommandType.StoredProcedure, query, transaction, parametri);
            transaction.Commit();
        }
        catch (SqlException sqlError)
        {
            transaction.Rollback();
            message = sqlError.Message;
            result = 0;
        }
        return result;
    }
}
Ответ принят как подходящий

Я обнаружил проблему ... в Angular я добавлял заголовок ко всем своим запросам с помощью Content-Type: application / json через перехватчик. Удаление этого заголовка работает нормально.

Спасибо

Другие вопросы по теме