May 12

Written by: Michael Washington
5/12/2017 7:35 PM  RssIcon

image

You can easily implement file upload and management in a .Net Core C# Angular 2+ application using PrimeNG FileUpload.

image

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

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

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

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

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

Create a directory at: ClientApp/components/upload.

image

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

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

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

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

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

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

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

Run the application.

image

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.

Tags:
Categories:

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation