檔案上傳,是Web開發很普遍的一個需求。Angular 2 的部分,要怎麼處理這一塊呢?請繼續看下去...
緣起
承上篇「[筆記][WebAPI][Upload] WebAPI 檔案上傳範例」,本篇小喵記錄Angular 2 ( Angular 4 )的部分,在測試的過程中,比較大的問題在CORS的處理與解決,這部分,會針對 WebAPI 的部分,做一個補充。
安裝套件:ng2-file-upload
小喵這裡是使用別人寫好的套件「ng2-file-upload」,請輸入以下指令進行安裝:
npm i ng2-file-upload --save
特別注意:小喵發現,這一套件與小喵之前用的一個bootstrap套件「ngx-bootstrap」有衝突,會 把原本安裝好的套件移除如果您也遇到小喵一樣的狀況,請您再次把他裝回去即可。
AppModule
接著,先在AppModule中,處理好後續需要套件或模組:
import { FileUploader, FileDropDirective, FileSelectDirective } from 'ng2-file-upload';
import { HttpModule } from '@angular/http';
import { FormsModule } from '@angular/forms';
import { FormBuilder } from '@angular/forms';
//.....
@NgModule({
declarations: [
//...
UploadComponent,
FileDropDirective,
FileSelectDirective,
//...
],
imports: [
//...
FormsModule,
HttpModule,
//...
],
providers: [FormBuilder],
//...
})
其中 imports:[] 中的 「FormsModule, HttpModule」以前在 Angular 2 預設是載入的,但後來的 Angular-Cli 建立的 Angular 4 專案,這部分預設省略,我們把他補回來。
建立Component
接著,建立Component來撰寫上傳的相關部分,首先,透過以下的語法,產生Component 「Upload」
ng g c Upload
在AppComponent中,清掉原有的內容,使用這個Component
<app-upload></app-upload>
TS : upload.component.ts
import { Component, OnInit } from '@angular/core';
import { NgClass, NgStyle} from '@angular/common';
import { FileUploader } from 'ng2-file-upload'
// const URL = '/api/';
// 請依據您的 WebAPI 的網址修正
const URL = 'http://localhost:56956/api/upload';
@Component({
selector: 'app-upload',
templateUrl: './upload.component.html',
styleUrls: ['./upload.component.css'],
})
export class UploadComponent implements OnInit {
constructor() { }
ngOnInit() {
}
public uploader:FileUploader = new FileUploader({url: URL});
public hasBaseDropZoneOver:boolean = false;
public hasAnotherDropZoneOver:boolean = false;
public fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e;
}
public fileOverAnother(e:any):void {
this.hasAnotherDropZoneOver = e;
}
}
CSS : upload.component.css
.my-drop-zone { border: dotted 3px lightgray; }
.nv-file-over { border: dotted 3px red; } /* Default class applied to drop zones on over */
.another-file-over-class { border: dotted 3px green; }
html, body { height: 100%; }
Html : upload.component.html
<form name="form1" method="post" enctype="multipart/form-data" action="api/upload">
<div class="container">
<div class="navbar navbar-default">
<div class="navbar-header">
<a class="navbar-brand" href>Angular2 File Upload</a>
</div>
</div>
<div class="row">
<div class="col-md-3">
<h3>Select files</h3>
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropZoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="well my-drop-zone">
Base drop zone
</div>
<div ng2FileDrop
[ngClass]="{'another-file-over-class': hasAnotherDropZoneOver}"
(fileOver)="fileOverAnother($event)"
[uploader]="uploader"
class="well my-drop-zone">
Another drop zone
</div>
Multiple
<input type="file" ng2FileSelect [uploader]="uploader" multiple /><br/>
Single
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
<div class="col-md-9" style="margin-bottom: 40px">
<h3>Upload queue</h3>
<p>Queue length: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th>Size</th>
<th>Progress</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.isHTML5">
<div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
</div>
</td>
<td class="text-center">
<span *ngIf="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
<span *ngIf="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
<span *ngIf="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
</td>
<td nowrap>
<button type="button" class="btn btn-success btn-xs"
(click)="item.upload()" [disabled]="item.isReady || item.isUploading || item.isSuccess">
<span class="glyphicon glyphicon-upload"></span> Upload
</button>
<button type="button" class="btn btn-warning btn-xs"
(click)="item.cancel()" [disabled]="!item.isUploading">
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
</button>
<button type="button" class="btn btn-danger btn-xs"
(click)="item.remove()">
<span class="glyphicon glyphicon-trash"></span> Remove
</button>
</td>
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress" style="">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="glyphicon glyphicon-upload"></span> Upload all
</button>
<button type="button" class="btn btn-warning btn-s"
(click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
<span class="glyphicon glyphicon-ban-circle"></span> Cancel all
</button>
<button type="button" class="btn btn-danger btn-s"
(click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
<span class="glyphicon glyphicon-trash"></span> Remove all
</button>
</div>
</div>
</div>
</div>
</form>
執行結果:
Angular 2 (Angular 4)的部分,到這邊就完成囉。可以單筆選取,多筆選取,拖拉放,一次上傳多筆的介面也大多OK,到最後的測試結果也OK沒問題。不過~
剛開始測試,結果在上傳的時候,發生問題,原因是原本的WebAPI,沒有撰寫『CORS』跨網域的相關處理。
所以,接下來,又回到Server端的 WebAPI 程式,要來處理 WebAPI CORS的部分
WebAPI CORS處理
nuget : WebAPI CORS
WebAPI 2後,有套件可以簡單容易的去處理 CORS的問題,所以,首先,開啟NuGet套件管理員,要把 WebAPI CORS 的套件裝起來
App_Start / WebApiConfig
加上 Imports 與設定
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web.Http
Imports System.Web.Http.Cors '<--這裡
Public Module WebApiConfig
Public Sub Register(ByVal config As HttpConfiguration)
' Web API 設定和服務
config.EnableCors() '<--這裡
' Web API 路由
config.MapHttpAttributeRoutes()
config.Routes.MapHttpRoute(
name:="DefaultApi",
routeTemplate:="api/{controller}/{id}",
defaults:=New With {.id = RouteParameter.Optional}
)
End Sub
End Module
修改Controller設定
Imports System.Web.Http.Cors
Namespace Controllers
<EnableCors("*", "*", "*", SupportsCredentials:=True)>
Public Class UploadController
'....以下略
其中,SupportsCredentials在以前小喵沒有這樣設定,不過這次在測試的時候,發現以下這樣的問題
所以,「, SupportsCredentials:=True」這個設定請不要忘記。
參考資料:
- http://valor-software.com/ng2-file-upload/
- http://www.inoaspect.com.au/uploading-files-angular-2-asp-net-core-web-api-part-1/
相關程式碼:
https://github.com/topcattw/Angular2WebApiFileUploadSample
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
- 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
Microsoft MVP Visual Studio and Development Technologies (2005~2019/6) | topcat Blog:http://www.dotblogs.com.tw/topcat |