Gulp with Visual Studio

Recently, I worked on a ASP.NET 4.6 MVC 5 project which didn’t have anything MVC about it. ūüôā

It was a Single Page Application built on TypeScript, Knockout JS, CSS. Now, since it we didn’t have any server side code, we decided to give Gulp a try to concatenate and minify the JS and CSS files. Below I have explained the steps to configure gulp on ASP.NET 4.6 application with Visual Studio 2015. I created a sample application to explain the steps.

Disclaimer: This is my first attempt to use gulp in any of my projects. I do not claim to follow all the best practices. I you see there is anything I could have differently, please feel free to comment and share your ideas ūüôā

 

Install and set up Node.js

  • Download and Install node.js v4.4.4 from here
  • Once Node.js is installed, open Node.js Command Prompt
  • Execute command: npm install –global gulp-cli ‚Äď This command will install gulp globally.
  • Optionally, execute command npm install -g npm3.This will install npm3 alongside npm.The reason I installed npm3 alongside npm was because npm3 installs the dependencies in flat file structure while npm v2 installs the dependencies in hierarchical structure. For windows machine this can be issue as full file path could exceed more than 255 characters.

Configure Gulp in Visual Studio

  • Right click your Visual Studio project, and click new item. Search for NPM template. and select NPM Configuration File. This will add package.json file to your Visual Studio project.
    add-npm-package
  • Similarly, add Gulp Configuration File from installed template. This will add a file with name gulpfile.js to the Visual Studio Project. You will add your gulp tasks to concatenate and minify in this file.
    add-gulp-file.PNG
  • Now, add a JavaScript file with name gulp.config. This is a configuration file which will be later used by our gulpfile. It contains configuration settings like html source, js/css files source that needs to be minified, name of minified js file etc. A sample gulp.config file is shown below:
    module.exports = function() {
            var config = {
            htmlSource: [
                "index.html" /* The HTML file */
            ],
            js: [
                "./lib/js/Javascript1.js",
                "./lib/js/Javascript2.js" /* List of js files in the order as they appear in index.html*/
            ],
            minJs: "js-min.js", /* Minified JS file name */
            minJsDestination: "./lib/js/", /* Minified JS file destination */
            css: [
                "./lib/css/*.css" /* List of css files that need to be minified */
            ],
            minCss: "css-min.css", /* Minified CSS file name */
            minCssDestination: "./lib/css/" /* Minified CSS file destination */
        }
        return config;
    }
    
  • Now, open your html file where the minified js and css files need to be injected. Remove the css files reference from html file and add below code to your html file.
    <!-- inject:css -->
    <!-- endinject -->
    

    Similarly, remove the js files reference and add below code to your html.

    <!-- inject:js -->
    <!-- endinject -->
    
  • Next, we need to install the Gulp packages to first concatenate, minify js/ css files and later inject the minified files to html. To achieve this following packages need to be installed through NPM:
    • gulp – The streaming build system
    • gulp-csso – Minifies CSS
    • gulp-uglify – Minifies JS
    • gulp-inject – Injects file references into html
    • gulp-concat – Concatenates files
  • Open, Node.js Command Prompt. Go to your project folder and execute the below command.
    npm3 install --save-dev gulp gulp-csso gulp-uglify gulp-inject gulp-concat

    As you can see we used npm3 to install gulp packages locally to install the dependencies in a flat structure. And instead of installing each package one by one we used a single command to install all the packages together.

  • Once the packages are installed, go to package.json and you will see the installed packages under devDependencies. You will also notice a folder node_modules created under your project where all the packages are installed.
  • Next, we will start writing gulp tasks in gulpfile.js. Go to gulpfile.js and add the required packages you need for your tasks.
    var gulp = require("gulp");
    var concat = require("gulp-concat");
    var uglify = require("gulp-uglify");
    var minify = require("gulp-csso");
    var inject = require("gulp-inject");
    var config = require("./gulp.config")();
    
  • Now, add the gulp tasks to minify js and css files.
    // Task to minify JS
    gulp.task("min-all-js", function () {
        return gulp
            .src(config.js)
            .pipe(concat(config.minJs))
            .pipe(uglify())
            .pipe(gulp.dest(config.minJsDestination));
    });
    // Task to minify CSS
    gulp.task("min-all-css", function () {
        return gulp
       .src(config.css)
       .pipe(concat(config.minCss))
       .pipe(minify())
       .pipe(gulp.dest(config.minCssDestination));
    });
    

    To verify the above tasks go to View-> Other Windows -> Task Runner Explorer. In the Task Runner Explorer window you will see the two tasks created by you. Run these tasks from the window and verify that it creates the minified files in destination folder.

  • Now, add the gulp tasks to inject js and css files into html source
    // Task to inject minifed JS
    gulp.task("inject-min-js", function () {
        return gulp
        .src(config.htmlSource)
        .pipe(inject(gulp.src(config.minJsDestination + config.minJs)))
        .pipe(gulp.dest("."));
    });
    // Task to inject minifed CSS
    gulp.task("inject-min-css", function () {
        return gulp
        .src(config.htmlSource)
        .pipe(inject(gulp.src(config.minCssDestination + config.minCss)))
        .pipe(gulp.dest("."));
    });
    
  • With this we have created all our required gulp tasks. Next step is to run these tasks at the time of build. Go to Task Runner Explorer, right click task min-all-css, select Bindings -> Before Build. This will tell Visual Studio to run this task before the build starts. Similarly, add tasks min-all-js, min-inject-css, min-inject-js. Make sure these tasks are added in correct order.

    Gulp-task-binding.png
    Gulp task binding
  • That’s it. Now, just build the application. And you will see the gulp tasks are run before the build starts. If you go to your html source file, you will see the minified css and js files are injected into your html file.
    <!DOCTYPE html>
    <html>
    <head>
    <title>Gulp Test</title>
    <meta charset="utf-8" />
    <!-- inject:css -->
    <link rel="stylesheet" href="/lib/css/css-min.css">
    <!-- endinject -->
    </head>
    <body>
    	Gulp Test
    </body>
    </html>
    <!-- inject:js -->
    /lib/js/js-min.js
    <!-- endinject -->
    
Advertisements

Publish Web App to Azure Virtual Machine – Part 2

This post is Part 2 of the series – Publish web app to Azure VM. In this post I will take the application, we created in Part 1 and publish it on Azure Virtual Machine through Visual Studio Team Services.

Before you go any further I you recommend to go through Part 1 of the series, if you have not already.

As a pre-requisite I have assumed that your solution along with the publish profile you created in part 1 is checked in Visual Studio Team Services. For this demo I have used the Team Foundation as my version control. But steps are same if you have used Git as your version control.

Publish Web App from Visual Studio Team Services

First, go to your Visual Studio Team Services dashboard of your project. Your visual studio team services dashboard should look similar to the figure below:

visual-studio-dashboard.PNG
Visual Studio Team Services Dashboard

 

Now, click on Continuous Integrate to create your build definition. This will take you to a new page where you will see a “+” icon on left navigation pane.¬†Click on icon¬†to create a new build definition and then select Visual Studio template.

CI - step1.png
Create new build Definition

Click next, select your repository in the second step and then click create.

Your build definition will have some default build steps added. Keep only Nuget restore and remove rest of the build steps as this demo is focussed only on publishing the build to Azure VM.

ci-step3.PNG
Visual Studio Definition РNuget restore build step

Next, click on Add Build step and add MsBuild task from Add build step window. We will use MsBuild to publish the publish profile we created in first part of this series.

Now, select MS Build step and specify your MsBuild arguments as

/p:DeployOnBuild=true /p:PublishProfile="$(publishProfileName)" /p:Password="$(userServerPassword)" /p:Configuration="$(BuildConfiguration)"

Let us go through each argument one by one:

  • DeployOnBuild: Setting DeployOnBuild to true means, we will deploy the solution after building
  • PublishProfile: Defines the name of the publish profile we use for the deploying. We have provided the value of publish profile as user defined variable, $(publishProfileName). We will define this variable later.
  • Password: Defines the user password of the Azure virtual machine. Again, we have provided the value of password as variable $(userServerPassword) which we will define later.
  • Configuration: Defines the build configuration of the solution. This build configuration value can be either be¬†release or debug based on kind of deployment you are doing.

With this our build steps are completed.

ci-step4
Visual Studio Definition – MS Build Step

Next, we need to define the variables we used in MSBuild step. Select Variables tab in the build definition. Click, Add variable and give the variable name as publishProfileName. Provide the value of the variable same as the name of your publish profile. Click, on Add variable again and give the name of variable as userServerPassword. Provide password of Azure VM user in the value field of variable. Since, password is sensitive information, make sure to click on the lock icon present on the right side of the variable field.

For both the variables also check Allow at Queue Time. This will prompt the user to change the values of variables before queueing the build.

Also, notice that variable $(BuildConfiguration) is created by default so we do not need to add it again.

ci-step5.PNG
Visual Studio Definition – Variables

Next, you can optionally define the when this build definition would be executed from Triggers tab. You can chose to either build each check-in (Continuous Integration) or schedule it at a specific time.

Now, click save and provide the name of the build to complete our visual studio definition.

ci-step6.PNG
Visual Studio Definition – Save

With this all our build definition is complete. Now, just queue you build and verify that publish to Azure is successful.

ci-step7
Queue Build

Important Note

Your build definition may fail with error #ERROR_CERTIFICATE_VALIDATION_FAILED. This error comes up because the remote server has a self-signed certificate for the Remote Agent Service or the Web Management Service. In this case, you need to bypass the certificate validation. Go to your publish profile in your solution under Properties -> PublishProfiles. Add below line to the property group

<AllowUntrustedCertificate>True</AllowUntrustedCertificate>

This option should NOT be used for Production. In production make sure to have a valid certificate on remote server.

 

Publish Web App to Azure Virtual Machine – Part 1

This post is two-part series where I will explain how we can publish a web app to Azure Virtual Machine.

In the Part 1 of this post I have explained how to publish a web app directly from Visual Studio. In the Part 2, I will publish the same web app from Visual Studio Team Services.

Important Note: Publishing a web app from Visual Studio directly should be use only during development. Usually, developers do not have access to Production VMs.  In Production you can use PowerShell script to publish the web app outside the Visual Studio.

Prerequisites

  1. Active Azure Subscription.¬†Create your free Azure account¬†if you don’t¬†already have one.
  2. Windows¬†Virtual Machine on Azure: Follow these steps on to create an Azure Virtual Machine. For this demo I have created “Windows Server 2012 R2 Datacenter” with deployment mode as “Resource Manager“.
  3. Visual Studio 2015 – Update 2 with Azure SDK 2.9 or greater.
  4. Code repository on Visual Studio Team Services: Create an account on Visual Studio Team Services and set up your code repository using Git or Team Foundation Version Control. I have used TFS as my version control for this demo. This step is required only for part 2 of this series.

Configure Virtual Machine

1. Open http port 80 and web deploy port 8172

Our first step is to open http port 80 and web deploy port 8172 on Azure VM. In the classic Azure VM this step is straightforward. All you need to do is to create an endpoint. While port 80 is opened by default, you can follow these steps to open endpoint 8172.

In the Azure Resource Manager (ARM) VM we need to open both ports 80 and 8172. You can follow my previous blog post where I have explained how add an Inbound security rule to open port 80 on the Azure VM. Similarly, you need add an Inbound security rule to open port 8172 on the VM.

Your Inbound security rules window on Azure portal after adding rules to open the port should like figure below:

inbound-security-rules
Inbound security rules

 2. Configure DNS Name

With classic Azure VM, the cloud service is created automatically and you do not need to do anything special to configure DNS name.

To configure DNS name with ARM VM, follow the steps to configure azure vm in my previous blog post.

3. Set up web deploy on remote machine

Now, remote desktop on your virtual machine and install IIS on your machine. To install IIS, go to Add Roles and features Wizard and select Web Service (IIS), under Application Development select all options.

Now, install Web Platform Installer 5.0 on your server from this link. Once installed search for web deploy on the Web platform installer. Look for “Web Deploy 3.6 for Hosting Server” and install.

web-deploy-install.PNG
Install Web Deploy on Azure VM

The next step is to create a website in IIS where we will host our application. To keep the things simple for this demo, I will deploy my application on Default Web Site. Now, select your website from IIS. Then, under IIS Manager Permissions add user with appropriate permission.

iis-manager-permission.png
IIS on Azure VM

Before we proceed further make sure that you have opened port 8172 on Windows Firewall. For this you need to create following firewall rules on your machine:

Direction From Port To Port Port Type
Inbound Any 8172 TCP
Outbound 8172 Any TCP

Publish Web App from Visual Studio

For this demo I have created a simple MVC web application from the standard visual studio template. I modified the home page to show my machine name and hosting server. On local, my homepage looks like below:

localhost-homepge
Web App on localhost

Now, the next step is to create  a publishing profile to publish the web app directly from Visual Studio to Azure. Select the project, right click and select publish. On the publish window, expand More Options and select Microsoft Azure Virtual Machines.

select-azure-vm-option1.png
Select Publish target – Azure Virtual Machine

You will be then asked to login to the Microsoft Azure account. Login to your Azure account and then select the Windows VM you have created already.

select-azure-vm
Log in to Azure subscription and select Virtual Machine

Click Next and provide your publish details. Keep the publish method as “Web Deploy“. Do not change the server details. Provide the name of the site you created in previous steps. Provide your VM username and password.

publish-web
Validate Connection with Azure VM

 

Now, click Validate Connection to validate your connection. You may get a Certificate Error. This error comes up because the remote server has a self-signed certificate for the Remote Agent Service or the Web Management Service. Click Accept to bypass certificate validation.

validate-certificate
Bypass certificate validation

 

Click “Next” and then “Publish”. Once, the publish completes go to the publish URL to verify that the web app is up and running.

remote-homepage
Web App hosted on Azure Virtual Machine

 

Set up web app on new Azure Virtual Machines

Setting up a website on classic Azure Virtual Machine is straight forward as in classic Azure VM we have the Endpoints for port 80 and 443 open by default. For each classic Azure VM we also had cloud service created. Hence, if we host a website directly on port 80 or 443 it would work without much hassle.

Recently, I landed up in an issue where I created a new Windows Virtual Machine with deployment mode as “Resource Manager” and deployed my web app on Azure VM, but I did not find the¬†corresponding cloud service for the virtual machine. Hence, I could not¬†browse my application through internet since I didn’t have DNS. I then tried to access my application through public IP address of the Virtual Machine but again it didn’t work. After digging into various Virtual Machine options in new Azure Portal I found out the issue. The new Azure VMs do not have port 80 or 443 opened by default. Additionally, they do not have DNS configured by default. To resolve the issue you need to follow below two steps.

Open http port 80/ 443

The open port option in new Azure VM is a bit obscure. You need to go Virtual Machine -> Settings -> Network Interfaces -> Select Network Interface -> Network Security Group -> Settings -> Inbound security rules as explain in the below two figures.

open-endpoint1

open-endpoint2

 

Now, click on Inbound security rules and add a new inbound security rule to open port 80 as shown in figure below.open-port-80.png

 

Similarly, open port 443 or any other port where your application is hosted. With this you can now access your application via public port number.

But you still cannot access your application through DNS. For that you need to first configure DNS name.

Configure DNS Name

To configure DNS name you need to go to first go Network Interface as explained in the previous step. Now, Select Public IP address -> Settings -> Configuration as shown in figure below:

DNS-Configure1.PNG

Now, just provide preferred DNS name and you are free to access, test, share your web app.

DNS-Configure2.png

Hope this post helps someone to save time.