ngx-dropzone-wrapper + .NET Core Web API

По какой-то причине моя коллекция IFormFiles всегда пуста при отправке файлов из моего приложения Angular 5 в мой.NET Core Web API. Полагаю, я просто где-то просматривал конфигурацию. Кто-нибудь видит что-то не так с этим? Обратите внимание, что я использую ngx-dropzone-wrapper ( https://github.com/zefoy/ngx-dropzone-wrapper). Заранее спасибо!

home.component.html

<!-- Container -->
<div class="container">
    <form>
        <dropzone class="dropzone-container" [message]="'Click or drag groups of files to upload them to the Data Entry API'" (error)="uploadError($event)"
            (success)="uploadSuccess($event)" (queueComplete)="complete($event)" (sending)="sending($event)">
        </dropzone>
        <button (click)="processQueue()">Go</button>
    </form>
</div>
<!-- End Container -->

home.component.ts

import { Component, ViewEncapsulation, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { DropzoneComponent, DropzoneDirective, DropzoneConfigInterface } from 'ngx-dropzone-wrapper';
import { DataEntryService } from '../../services/data-entry.service';
import Swal from 'sweetalert2'

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class HomeComponent implements AfterViewInit {

  // References to the dropzone component
  @ViewChild(DropzoneComponent) componentRef: DropzoneComponent;
  dropzone: any;

  // Flag to determine whether or not the 'Yes' button should be shown
  uploading: boolean = false;

  //** Constructor */
  constructor(private _dataEntryService: DataEntryService) { }

  /** Lifecycle hook that is called after a this component's view has been fully initialized */
  ngAfterViewInit() {

    // Get a reference ot the dropzone component
    this.dropzone = this.componentRef.directiveRef.dropzone();
  }

  /** 
   * Sends all queued files to our API (not the Data Entry API)
   * Triggered when the user clicks the 'Yes' button
   * @returns {void}
   * */
  processQueue(): void {

    console.log('Processing the queue');

    this.dropzone.processQueue();
  }

  /** 
   * Gets the xhr object and the formData objects as second and third parameters, so they can be modified or additional data can be added
   * Triggered by dropzone just before each file is sent
   * @param {any} args - The dropzone arguments
   * @returns {void}
   * */
  sending(args: any): void {

    console.log('Sending files');
    console.log(args);
  }

  /** 
   * Displays an error messages if one or more files were rejected by dropzone
   * Triggered by dropzone when an upload was either successfull or erroneous
   * @param {any} args - The dropzone arguments
   * @returns {void}
   * */
  complete(args: any): void {

    console.log('File upload comlpete');

    let accepted = this.dropzone.getAcceptedFiles();
    let rejected = this.dropzone.getRejectedFiles();
    let queued = this.dropzone.getQueuedFiles();
    let uploading = this.dropzone.getUploadingFiles();

    console.log('Accepted:  ' + accepted.length);
    console.log('Rejected:  ' + rejected.length);
    console.log('Queued:  ' + queued.length);
    console.log('Uploading:  ' + uploading.length);

    if (queued.length === 0 && uploading.length === 0) {

      if (rejected.length > 0) {

        Swal({
          type: 'error',
          title: 'Rejected Files',
          text: rejected.length + ' of the files that you uploaded were rejected. Please close this modal, correct your errors and try again.'
        });

        this.uploading = true;
      }
    }
  }

  /** 
   * For now, this just writes success messages to the console for debugging purposes
   * Triggered when a file has been uploaded successfully
   * @param {any} args - The dropzone arguments
   * @returns {void}
   * */
  uploadSuccess(args: any): void {

    console.log('Upload successful');

    if (args && args[0]) {
      console.log('File Uploaded:  ' + args[0].name);
    }
  }

  /** 
 * For now, this just writes error messages to the console for debugging purposes
 * Triggered when an upload error occurs
 * @param {any} args - The dropzone arguments
 * @returns {void}
 * */
  uploadError(args: any): void {

    console.error('Upload Error');

    if (args && args[1]) {
      console.error(args[1]);
    }
  }

}

конфиг

const DEFAULT_DROPZONE_CONFIG: DropzoneConfigInterface = {

  // Where we should send the files (Default: null)
  url: 'http://localhost:61143/api/xray',

  // Whether the queue will be processed automatically
  autoProcessQueue: false,

  // Optional oject to send additional headers to the server (Default: null)
  headers: null,

  // How many file uploads to process in parallel (Default: null)
  parallelUploads: 500,

  // Name of the file parameter that gets transferred (Default: 'file')
  paramName: 'file',

  // Maximum file size for the upload files in megabytes (Default: null)
  maxFilesize: 500,

  // Comma separated list of mime types or file extensions (Default: null)
  acceptedFiles: '.jpg, .dcm, .dicom',

  // Whether to send multiple files in one request (Default: null)
  uploadMultiple: true,

  // Whether thumbnails for images should be generated
  createImageThumbnails: false,

  // Whether to add a link to every file preview to remove or cancel (if already uploading) the file
  addRemoveLinks: true
};

.NET Core Web API Controller

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using DataEntry.Data;
using System;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;

namespace DataEntry.API.Controllers
{
    [Produces("application/json")]
    [Route("api/xray")]
    public class XRayController : Controller
    {
        private readonly DataEntryContext _db;

        public XRayController(DataEntryContext db)
        {
            _db = db;
        }

        // POST: api/xray
        [HttpPost]
        public IActionResult AddXRay(ICollection<IFormFile> files)
        {
            try
            {
                if (files == null || files.Count == 0)
                {
                    // Always 0 files here
                    throw new Exception("One or more JPG or DICOM file is required to upload X-rays.");
                }

                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
    }
}

1 ответ

Вы можете попробовать заменить ICollection на IFormFile[]

Проблема в вашей конфигурации. изменение

paramName: file // to 
paramName: files

Вы должны поместить paramName в функцию (например, paramName: () => 'files'). Причину можно найти в самом файле dropzone.js:

// @options.paramName can be a function taking one parameter rather than a string.
// A parameter name for a file is obtained simply by calling this with an index number.
  _getParamName(n) {
    if (typeof this.options.paramName === "function") {
      return this.options.paramName(n);
    } else {
      return `${this.options.paramName}${this.options.uploadMultiple ? `[${n}]` : ""}`;
    }
  }

Вы хотите предотвратить присвоение индексного номера (например, file[0]) параметру paramName, иначе paramName не будет таким же, как в.NET Core Web API Controller.

Это то, что не задокументировано, мне тоже пришлось это найти, погрузившись в исходный код.

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