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 ответ
Проблема в вашей конфигурации. изменение
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.
Это то, что не задокументировано, мне тоже пришлось это найти, погрузившись в исходный код.