May
12
Written by:
Michael Washington
5/12/2017 7:35 PM
You can easily implement file upload and management in a .Net Core C# Angular 2+ application using PrimeNG FileUpload.
We will start with the code from the blog post: Hello World Angular 2+ Data Sample Using JavaScriptServices .Net Core and PrimeNg.
Update Angular Base
Open the project in Visual Studio 2017 (or higher).
Open the file at Views/Shared/_Layout.cshtml and change the base href to the following:
<base href="~/" />
This will allow the Angular code to properly find the root of the application if we publish it to a location where it is not at the root of the web address (for example: http://localhost/HeloWorlData).
Note: This may already be set for you because the JavaScriptServices project will incorporate this automatically in the future.
Create The Server Side Code
Create a file at Models/SystemFile.cs using the following code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace HelloWorldData
{
public class SystemFile
{
public string FileName { get; set; }
public string FilePath { get; set; }
}
}
This class will be used to pass the contents of the Files directory to the Angular code.
Create a file at Controllers/WebApi/FilesController.cs using the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
using System.IO;
namespace HelloWorldData.Controllers
{
//api/Files
[Route("api/[controller]")]
public class FilesController : Controller
{
public List<SystemFile> colSystemFiles = new List<SystemFile>();
private readonly IHostingEnvironment _hostEnvironment;
public FilesController(IHostingEnvironment hostEnvironment)
{
_hostEnvironment = hostEnvironment;
// Set WebRootPath to wwwroot\Files directiry
_hostEnvironment.WebRootPath =
System.IO.Path.Combine(
Directory.GetCurrentDirectory(),
@"wwwroot\Files");
}
// api/Files/SystemFiles
#region public IEnumerable<SystemFile> SystemFiles()
[HttpGet("[action]")]
public IEnumerable<SystemFile> SystemFiles()
{
colSystemFiles = new List<SystemFile>();
if (Directory.Exists(_hostEnvironment.WebRootPath))
{
// Get Files
ProcessDirectory(_hostEnvironment.WebRootPath);
}
return colSystemFiles;
}
#endregion
// api/Files/DeleteFile
[HttpPost]
public IActionResult Post([FromBody]SystemFile file)
{
try
{
// Allow user to only delete a file in Files directory
string FileToDelete =
Path.Combine(_hostEnvironment.WebRootPath, file.FileName);
System.IO.File.Delete(FileToDelete);
}
catch (Exception ex)
{
throw ex;
}
return Ok();
}
// Utility
#region public void ProcessDirectory(string targetDirectory)
// Process all files in the directory passed in, recurse on any directories
// that are found, and process the files they contain.
public void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string[] fileEntries = Directory.GetFiles(targetDirectory);
foreach (string fileName in fileEntries)
{
ProcessFile(fileName);
}
// Recurse into subdirectories of this directory.
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
#endregion
#region public void ProcessFile(string path)
// Insert logic for processing found files here.
public void ProcessFile(string path)
{
string FileName = Path.GetFileName(path);
string FilePath = path;
colSystemFiles.Add(new SystemFile() { FileName = FileName, FilePath = FilePath });
}
#endregion
}
}
This will return a list of files in the Files directory to the Angular code.
It will also allow a user to delete a file.
Create a file at Controllers/WebApi/UploadController.cs using the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using System.Threading;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.Http;
namespace HelloWorldData.Controllers
{
//api/Files
[Route("api/[controller]")]
public class UploadController : Controller
{
public List<SystemFile> colSystemFiles = new List<SystemFile>();
private readonly IHostingEnvironment _hostEnvironment;
public UploadController(IHostingEnvironment hostEnvironment)
{
_hostEnvironment = hostEnvironment;
// Set WebRootPath to wwwroot\Files directiry
_hostEnvironment.WebRootPath =
System.IO.Path.Combine(
Directory.GetCurrentDirectory(),
@"wwwroot\Files");
}
// api/Upload
[HttpPost]
public IActionResult Index(ICollection<IFormFile> files)
{
if (!Request.HasFormContentType)
return BadRequest();
// Create wwwroot\Files directory if needed
if (!Directory.Exists(_hostEnvironment.WebRootPath))
{
DirectoryInfo di =
Directory.CreateDirectory(_hostEnvironment.WebRootPath);
}
var form = Request.Form;
// Process all Files
foreach (var file in form.Files)
{
// Process file
using (var readStream = file.OpenReadStream())
{
var filename = ContentDispositionHeaderValue
.Parse(file.ContentDisposition)
.FileName
.Trim('"');
filename = _hostEnvironment.WebRootPath + $@"\{filename}";
//Save file to harddrive
using (FileStream fs = System.IO.File.Create(filename))
{
file.CopyTo(fs);
fs.Flush();
}
}
}
return Ok();
}
}
}
This will allow a user to upload files.
Create The Angular Code
Create a directory at: ClientApp/components/upload.
Create a file at: ClientApp/components/upload/systemFile.ts using the following code:
/* Defines the SystemFile entity */
export interface ISystemFile {
fileName: string;
filePath: string;
}
This interface will be used by the Angular code. It matches the C# class that the server side controller uses to pass data to the Angular service that we will create next.
Create a file at: ClientApp/components/upload/files.service.ts using the following code:
import { Injectable } from '@angular/core';
import {
Http, Response, RequestOptions,
Request, RequestMethod, Headers
} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { ISystemFile } from './systemFile';
@Injectable()
export class FilesService {
constructor(private _http: Http) { }
getFiles(): Observable<ISystemFile[]> {
var _Url = 'api/Files/SystemFiles';
return this._http.get(_Url)
.map((response: Response) => <ISystemFile[]>response.json())
.catch(this.handleError);
}
deleteFile(file: ISystemFile): Observable<string> {
var _Url = 'api/Files';
// This is a Post so we have to pass Headers
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
// Make the Angular 2 Post
return this._http.post(_Url,
JSON.stringify(file), options)
.map((response: Response) => <string>response.statusText)
.catch(this.handleError);
}
// Utility
private handleError(error: Response) {
// in a real world app, we may send the server to
// some remote logging infrastructure
// instead of just logging it to the console
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
This service communicates with the server side C# code to display the files on the server, and to delete files on the server.
This service will be called by the component we will create next.
Create a file at: ClientApp/components/upload/files.component.ts using the following code:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import {
FileUploadModule,
DataTableModule,
SharedModule } from 'primeng/primeng';
import { ISystemFile } from './systemFile';
import { FilesService } from './files.service';
@Component({
selector: 'files',
templateUrl: './files.component.html'
})
export class FilesComponent implements OnInit {
errorMessage: string;
fileList: ISystemFile[] = [];
// Register the service
constructor(private _FilesService: FilesService) { }
ngOnInit(): void {
this.getFiles();
}
public getFiles() {
this.errorMessage = "";
//Clear Filelist
this.fileList = [];
// Call the service
this._FilesService.getFiles()
.subscribe((files) => {
for (let file of files) {
this.fileList.push({
fileName: file.fileName,
filePath: file.filePath
});
}
},
error => this.errorMessage = <any>error);
}
public onUpload(event) {
this.getFiles();
}
public deleteFile(file: ISystemFile) {
// Call the service
this._FilesService.deleteFile(file)
.subscribe((response) => {
// Refresh file list
this.getFiles();
},
error => this.errorMessage = <any>error);
}
}
This is the code behind file for the main component that will allows files to be uploaded, displayed, and deleted.
Create a file at: ClientApp/components/upload/files.component.html using the following code:
<span style="background-color: #FFFF00">{{errorMessage}}</span>
<h4>Upload File</h4>
<p-fileUpload name="myfile[]"
url="api/upload"
(onUpload)="onUpload($event)">
</p-fileUpload>
<h4>Files In Directory</h4>
<p-dataTable [value]="fileList">
<p-column styleClass="col-button"
[style]="{'width':'100px','text-align':'center'}">
<template let-file="rowData" pTemplate="body">
<button type="button"
pButton (click)="deleteFile(file)"
icon="fa fa-trash-o">
</button>
</template>
</p-column>
<p-column styleClass="col-button" header="File Name">
<template let-file="rowData" pTemplate="body">
<u><a href="Files/{{file.fileName}}"
target="_blank">{{file.fileName}}</a></u>
</template>
</p-column>
<p-column field="filePath" header="File Path"></p-column>
</p-dataTable>
Note that the fileUpload control is set to call the server side “api/upload” controller directly. We do not need to create an Angular service ourselves.
Add PrimeNG to the Angular Module
Open the file at ClientApp/app/components/app.module.ts.
Change the PrimeNG import to the following:
import {
ButtonModule, GrowlModule,
FileUploadModule,
DataTableModule,
SharedModule
} from 'primeng/primeng';
Also, add the following to the module import list:
FileUploadModule,
DataTableModule,
SharedModule
Add the New Component and Service and Routing
Make the additional changes below to add the files component, and service, and the routing for the component, to the module:
Finally, open the ClientApp/app/components/navmenu/navmenu.component.html file and add the following link:
<li [routerLinkActive]="['link-active']">
<a [routerLink]="['/files']">
<span class='glyphicon glyphicon-file'></span> Files
</a>
</li>
Run the application.
You can now click the Files link to take you to the page that will allow you to upload and delete files.
Links
PrimeNG FileUpload
Hello World Angular 2+ Data Sample Using JavaScriptServices .Net Core and PrimeNg
Building Single Page Applications on ASP.NET Core with JavaScriptServices
Visual Studio 2017
Download
The project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
You must have Visual Studio 2017 (or higher) installed to run the code.
1 comment(s) so far...
@Naresh - Please download the code, from the download page on this site, and compare it to your own.
By Michael Washington on
12/5/2018 4:47 AM
|