A thoughtful technical blog

Menu

Tag Archives: msbuild

As I start looking into building more high-performance web apps, we are lead into the area of Javascript and CSS bundling and minification. I know my “old-school” Javascript coding, but in recent years, there’s been a huge movement in the JS community regarding the whole toolchain, so i’m jumping in here.

Since most of the development in this area has been built in the JavaScript / HTML / CSS community, the most mature tools are there. So i’m going to do a documented test of the tools in use. In recent years, i’ve done most web development in Visual Studio w/C#, Javascript, HTML, CSS. But i do have a background in professional Perl web development (years ago), so i have a different perspective. I’m coming at the new front-end JS toolsets from a point of discovery, so this may be most useful if you are also new to it. Don’t treat this as a “how to do it the best way” article.

Grunt is a “JavaScript Task Runner”, which can be thought of as a build tool for JS code. It uses node.js for executing tasks.

Gulp is another JavaScript Task Runner. It is in the same role as Grunt, but works with a JS code function instead of a JSON config. Also, it uses Node Streams instead of temp files, and does not require a ‘plugin’ per library. I was going to write a Grunt how-to, but i changed my mind and will do Gulp.

We want some kind of task runner, since we need to:

read all the JS library files and ‘minify’ them to take up the least space possible

bundle the files into one JS file, to reduce the number of HTTP requests the client needs to make

Thus, static files will not work. The task runner need to run during design time, and probably build/deploy time as well.

Installing the Toolset

using Command Prompt or Powershell as a command line (i use command prompt here)

Then we can figure out later how to make it easier to use in Visual Studio and MSBuild.

OK, i installed Node and npm, the Node.js package manager. Think of node of being it’s own platform with its own infrastructure, its own EXE, and its own set of installable packages. NPM is how you install packages.

Installing Grunt (via NPM)

Run the “Node.js command prompt” as Administrator by right-clicking it in the start menu. Note: this is NOT the green “Node.js” shortcut, which will not work. Then in the prompt, type:

npm install -g grunt-cli

You will see it download and install. But never mind that/skip it, cause i just changed my mind (Javascript fashion changes rapidly – just hang on for the ride, and just make sure you know what problem a tool does before you try to use it). I like the gulpfile code syntax better that the grunt json format, and i heard it builds faster too.

Installing Gulp (via NPM)

Now that i changed my mind, here’s how we can install Gulp via NPM: (from the Getting Started)

npm install --global gulp

Seems to have installed some dependent libs i know nothing about. No prob.

Now on the command line, you can run the default ‘gulp’ command, which will do nothing.

Installing other JS libraries for use (via NPM)

The point of using a JS build tool is including other JS libraries in your project, for use at build time or run time. So for the sake of proof-of-concept, i will install the uglify lib (for minification), concat to bundle all js scripts, and the JQuery lib (for use in our client-side scripts).

There is a special gulp-uglify plugin (a bunch of others too), so we install that in the same way with npm.

npm install gulp-uglify --save-dev

concat also has a gulp plugin:

npm install gulp-concat --save-dev

I will install the standard JQuery lib as well. Note i can use NPM to install it, or i could have it Microsoft-style and install using NuGet. The only difference would be the path to the *.js files in the project.

npm install jquery --save-dev

jQuery installs to: /node_modules/jquery/dist/jquery.js

Create a primitive “real” app

I’m going to create a /scripts/app.js file which does a simple jQuery DOM manipulation.

Note i’ve created a new ‘scripts’ task, which is added as a dependent task to the ‘default’ task. The ‘scripts’ task is using the jquery.js file and all the *.js files in the /scripts/ directory as sources. They all go thru concat(), output to main.js , in the dist/js/ directory. They then go thru uglify().

Next,we run the ‘gulp’ command on the node command line. After a couple back and forth errors and corrections, we get this:

In Solution Explorer, you can refresh and now see the /dist/js/main.js file which was created.

It should contain our custom js code as well as the whole jQuery.

Then we can update the HTML reference to the new output bundle.js file, and see if it runs the same way. Delete the script tags for jquery.js and app.js, and add a single one for main.js

<script src="dist/js/main.js"></script>

When you run the same index.html in the browser, you should get the same “jQuery changed this.” output, even though the only js file is ‘main.js’. The output main.js is only 83K. I’m sure it could get smaller if we use gzip, etc. But it proves the concept works. It should be very easy to add other JS modules as needed.

The downside is installing this stuff to the project added 2,000 files under /node_modules/, adding about 12MB.

Visual Studio and MSBuild Integration

I did find some info on how to run Gulp and Grunt from withing VS as a post-build command, and hopefully in MSBuild as well:

Update: I installed the Task Runner Explorer per the article above. It does work to view/run targets in the Gulpfile.js, so you don’t have to run on the command line, or have to build to execute the tasks.

Continuous Deployment goes a step further than Continuous Integration, but based on the same principle: the more painless the deployment process is, the more often you will do it, leading to faster development in smaller, manageable chunks.

As a C#/ASP.NET developer deploying to an IIS server, the go-to tool from Microsoft is MSDeploy (aka WebDeploy). This article primarily discusses steps in Visual Studio 2010, Web Deploy 2.0, and TeamCity 7.1. I have read numerous articles which explain using Git w/TeamCity and MSBuild, but not so much specifically with MSDeploy.

My ideal setup is to have the CI server automate all the steps which would otherwise be done manually by the developer. I am using the TeamCity 7 continuous integration server. You can mix/match your own tools, but the basic steps would be the same:

Edit your VS web project “Package/Publish” settings

New code changes are committed to source control branch (in my case, Git)

TeamCity build configuration triggers builds from VCS repository (Git) when new commits are pushed up

I’ll go thru the steps in detail (except test running, which is important, but a separate focus).

Step 1: edit the Visual Studio project properties

When deploying, there are some important settings in the project which affect deployment. To see them, in your solution explorer, right-click (project name) -> Properties… , tab “Package/Publish Web” …

Configuration: Active (Debug) – this means the ‘Debug’ config is active in VS, and you are editing it. The ‘Debug’ and ‘Release’ configurations both can be selected and independently edited.

My first build after adding the web project did fail. Here’s the error:

C:\TeamCity\buildAgent\work\be5c9bc707460fdf\MyWebApp\MyWebApp\MyWebApp.csproj(727, 3): error MSB4019: The imported project ”C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets” was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

Step 5: Install the MS Web Deployment tool

I get the Web Deployment Tool here and install. After reboot, the TeamCity login has a 404 error. Turns out Web Deploy has a service which listens on port 80, but so does TeamCity Tomcat server. For short term, i stop the Web Deploy web service in control panel, and start the TeamCity web service. The purpose of the Web Deployment Agent Service is to accept requests to that server from other servers. We don’t need that, because the TeamCity server will act as a client, and deploy out to other web servers.

The Web Deployment Tool also has to be installed on the target web server. I’m not going to go too far into detail here, but you have to configure the service to listen as well, so when you run the deployment command, it accepts it and installs on the server. For the development server, i set up a new account named ‘webdeploy’ with permission to install. For production web servers, i’m not enabling it yet, but i did install Web Deploy so i can do a manual run on the server using Remote Desktop (will explain later).

This is a package and deploy in one step. However, i opted for a different path – separate steps for packaging and deployment. This will allow cases for building a Release package but manually deploying it.

So in our case, we’ll need to do the following:

Try using the “Debug” config. That will use our dev server web.config settings. XML transformations in Web.Debug.config get applied to Web.config during the MSBuild packaging (just as if you ran ‘Publish’ in Visual Studio).

MyWebApp.csproj : path to VS project file to build. There are important options in there which get set from the project Properties tabs.

/T:Package : create a ZIP package

/P:Configuration=Debug;PackageLocation=*** : run the Debug configuration. This is the same as Build in Visual Studio with the ‘Debug’ setting selected. The ‘Package Location’ is what it created. We will reference the package file later in the deployment command.

I tested this command running on my local PC first. When it was working, i ran the same on the CI server via Remote Desktop (for me, it’s a remote Windows 7 instance).

Step 7: Create a Web Deploy command to deploy the project

MsDeployServiceUrl – we’ll have to configure the development web server with Web Deploy service.

Set up user account to connect as (deployuser)

Have a complete working MSbuild.exe command which works on the command line

-dest:auto,wmsvc=devserver : use the settings in the package file to deploy to the server. The user account is an OS-level account with permission (i tried IIS users, but didn’t get it working). The hostname is specified, but not the IIS web site name (which is previously specified in the MSBuild project file in the project properties).

After deployment, i checked the IIS web server files, to make sure they had the latest DLLs and web.config file.

Step 8: Package and Deploy from the TeamCity build steps

Since we now have 2 good commands, we have to add them to the build steps:

MSBuild – Package step

Note – there is a special TeamCity MSBuild option, but i went with the command-line runner, just because i already had it set.

MSDeploy – Deploy step

In this case, i had to use the command-line runner, since there is no MSDeploy option.

When you run the build with these steps, if they succeed, we finally have automatic deployment directly from git!

You can review the logs in TeamCity interface after a build/deployment, to verify everything is as expected. If there are errors, those are also in the logs.

Now every time new code gets merged and pushed to git origin/master branch, it will automatically build and deploy the the development server. Another benefit is that the installed .NET assemblies will have version numbers which match the TeamCity build number, is you use the AssemblyInfo.cs patcher feature.

It will dramatically reduce the time needed to deploy to development – just check in your code, and it will build/deploy in a few minutes.