Integrating Vue.js V4 In ASP.NET Core 3.1 MVC And File Uploading Using Dropzone

Introduction

 
We’re used to transferring a file through the browser on a website from the user’s computer/system to a different server. This process is known as file uploading. We know that in the Single-Page-Application, the entire page is loaded in the browser during the initial request and later on it can update the particular part of the section/page which is changed. That’s why we don’t need to reload the entire page for each update. To accomplish the file uploading, we can divide it into two parts. The front-end/UI part of the file upload will be handled using Vue.js and the logical file saving part/back-end will be handled using ASP.NET Core 3.1 MVC. The single file will be buffered in memory using IFormFile and the file content will be accessible as the stream.
 

Topics

  1. Introduction & installation of Node.js and NPM
  2. Introduction & installation of Vue.js V4
  3. Introduction & installation of VS 2019 for Dot NET Core 3.1
  4. Introduction & run instruction of NPM and WebPack Task Runner
  5. Integrating/configuring Vue.js with ASP.NET Core 3.1 MVC
  6. Configuration/setup DropZone with Vue.js and ASP.NET Core MVC
Prerequisites
  • Need Visual Studio 2019 for the .NET Core 3.1
  • Install Node.js, NPM and Vue.js
  • Need WebPack Task Runner to compile the JS files visually
  • Need NPM Task Runner to install/update the packages visually
Here are some questions for you:
  • Why do you choose Vue.js? - Do you have the option to choose the JS framework (say, Angular/React/Vue.js etc.)? If yes, then which one should be good for you and why? Or, don't you have the option to choose, and your team already chose a JS framework (say, Vue.js) for you? If so, then why did they choose it, was there another alternative?
  • Why do you choose NPM? - If you have the option to choose Bower, Yarn or NPM, then why did you choose NPM?
  • Why do you choose WebPack? -If you have the option to choose Grunt, Gulp or WebPack, then why did you choose WebPack?

Introduction to Node.js

  • Node.js is an open source command line tool. It uses the Google V8 JavaScript engine to execute the code.
  • Installation of Node.js/NPM - To download Node.js, click on the link (https://nodejs.org/en/download/)
  • Why do we need Node.js/NPM? - In short, you may need to install 3rd party packages in your application. NPM is the command-line utility which helps you to install the required packages. But without Node.js, you can't install NPM. You will be asked to install NPM with Node.js installation setup. So, install Node.js to run NPM.

Have you already installed Node.js/NPM?

 
Open the command-prompt, type: node -v and press enter. If you get the version number, that means you already have it on your machine.
  • To check the npm version, use the following command: npm -v
  • To upgrade the npm version, use the following command: npm i -g npm

Node/NPM version related common error

 
Suppose, you have the older version in your system and you have upgraded the latest version. Now if you get any error (like, "TypeError: log.gauge.isEnabled") during the version check using the following command: npm -v, then this is the npm package dependency issue. Remove all of the directories/files from the following path and re-install/repair the Node.js again,
  • C:\Users\[User-Name]\AppData\Roaming\npm-cache
  • C:\Users\[User-Name]\AppData\Roaming\npm

Introduction of Vue.js

 
Vue.js is a JavaScript framework for single-page-application (SPA) development. This one is similar to the Angular, React.js or Knockout and avoids page reload. Each of these has a different focus and you will have to decide which one is good for you according to your situation. If you have to play with dynamic DOM manipulation, then React.js is good. If you need data-driven CRUD operations, then Angular is good. The position of Vue.Js is in between these situations; but still it likes to deal with dynamic DOM manipulation. Although this is my personal opinion!
 

Installation of Vue.js V4

 
Use the following command to install the new version globally: npm install -g @vue/cli

Why do we need to uninstall previous versions of vue-cli? - If you already installed the vue-cli package (version: 1.0/2.0) globally and want to use new v4, then you have to uninstall the previous version. New version v4 is changed to @vue/cli from vue-cli.
  • To check the version, use the following command: vue --version
  • To uninstall it globally with NPM, use the command: npm uninstall vue-cli -g
  • To install it globally with NPM, use the command: npm install -g @vue/cli

Introduction of Dot NET Core

 
I don't need to introduce the Dot NET Framework. But if you target to run your application on multiple platform like Windows, Mac and/or Linux, then .NET Core is perfect. Because, it focuses on the micro-services. Another consideration, if you need docker-containers, then you know that containers is light weight comparing to virtual machine (VM).
 
Installation of Visual Studio 2019:

Introduction of WebPack/NPM Task Runner Explorer

 
Web-pack Task Runner Explorer is used to compile and bundle the JS files, whereas NPM Task Runner Explorer is used to install/update the dependencies packages.
 
Download and run the instructions for NPM/WebPack Task Runner for VS 2019:
This is required when you want to install/update 3rd party packages in the application manually. The “package.json” file is used to save the packages list and working with the Node.js and NPM. In this file, you may add the dependencies so the package name and version look like the following manner:
 
“devDependencies”: {“PackageName”: “VersionNumber”}
 
NPM_Task_Runner
 

How Web-Pack Works

 
Let's see the following situation.
  • End-User: Eva, I like your T-Shirt. Where did you get this? I want to buy one.
  • Eva.js: John gifted me this one.
  • End-User: Okay, talk to John and ask him where he got it.
  • Eva.js: Hey John, last Christmas, from where did you buy the T-Shirt that you gave me?
  • John.js: I have bought it from ABC store at IN.
So, the end-user sends one more Http-requests to get the expected result. This means that there is a dependency graph where Eva.js calls John.js. Now if you want to merge both of these JS files into one bundle, then a single http-request is okay to find the file. So, you need the Web-Pack to make those bundles. You can concat, minify and/or uglify your JS files using the Web-Pack. (Concatenation is appending all of the files into one large file; Minification is removing unnecessary whitespace and character without changing the functionality; Uglification is converting the code in such a format that it will be difficult to understand.)
 

Why Need Web-Pack Task Runner?

 
In short, considering the above situation we can say that you need the Web-Pack Task Runner to compile and bundle the JS files.

WebPack_Task_Runner
 
The "webpack.config.js" file pulls all of the configuration and has an entry point to bring all of the JS files configuration to where the bundler starts. Then it uses output to get the path and file name configuration to generate the bundle.
  1. module.exports = {  
  2. entry: {   app: './wwwroot/js/app.js'  },  
  3. output: {  
  4.         publicPath: "/dest/js/",  
  5.         path: path.join(__dirname, '/wwwroot/dest/js/'),  
  6.         filename: '[name].bundle.js'  
  7.     }  
  8. }  

Integrating Vue.JS with ASP.NET Core MVC Web Application

 
Project Creation
 
Assuming that you can create a new project “ASP.NET Core Web Application>Web Application (Model-View-Controller)”. If you don’t want to use the default jQuery library, then you can remove the files and folder from the “wwwroot>lib”, although this is optional.

 
Template Design
 
You can modify the default site.css and site.js file according to your requirements.
 
 

Adding Bootstrap into the App.js file of the project

 
Within the "wwwroot/css" directory, I added the app.css file for the CSS. Within the "wwwroot/js" directory, I added the app.js file to register the “Bootstrap” plugin to use material icons. I ended up with the following:
  1. import $ from 'jquery';  
  2.   
  3. //// Import the Bootstrap Material Design Theme  
  4. import 'bootstrap-material-design/dist/css/bootstrap-material-design.min.css';  
  5. import 'bootstrap-material-design/dist/js/bootstrap-material-design.min.js';  
  6. import 'material-design-colors/dist/material-design.min.css';  
  7.   
  8. //// Import the App Styles  
  9. import '../css/app.css';  
  10.   
  11. //// Initialize the Material Design elements when the page loads  
  12. $(document).ready(function () {  
  13.     $('body').bootstrapMaterialDesign  
  14.     $('[data-toggle="popover"]').popover  
Note: I add this file just for an example. In this project, I avoid the design/material-icon and focus on the configuration.
 

Adding NPM Packages into the package.json

 
You may need Vue, babel, WebPack, bootstrap etc. packages. Babel is a JavaScript transpiler that compiles and converts old ES5 JavaScript to make browser compatible. All of the packages are saved into the “package.json” file. Now you can install/update these packages using Package-Manager-Console or Task Runner Explorer. For example, I added some packages and ended up with the following:
  1. {  
  2.   "name""HR.App.Web",  
  3.   "version""1.1.1",  
  4.   "private"true,  
  5.   "devDependencies": {  
  6.     "babel-core""^6.26.3",  
  7.     "babel-loader""^7.1.5",  
  8.     "babel-preset-env""^1.7.0",  
  9.     "babel-preset-es2017""^6.24.1",  
  10.     "bootstrap""^4.1.3",  
  11.     "bootstrap-material-design""^4.1.1",  
  12.     "css-loader""^1.0.0",  
  13.     "fuse.js""^3.2.1",  
  14.     "jquery""^3.3.1",  
  15.     "material-design-colors""^1.0.2",  
  16.     "style-loader""^0.19.0",  
  17.     "uglifyjs-webpack-plugin""^1.3.0",  
  18.     "url-loader""^0.6.2",  
  19.     "vue""^2.6.10",  
  20.     "vue-loader""^15.4.2",  
  21.     "vue-template-compiler""^2.5.17",  
  22.     "webpack""^4.20.2",  
  23.     "webpack-cli""^3.1.1",  
  24.     "webpack-dev-server""^3.1.9"  
  25.   },  
  26.   "dependencies": {}  
  27. }  
If you want to install/update the packages from the package.json file using NPM Task Runner Explorer, then make use of the NPM Task Runner Explorer. If you don’t see the Task Runner Explorer, then select the Package.json and click on the right button of the mouse. Now from the Task Runner Explorer, select the install from the package.json and click on the right button of the mouse as shown in the below image. As a result, all of the packages will be installed.
 
 

The WebPack configuration and bundling the JS files

 
The Web-Pack Task Runner automatically triggers when it finds webpack.config.js file. The file ends up with following:
  1. "use strict";  
  2. const { VueLoaderPlugin } = require('vue-loader');  
  3. const path = require('path');  
  4. const webpack = require('webpack');  
  5. const UglifyJsPlugin = require('uglifyjs-webpack-plugin');  
  6.   
  7. module.exports = {  
  8.     entry: {  
  9.         app: './wwwroot/js/app.js',  
  10.         home: './Views/Home/Index.cshtml.js',  
  11.         errorDetail: './Views/Home/ErrorDetail.cshtml.js'  
  12.            },  
  13.     plugins: [  
  14.         new webpack.ProvidePlugin({  
  15.             '$''jquery',  
  16.             jQuery: 'jquery',  
  17.             'window.jQuery''jquery',  
  18.             Popper: ['popper.js''default']  
  19.         }),  
  20.         new VueLoaderPlugin()  
  21.     ],  
  22.   
  23.     optimization: {  
  24.         minimizer: [  
  25.             new UglifyJsPlugin({  
  26.                 cache: true,  
  27.                 parallel: true,  
  28.                 uglifyOptions: {  
  29.                     compress: false,  
  30.                     ecma: 6,  
  31.                     mangle: true  
  32.                 },  
  33.                 sourceMap: true  
  34.             })  
  35.         ]  
  36.     },  
  37.     output: {  
  38.         publicPath: "/dest/js/",  
  39.         path: path.join(__dirname, '/wwwroot/dest/js/'),  
  40.         filename: '[name].bundle.js'  
  41.     },  
  42.     module: {  
  43.         rules: [  
  44.             {  
  45.                 test: /\.js$/,  
  46.                 loader: 'babel-loader',  
  47.                 exclude: /(node_modules)/,  
  48.                 query: {  
  49.                     presets: ['es2017']  
  50.                 }  
  51.             },  
  52.             {  
  53.                 test: /\.css$/,  
  54.                 loaders: ['style-loader''css-loader']  
  55.             },  
  56.             {  
  57.                 test: /\.(png|jpg|gif)$/,  
  58.                 use: {  
  59.                     loader: 'url-loader',  
  60.                     options: {  
  61.                         limit: 8192  
  62.                     }  
  63.                 }  
  64.             },  
  65.             {  
  66.                 test: /\.vue$/,  
  67.                 loader: 'vue-loader'  
  68.             }  
  69.         ]  
  70.     },  
  71.     resolve: {  
  72.         alias: {  
  73.             vue: 'vue/dist/vue.js'  
  74.         },  
  75.         extensions: ['.js''.vue']  
  76.     }  
  77. };  
I already explained that on the top we need “Entry” to configure the source of the js files with the path to get the bundle later.
  1. entry: { app: './wwwroot/js/app.js', home: './Views/Home/Index.cshtml.js'}  
Output: This is the configuration of the output path and bundle name of compiled JavaScript files.
  1. output: { publicPath: "/dest/js/", path: path.join(__dirname, '/wwwroot/dest/js/'),  
  2.         filename: '[name].bundle.js'}  
If you want to compile and bundle the JS files using web-pack Task Runner Explorer, then make use of the Web-Pack Task Runner Explorer. If you don’t see the Task Runner Explorer, then select the webpack.config.js and click on the right mouse button. From the Task Runner Explorer, select Run in the webpack.config.js and click on the right button of the mouse as shown in the below image. As a result, all of the JS files will be built to the output directory (wwwroot\dest\js).
 
 

Why Drop-Zone?

 
It is easy to drag and drop a file onto it as well as to upload the file to the server. Lightweight JavaScript library and minimum code requires that you use it.
 
Adding Drop-Zone and configuring it in the JS and view file,
  • To install dropzone package, add the dropzone into the devDependencies of the package.json file. "devDependencies": {vue2-dropzone": "2.0.0" } 
  • If you open the webpack.config.js file then you will find that I already add the JavaScript source file with the path into the entry. entry: {home: './Views/Home/Index.cshtml.js'} 
  • In this project, find the ‘Index.cshtml’ View page and ‘Index.cshtml.js’ file in the View>Home directory. Open the Index.cshtml and add the dropzone and Javascript bundle file. Once added, you end up with following
In the dropzone,
  1. url: is used to send the posted file and it requires the path of the controller with the action method (“/Home/SubmitFile”).
  2. use-custom-dropzone-options: will be true if you want to customize the option; (I add the “useUploadOptions” variable in the Index.cshtml.js file.)
  3. dropzone-options: here you can customize the maxfiles, maxFileSizeInMB, acceptedFiles, dictDefaultMessage. (Find the “uploadOptions” in the Index.cshtml.js)
  4. v-on:vdropzone-success: This method is used after successfully uploading the file.
  5. v-on:vdropzone-error: This method is used if the upload has failed.
The Index.cshtml.js file is used for the Index.cshtml with the bundle named home.bundle.js. You end up with the following:
  1. import Vue from 'vue';  
  2. import Dropzone from 'vue2-dropzone';  
  3.   
  4. document.addEventListener('DOMContentLoaded'function (event) {  
  5.     let view = new Vue({  
  6.         el: document.getElementById('view'),  
  7.         components: {  
  8.             "dropzone": Dropzone  
  9.         },  
  10.         data: {  
  11.             message: 'This is the index page',  
  12.             useUploadOptions: true,  
  13.             uploadOptions: {  
  14.               acceptedFiles: '.png,.jpg,.pdf',  
  15.               dictDefaultMessage: 'To upload the file click here. Or, drop a file here.',  
  16.               maxFiles: 1,  
  17.               maxFileSizeInMB: 20,  
  18.               addRemoveLinks: true  
  19.             }  
  20.         },  
  21.         methods: {  
  22.             onUploaded: function (file, response) {  
  23.                 if (response.status === "OK" || response.status === "200") {  
  24.                     console.log('Successfully uploaded!');  
  25.                 }  
  26.                 else {  
  27.                     this.isVisible = false;  
  28.                     console.log(response.message);  
  29.                 }  
  30.             },  
  31.             onUploadError: function (file, message, xhr) {  
  32.                 console.log("Message ====> " + JSON.stringify(message));  
  33.             }  
  34.         }  
  35.     });  
  36. });  
Go to the home controller file and add the following code:
  1. [HttpPost("/Home/SubmitFile")]  
  2. public async Task<ActionResult> SubmitFile(IFormFile file)  
  3. {  
  4.     try  
  5.     {  
  6.         //// Todo: Validation  
  7.         //// Todo: check file-content  
  8.         string webRootPath = hostingEnvironment.WebRootPath;  
  9.         string fileLandingPath = Path.Combine(webRootPath, folderName);  
  10.   
  11.         StreamReader stream = new StreamReader(file.OpenReadStream());  
  12.   
  13.         if (!Directory.Exists(fileLandingPath))  
  14.         {  
  15.             Directory.CreateDirectory(fileLandingPath);  
  16.         }  
  17.   
  18.         string filePath = string.Format("{0}\\{1}{2}", fileLandingPath,  
  19.             Path.GetFileNameWithoutExtension(file.FileName), Path.GetExtension(file.FileName));  
  20.   
  21.         using (var fileStream = new FileStream(filePath, FileMode.Create))  
  22.         {  
  23.             await file.CopyToAsync(fileStream);  
  24.         }  
  25.   
  26.         var jsonResult = Json(new { status = "OK" });  
  27.         return jsonResult;  
  28.     }  
  29.     catch (Exception ex)  
  30.     {  
  31.         return Json(new { status = "Error", message = ex.Message });  
  32.     }  
  33. }  
Now Select the Web-pack Task Runner to compile and bundle the JS files. Select Run and right click on the mouse button, then you will find the run and Bindings options. Click on the Run. Wait few seconds, and you will get the results in the “wwwroot\dest\js” directory.
 
Now you are ready to run the application. After running, you will find the following upload control:
 
 
Note
In this article, I primarily focus on configuration and setup. So, I didn’t care about the latest version of the packages. You should use the latest version of the packages.