Thursday 28 April 2011

Publishing an ASP.NET application using MSBuild

I've been meaning to automate some if not all of the build on the project I work on for some time. Initially I considered NANT, because I have previous experience with ANT, and MSBuild. After a very small amount of research I decided that MSBuild was the way to go. It's really a no brainer. NANT is no longer developed, whereas MSBuild is, and seems very similar, plus custom tasks can be written. 

At minimum I wanted to set up an automated build that:
  1. Built the project in a specified configuration
  2. Published the project
  3. Set the release version in the web.config
  4. Zipped the published files
  5. Transferred zip file to the server
Ideally I'd like to zip and deploy the files, unfortunately due to our appalling network connection unzipping over the network is very slow and doesn't save time, so I gave up on that idea. In addition to the above steps I wanted the process to be configurable for each developer without changing the MSBuild.xml file. For example it's likely that each developer will have slightly different paths to the project on their machine. The situation I wanted to avoid was having each developer change a path in the MSBuild.xml file and overwrite someone else's file when they did a checkout from source control.

Set up

The first thing to do is add the MSBuild.exe to your PATH environment variable. Typically the path will be something like: C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe.

Download the community tasks if you think you'll need them (you almost certainly will): http://msbuildtasks.tigris.org/.

Create an MSBuild.xml file in your project directory. The bare bones file looks like this:

<Project DefaultTargets="SomeDefaultTarget" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <Target Name="SomeDefaultTarget">        
          <!-- Do some stuff here -->    
     </Target>
</Project>
 
Actions are carried out by creating <Target> tags. Each <Target> tag contains one or more tasks like <MSBuild>, or <Copy> which are generally fairly self explanatory. Other important tags you'll need are <PropertyGroup>, for defining reusable properties; <ItemGroup>, for defined things like file groups; and <Import> for importing custom tasks. I'm not going to explain how these tags work, the documentation is pretty good, my aim in this blog is to describe how I overcame the particular problems I faced. 


Publishing

One of the first problems I had to figure out was how to publish the files as you don't want all the files in your project to be in your web site. Turns out it's pretty simple. Just a case of specifying the OutDir property in the MSBuild task.

<MSBuild Projects="$(ProjectRootPath)\MyProject.vbproj" 
     Targets="_CopyWebApplication;_BuiltWebOutputGroupOutput"   
     Properties="OutDir=$(BuildFilesPath)\" />
$(ProjectRootPath) and $(BuildFilesPath) are properties I've created. The files are published in a directory called "_PublishedWebsites" within $(BuildFilesPath).


Setting the version

The version number of the software is specified as an application setting within the web.config in the particularly project I work on. Fortunately the community tasks download provides an XmlUpdate task:

<XmlUpdate XmlFileName="$(PublishPath)\web.config" 
     XPath="/configuration/appSettings/add[@key='version']/@value" 
     Value="$(ProjectVersion)" />

Working out the required XPath string is the hardest aspect of this tag, and that isn't very difficult really. The above example finds the <configuration> tag containing the <appSettings> tag containing an <add> tag with an attribute called "key" with a value of "version", and selects the "value" attribute. The "value" attribute is set to the value specified by the $(ProjectVersion) property.

Making it configurable

Something I wanted to avoid was storing developer specific paths in the MSBuild.xml file. Obviously the build file should be in source control, but you don't want to be in a situation where developers are constantly overwriting each others build paths when checking out from or committing to source control. To avoid this all developer specific variables must be stored in configuration file which is not in the repository. 

After a little research and a number of false starts I found that a good way to create a configuration file was actually to use another build file and import it. So, simply create a file containing the required configurable properties and give it a name, for example MSBuild.props:



<Project ToolsVersion="4.0" DefaultTargets="Default" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">     
     <PropertyGroup>          
          <ProjectRootPath>C:\PathToProject</ProjectRootPath>          
          <ExtensionsPath>C:\PathTo\MSBuild</ExtensionsPath>     
     </PropertyGroup>
</Project>


Now it is simply a case of importing the properties into your main build file using the import tag:

<Import Project="MSBuild.props" />

I've not included a path in this example because I'm assuming that the MSBuild.xml and MSBuild.props are in the same directory. Once imported you can use the properties as normal. Put your import tag at the top of the MSBuild.xml file otherwise you run the risk of using properties before they have been initialised. I only mention it because it's a mistake I made. Whoops.

Running the build

In addition to a properties file I also wanted to specify options at build time, namely configuration (e.g. release) and project version. Ideally these options should be inputed via a menu. I decide to do this using a batch file. I would recommend using another scripting language if you know one. I don't, and I knew I could knock up a batch file quickly, so that's why I chose a batch file. My build file takes a configuration and a project version then calls MSBuild. 


echo OFF
:MENU
cls
echo 1 - Staging
echo 2 - Training
echo 3 - Preview
echo 4 - Live
echo 5 - Exit
echo.
set /P M=Choose:
if %M%==1 set config=Staging
if %M%==2 set config=Training
if %M%==3 set config=Preview
if %M%==4 set config=Release
if %M%==5 exit
set /P projectVersion=Project version [ENTER to remain unchanged]:

msbuild MSBuild.xml /p:Configuration=%config% /p:ProjectVersion=%projectVersion%

pause


The above file displays a menu allowing the using to select the build configuration or exit (please note the configurations a specific to this particular project). Once selected the user then enters the project version, hits enter and the build starts. I've added the pause command at the end because typically you would set up a short cut to the batch file and without it the command window would disappear after the build was complete, hiding any success or error messages. Take note of the msbuild command. It takes the MSBuild file as the first parameter, then I've passed in two properties. Using /p: is a shortcut for /property. Predefined properties, like Configuration, or user defined properties, like ProjectVersion, can be set this way. 


Useful links

Friday 15 April 2011

Star Wars used to be great

Along with millions of other people I love Star Wars. I can't put my finger on exact why the films are so good, they just are. There's something very endearing about the story and the characters that somehow strikes a chord. Of course I'm talking about the original trilogy, A New Hope, Empire Strikes Back and Return of the Jedi. I've seen the new films, although saying that they're hardly new any more, and I enjoyed them, or so I thought. I'm the kind of person who goes to the cinema with the attitude of I've paid good money to see this film so I'm damn well going to enjoy it. Fortunately for me I enjoy most films I see, with the exception of Epic Movie. Please never watch this film. Never buy the DVD, rent it, or watch it on TV. Do something more constructive like cutting your grass with a spoon, painting your carpet or drinking non alcoholic beer. Anyway, the new Star Wars films. I didn't leave the cinema particularly unsatisfied. Without thinking about it too much I thought the films were okay. Turns out I was wrong. Someone introduced me to the Red Letter Media Star Wars reviews. After watching these I realised that there really is no room for any doubt that the films were absolute turd. Everything about them was awful. But don't take it from me, watch the reviews. Not only are they informative, they're also hilarious. I warn you, this is no small undertaking, The Phantom Menace review is roughly one hour and ten minutes and it's the shortest of the three!

My favourite part of all three reviews is a section in the Attack of the Clones review where the reviewer, Plinkett, analyses Padme and Anakin's relationship. Needless to say he goes into great detail, but the part which makes me laugh the most is when he lists what Anakin did wrong and what he did right. For my own amusement, and so I have a reason to watch it again, I've listed Anakin's WINS and FAILS according to Plinkett:

WINS
  • Good looks
  • Talks about love
  • Carries her luggage
  • Listens to her prattle on about herself

FAILS
  • Inappropriate compliments
  • Inappropriate assertiveness
  • Talks about himself too much
  • Creepy sex looks
  • Interrupting
  • Losing temper
  • Forced apology
  • Supports fascism
  • Begging for sex
  • Murders women and children
  • Brings corpse home
  • Psychotic megalomaniac ranting
  • Weird, creepy comments (many times)

Thursday 7 April 2011

Was university a waste of time?

I was at university for a fairly long time. Well, I think it was a long time anyway. Don't misunderstand me, I wasn't one of these people who started three different courses and finished none. My bachelor degree was four years, which included a placement, then I went on to do another degree. Now I often wonder, was it a good use of my time in terms of what I learnt and how it has helped my career? 

So what did I learn? I was taught a wide variety of computing subjects; this included C, C++, VB, Java, basic web stuff like HTML, CSS and Javascript; database design and SQL; plus computing basics like binary and some other stuff which I forget. I suppose I should also mention some so called 'soft' skills, things like documentation, writing reports and such. Obviously I've just skimmed the surface, I was taught more, but this is all I can remember off the of of my head. However what bothers me a little is that when I left university I thought my knowledge of software development was reasonable. Now, several years down the line, I have some appreciation of how little I actually knew of the fundamentals of software development, things that were never covered at university but really should have been.

What's so important that I didn't get taught? Let's start with code construction. When I left university I could write the basic components of a program, methods and classes, but I had no appreciation how they should fit together. It's like being taught a few words, but not being taught how to string them together to form a meaningful sentence. I had heard the term 'modular' and I knew that's what I was aiming for, but could I do it? No. I'm pretty sure the principles of loose coupling weren't covered, which is frustrating because it is so key to writing good software. Add to this nothing about design patterns, unit testing, why and when to use inheritance, the importance of using conventions, refactoring, and you've got a serious hole in your knowledge.

I could bang on about other aspects of code construction that were lacking, but I'd be here all day, so I'll move on to another subject: software. What is the one piece of software that all programmers will use daily? The integrity of their work depends on it, being able to isolate their partially finished work from other team members depends on it, and their ability to roll back the code if they mess up depends on it. Of course I'm talking about source control. The importance of source control really cannot be overstated, it's absolutely unbelievable that this wasn't covered. Subsequently I ended up using Source Safe [shudder] for several years using a checkout, lock, check in type work flow, none the wiser that there was considerably better software and work flows available. What is another piece of software that programmers use daily? If it's good it will make sure they know what has to be done and by when. It will contain details of the work to be done and the progress. Obviously I mean some kind of bug/feature tracking database. You could say that there are so many that it's pointless teaching one. I would argue that you should have exposure to at least one, if only to underline the importance of it's use. As with source control I struggled for several years using less that adequate bug tracking software (e.g. a freebie or a spreadsheet) before using some commercial software and really grasping the benefits.

So far I've concentrated on the technical aspects of my course that were lacking, but there were other things which are just as important that were missed. I'm referring to things that can't really be taught but need to be discussed. Not one lecturer ever encouraged me to read about software development. Nobody ever said read Code Complete or any number of other books which are, to my mind, essential reading. There seems to be an assumption that you should stay within the confines of the course material. Either that or the lecturer wasn't capable of teaching material outside of the course. Anyway my point is you should always encourage people to find out information for themselves and read around a subject, and I don't feel this was the done.

So, what are the alternatives to university? Are they any better? Off the top of my head I can only think of two; some kind of intensive programming course or on the job training. Both of these would be more focused and therefore increase your skills much more quickly than a university course. One disadvantage is that you'd probably be exposed to less technologies and languages. But would that matter? I learned a whole load of stuff at university that I've never needed. Ever heard of VRML? No? Don't worry, nobody else has either. My preference would be on the job training, as the experience is guaranteed to be applicable to a job. And the most obvious statement award goes to....me! Seriously though, I've found that knowledge gained on a course can be difficult to apply to a real life situation. The flip side is that many see a degree as a passport to a job. Ever seen a job spec that said "relevant degree required"? I've seen a few.

My point with all this waffling is that based on my experience I don't think university is the be all and end all. It will teach you the basics, but it won't necessarily make you a good software developer. But, having said all that, university is a good laugh.