May
12
Written by:
Michael Washington
5/12/2017 7:35 PM
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_73807ab2-da88-4359-9154-a5d9ace45b79.png)
You can easily implement file upload and management in a .Net Core C# Angular 2+ application using PrimeNG FileUpload.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_aa53cca3-2c86-4e1c-bac5-401a90107875.png)
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
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_03585cc8-c850-44c5-afcb-30e136ee6495.png)
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
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_44ce6c45-8bf0-40b9-888c-64fe65739a5d.png)
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.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_794ded11-b165-473f-ae45-859dbd65903a.png)
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.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_41a3d88b-7bf5-452e-9d2f-ce78a75d353d.png)
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
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_8003a807-3706-4400-b1e5-515765240700.png)
Create a directory at: ClientApp/components/upload.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_a42254f9-8bee-41f7-a4d5-a771b33cc908.png)
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.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_805bf63e-d622-465e-bcd0-3226e57eccce.png)
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.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_bffd24f7-d696-456c-8401-42ba3e3755b0.png)
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.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_22d6189e-280b-44e1-9622-4fd96f0fc0b6.png)
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
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_0d372f3b-6705-4315-85c7-b16a6aa7b175.png)
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
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_1a42a98b-832e-40ee-833c-9602999c4877.png)
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:
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_f5081778-1aa2-4fd1-98dc-c4c6b83b7ac6.png)
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>
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_99a1ee92-39a0-46f9-a2ef-f4b3486f64d9.png)
Run the application.
![image image](/Portals/0/Blog/Files/1/4305/Windows-Live-Writer-1cd74d135141_FF3D-image_16ae6234-1d0d-43b3-81fc-fb55afe8b6b7.png)
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
|