Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 3

This is the third part of my documentation of how I have put up a Continuous integration (CI) flow with TeamCity, Rake, Albacore, GitHub and NUnit for a .Net project.

What do I want to achieve?

In the previous part I prepared my solution to be built from TeamCity; by using Albacore to orchestra a bunch of rake tasks. In this part, I will set up a project in our TeamCity installation, and let it checkout the code from our GitHub repository and execute our rake tasks to build, test and package the binaries as a ZIP- and a NuGet package.

Upgrade TeamCity

First, there has come an upgrade of TeamCity, and since I still have a very clean TeamCity environment on my CI server I decided to upgrade it by doing a reinstall. More information about the recommended process of how to upgrade, could be found here: http://confluence.jetbrains.net/display/TCD65/Upgrade#Upgrade-win

Let the CI server manage build numbers

In my previous article I wanted my Albacore tasks to manage as much as possible, and I used version bumper and a VERSION file to bump the versions. This has been replaced and is now controlled by the CI server instead. This is something I have done so that I only need read access to my GitHub repository from my CI server.

Create a folder sturcture for the project

At the CI server I’ve decided to have some control of where files and folders are created. For this purpose I’ve created the following directories:

Builds: This is where the result of each individual build for the PineCone project will end up.
Checkout: This is where the files checked out from the GitHub repository will end up.
VCSRoot: Contains files/folders for managing the integration with GitHub.

Note! Checkout and VCSRoot is maintained by TeamCity and is nothing you need to maintain, just now that it’s there.

Create a project in TeamCity

I hope the screenshots talk for themselves. If not comment the article and I will insert explanations (if I can).


Log in


Create project


Name it


Add VCS Root


Create new VCS Root


Configure VCS Root
Note here that I’m using readonly and anonymous access which is feasible, since it’s a public project and I don’t want the CI server to push anything to my repository. This is probably something that I will change in the future, when I wan’t labels etc. created by the CI server.



Back to General tab


Create new build configuration


General settings
Since I have removed the version bumper and the VERSION file I know let the CI server handle the generation of build numbers. This is later on passed in to our rake tasks.


I have also specified a specific Checkout directory, just for the sake of having some control of the files needed for building the PineCone project.


Create new build step
Since my Rakefile lies in a directory named Build, which lies in the checkout directory, I need to specify the path. And since my Rakefile is designed in a manner where it’s supposed to be executed in the Build directory, where it lives, I also need to specify a working directory.


Since I have installed Ruby with registration of it’s bins in the environmentpath and I don’t want to specify a specific version, I’m satisfied with Use default Ruby.

Since I don’t need any of the attached reporters. If you select Test::Unit you need to install the gem test-unit.


Add Environment parameters
The Rakefile has been updated so that the environment parameters are now injected by the build step. To accomplish this, we need to specify Build parameters.


Naming
If the variable is called env_buildversion in our Rakefile, it should be named env.env_buildversion in TeamCity. This makes it an environment variable which is exactly what we want.


All environment parameters


Add Build feature for parsing the NUnit report
If we don’t supply a XML report processing build feature, we will not get any detailed information about the unit tests being executed.


Build it

As of now we have no automated process and as of now, this is left for future articles. But you could put up a trigger or make use of GitHub’s service hook against TeamCity.

If you trigger a build, you will get:

The updated Rakefile

As I said. The Rakefile has been updated, to not use version bumper and to not be responsible for generating project full names etc.

#--------------------------------------
# Dependencies
#--------------------------------------
require 'albacore'
#--------------------------------------
# Debug
#--------------------------------------
#ENV.each {|key, value| puts "#{key} = #{value}" }
#--------------------------------------
# My environment vars
#--------------------------------------
@env_projectname = ENV['env_projectname']
@env_buildconfigname = ENV['env_buildconfigname']
@env_buildversion = ENV['env_buildversion']
@env_projectfullname = ENV['env_projectfullname']
@env_buildfolderpath = ENV['env_buildfolderpath']
@env_unitTestXmlResultsPath = ENV['env_unitTestXmlResultsPath']
@env_solutionfolderpath = "../Solution/"
#--------------------------------------
# Albacore flow controlling tasks
#--------------------------------------
desc "Fixes version, compiles the solution, executes tests and deploys."
task :default => [:buildIt, :testIt, :deployIt]

desc "Fixes version and compiles."
task :buildIt => [:versionIt, :compileIt, :copyBinaries]

desc "Executes all tests."
task :testIt => [:runUnitTests]

desc "Creates ZIP and NuGet packages."
task :deployIt => [:createZipPackage, :createNuGetPackage]
#--------------------------------------
# Albacore tasks
#--------------------------------------
desc "Updates version info."
assemblyinfo :versionIt do |asm|
  sharedAssemblyInfoPath = "#{@env_solutionfolderpath}SharedAssemblyInfo.cs"
  
  asm.input_file = sharedAssemblyInfoPath
  asm.output_file = sharedAssemblyInfoPath
  asm.version = @env_buildversion
  asm.file_version = @env_buildversion  
end

desc "Creates clean build folder structure."
task :createCleanBuildFolder do
  FileUtils.rm_rf(@env_buildfolderpath)
  FileUtils.mkdir_p("#{@env_buildfolderpath}Binaries")
end

desc "Clean and build the solution."
msbuild :compileIt => :createCleanBuildFolder do |msb|
  msb.properties :configuration => @env_buildconfigname
  msb.targets :Clean, :Build
  msb.solution = "#{@env_solutionfolderpath}#{@env_projectname}.sln"
end

desc "Copy binaries to output."
task :copyBinaries do
  FileUtils.cp_r(FileList["#{@env_solutionfolderpath}Source/#{@env_projectname}/bin/#{@env_buildconfigname}/*.*"], "#{@env_buildfolderpath}Binaries/")
end

desc "Run unit tests."
nunit :runUnitTests do |nunit|
  nunit.command = "#{@env_solutionfolderpath}packages/NUnit.2.5.10.11092/tools/nunit-console.exe"
  nunit.options "/framework=v4.0.30319","/xml=#{@env_unitTestXmlResultsPath}"
  nunit.assemblies = FileList["#{@env_solutionfolderpath}Tests/**/#{@env_buildconfigname}/*.UnitTests.dll"].exclude(/obj\//)
end

desc "Creates ZIPs package of binaries folder."
zip :createZipPackage do |zip|
     zip.directories_to_zip "#{@env_buildfolderpath}Binaries/"
     zip.output_file = "#{@env_projectfullname}.zip"
	 zip.output_path = @env_buildfolderpath
end

desc "Creates NuGet package"
exec :createNuGetPackage do |cmd|
  cmd.command = "NuGet.exe"
  cmd.parameters = "pack #{@env_projectname}.nuspec -version #{@env_buildversion} -nodefaultexcludes -outputdirectory #{@env_buildfolderpath} -basepath #{@env_buildfolderpath}Binaries"
end

What’s next?

Well of course we need to automate our build and perhaps add features like labelling, reporting, code-coverage etc. But that’s left for a future article.

//Daniel

Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 2

This is the second part of my documentation of how I have put up a Continuous integration flow with TeamCity, Rake, Albacore, GitHub and NUnit for a .Net project.

What do I want to achieve?

In this part I will prepare my solution to be built from TeamCity; and to do this I will use Rake via Albacore. More specifically, I will show how to accomplish the following:

  • Manage the assembly version
  • Do a clean release build
  • Execute our NUnit tests
  • Create a ZIP package for deployment
  • Create a NuGet package for deployment

We will not look at the integration with TeamCity in this article, that’s for the future. However, after this article you will have a build, test and deploy process that you can trigger via the command prompt. And with just adding one additional NuGet publish task, you could as well publish the generated NuGet package.

As of now, I have decided to go with a solution where as much logic of my building process is kept in the source code. Whit this I mean, that I, using Albacore, will try to create Rake tasks that takes care of this instead of putting this responsibility on the continuous integration (CI) server. By doing this I hope to get a simpler CI server configuration, and for me as a developer, I like to find the specs for the build with the source code instead of in a CI server. Lets hope I can stick to this when looking closer at TeamCity in future articles.

Install Ruby, Rake, Albacore & Version bumper

First we need to install Ruby and then the necessary gems: Rake gem, Albacore gem and the Version bumper gem. This is something I will do on both my client as well as on my server where TeamCity is installed, since this is where the builds will be executed.

I used the installer from: http://rubyinstaller.org/downloads/ and at the time of this writing the latest version was: Ruby 1.9.2-p180.

During the installation I explicitly selected the two checkboxes to add it to the Path environment variable and to associate it with Ruby files.

Install the required gems

Since I chosen to register ruby in my environment path, to install the required gems is a real breeze. After the installation was finished I just fired up the command prompt and typed:

gem install rake
gem install albacore
gem install version_bumper

Meet Albacore

Just to provide you with a quick insight in what Albacore is, I have pasted some lines from the Albacore Wiki, below:

Albacore is intended to be a professional quality suite of Rake tasks to help automate the process of building a .NET based system. – https://github.com/derickbailey/albacore/wiki

Albacore is a build system that is based on Ruby’s Rake. Within it, you can use several different build ‘tasks’ that help you forge the build of your choice. – https://github.com/derickbailey/Albacore/wiki/Getting-Started

The Rakefile

A rakefile is a collection of tasks – work to be performed. A rakefile is also a valid ruby script, meaning you can write any executable ruby code that you wish to use with your tasks, in this file. – https://github.com/derickbailey/Albacore/wiki/Getting-Started

The Rakefile shoud be named: “Rakefile.rb“; and it is case-insensitive. According to the documentation it should reside in the “project root”. The project I will use for this guide is a rather simple one, and it’s named “PineCone” (GitHub site) and the folderstructure looks like this:

As you can see I have chosen to put my Rakefile and my NuSpec in a folder called Build and not directly in the root. In the Build folder, I have created tasks so that there will be a Builds folder created. This folder is with advantage excluded from Git using the .gitignore file. In the Builds folder there will be a folder created for each build, with a naming convention: [ProjectName]-v[Version]-[BuildConfigName]. In that folder the binaries, testresult and ZIP-package as well as the NuGet-package will be created.

A few words about the solution and its layout

To keep the complexity down, I’ve deliberately selected this, as of now, fairly simple project:

I will be adding more projects to this solution in the future but then I would like to share the versioning info as well as copyrights etc. For this I have selected to have a SharedAssemblyInfo added as a linked file. This shared assembly info file is the one we will use in our Albacore AssemblyInfoTask later on in the article.

SharedAssemblyInfo.cs

using System.Reflection;

#if DEBUG
[assembly: AssemblyProduct("PineCone (Debug)")]
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyProduct("PineCone (Release)")]
[assembly: AssemblyConfiguration("Release")]
#endif

[assembly: AssemblyDescription("Library used for managing primitive value members in object-graphs as key-values.")]
[assembly: AssemblyCompany("Daniel Wertheim")]
[assembly: AssemblyCopyright("Copyright © Daniel Wertheim")]
[assembly: AssemblyTrademark("")]

[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]

With Albacore you could set each of the attributes above, but I will only affect versioning. Why? As of now it would be more natural for me to look in AssemblyInfo or SharedAssemblyInfo for these kind of attributes, and then look for versioning info in the build definitions.

I have two build configurations:

  • Debug
  • Release

Both configurations builds all projects, so the binaries being deployed are the same being tested by our test project; hence I don’t have a build configuration like “Deploy” that only compiles the the actual project and not the tests.

XML Documentation file

In Release mode the XML Documentation file is generated. To get rid of all warnings about not having a XML comment for all public members, I have added a Suppressed warning for this.

The complete Rakefile

Before having a look at the Rakefile, remember this is my first writings of Ruby code. Now, lets have a look at the complete and finished Rakefile and then break it down.

#--------------------------------------
# Dependencies
#--------------------------------------
require 'albacore'
require 'version_bumper'
#--------------------------------------
# My environment vars
#--------------------------------------
@env_solutionfolderpath = "../Solution/"
@env_projectname = "PineCone"
@env_buildconfigname = "Release"

def env_buildversion
  bumper_version.to_s
end

def env_projectfullname
  "#{@env_projectname}-v#{env_buildversion}-#{@env_buildconfigname}"
end

def env_buildfolderpath
  "Builds/#{env_projectfullname}/"
end
#--------------------------------------
# Albacore flow controlling tasks
#--------------------------------------
desc "Fixes version, compiles the solution, executes tests and deploys."
task :default => [:buildIt, :testIt, :deployIt]

desc "Fixes version and compiles."
task :buildIt => [:versionIt, :compileIt, :copyBinaries]

desc "Executes all tests."
task :testIt => [:runUnitTests]

desc "Creates ZIP and NuGet packages."
task :deployIt => [:createZipPackage, :createNuGetPackage]
#--------------------------------------
# Albacore tasks
#--------------------------------------
desc "Bumpes new version."
task :bumpVersion do
  bumper_version.bump_build
  bumper_version.write('VERSION')
end

desc "Updates version info."
assemblyinfo :versionIt => :bumpVersion do |asm|
  sharedAssemblyInfoPath = "#{@env_solutionfolderpath}SharedAssemblyInfo.cs"
  
  asm.input_file = sharedAssemblyInfoPath
  asm.output_file = sharedAssemblyInfoPath
  asm.version = env_buildversion
  asm.file_version = env_buildversion  
end

desc "Creates clean build folder structure."
task :createCleanBuildFolder do
  FileUtils.rm_rf(env_buildfolderpath)
  FileUtils.mkdir_p("#{env_buildfolderpath}Binaries")
end

desc "Clean and build the solution."
msbuild :compileIt => :createCleanBuildFolder do |msb|
  msb.properties :configuration => @env_buildconfigname
  msb.targets :Clean, :Build
  msb.solution = "#{@env_solutionfolderpath}#{@env_projectname}.sln"
end

desc "Copy binaries to output."
task :copyBinaries do
  FileUtils.cp_r(FileList["#{@env_solutionfolderpath}Source/#{@env_projectname}/bin/#{@env_buildconfigname}/*.*"], "#{env_buildfolderpath}Binaries/")
end

desc "Run unit tests."
nunit :runUnitTests do |nunit|
  nunit.command = "#{@env_solutionfolderpath}packages/NUnit.2.5.10.11092/tools/nunit-console.exe"
  nunit.options "/framework=v4.0.30319","/xml=#{env_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml"
  nunit.assemblies = FileList["#{@env_solutionfolderpath}Tests/**/#{@env_buildconfigname}/*.UnitTests.dll"].exclude(/obj\//)
end

desc "Creates ZIPs package of binaries folder."
zip :createZipPackage do |zip|
     zip.directories_to_zip "#{env_buildfolderpath}Binaries/"
     zip.output_file = "../#{env_projectfullname}.zip"
end

desc "Creates NuGet package"
exec :createNuGetPackage do |cmd|
  cmd.command = "NuGet.exe"
  cmd.parameters = "pack #{@env_projectname}.nuspec -version #{env_buildversion} -nodefaultexcludes -outputdirectory #{env_buildfolderpath} -basepath #{env_buildfolderpath}\Binaries"
end

Rakefile – “Dependencies”

We know that there’s a dependency on the albacore library, hence we need to define it using the require keyword. I’m also making use of version bumper, so we need to include that as well. I’m using version bumper to bump the versions of each build, as well as persist this information in the VERSION file, located in the Build folder.

require 'albacore'
require 'version_bumper'

Rakefile – “My environment vars”

As of now, before integrating with TeamCity, I have identified some few things I wan’t to define as some sort of shared configurations between my task. E.g the version to use for my project(s) and the path of the solution folder as well as the buildconfiguration name.

@env_solutionfolderpath = "../Solution/"
@env_projectname = "PineCone"
@env_buildconfigname = "Release"

def env_buildversion
  bumper_version.to_s
end

def env_projectfullname
  "#{@env_projectname}-v#{env_buildversion}-#{@env_buildconfigname}"
end

def env_buildfolderpath
  "Builds/#{env_projectfullname}/"
end

If you like you can also provide some shared configuration variables to Albacore, e.g. defining the NUnit test runner in one place.

Rakefile – “Albacore flow controlling tasks”

I like to see them as compositions of tasks with the purpose of controlling the flow in the build process. You could of course skip a lot of these, and instead “chain” the tasks directly, as I have done in the assemblyinfo task versionIt, where I state that before executing this task, the bumpVersion task needs to have been executed.

desc "Fixes version, compiles the solution, executes tests and deploys."
task :default => [:buildIt, :testIt, :deployIt]

desc "Fixes version and compiles."
task :buildIt => [:versionIt, :compileIt, :copyBinaries]

desc "Executes all tests."
task :testIt => [:runUnitTests]

desc "Creates ZIP and NuGet packages."
task :deployIt => [:createZipPackage, :createNuGetPackage]

I have selected to create the tasks below, so that I can execute just the build step or just the test step, …., etc. This can be achieved by passing the taskname to rake at the command prompt.

rake buildIt

this will only execute the tasks: versionIt, createCleanBuildFolder and compileIt.

Define a default task

If you don’t want to specify each task to be executed at the command prompt, you need to create a default task in the rakefile. If not you will be promted with a message stating:

Don’t know how to build task ‘default’.

In our case our default task is composed by three other tasks: buildIt, testI and deployIt. If you do have a look at the testIt task you will see that you can point on other tasks that in turn points to other tasks. So the testIt task could in turn have pointed to our runUnitTests task as well as a MSpec test task.

Rakefile – “Albacore tasks”

Now, it’s time to have a look at our actual worker task, the tasks that actually does something. There are a bunch of pre made tasks and you can create your own custom task etc.

Tasks: versionIt & bumpVersion

As stated above, I will only affect the version attribute in the SharedAssemblyInfo file and nothing else. The task used is the AssemblyInfoTask, which lets you set values to your assemblyinfo attributes. Note that I have specified a value for the input_file attribute on the task. If not, only the attributes being assigned a value on the Albacore task would be represented in the output_file and the rest would have been removed. In my case I have chosen to use a SharedAssemblyInfo file that acts as a template for all my projects in the solution. The only attributes I’m setting via Albacore and Rake is the version attributes.

desc "Updates version info."
assemblyinfo :versionIt => :bumpVersion do |asm|
  sharedAssemblyInfoPath = "#{@env_solutionfolderpath}SharedAssemblyInfo.cs"
  
  asm.input_file = sharedAssemblyInfoPath
  asm.output_file = sharedAssemblyInfoPath
  asm.version = env_buildversion
  asm.file_version = env_buildversion  
end

This task is dependent on the bumpVersion task which uses version bumper to read the current version string from the VERSION-file and then increment the build number by one. The version string from the version bumper is accessed via the property env_buildversion, defined under My environment vars.

desc "Bumpes new version."
task :bumpVersion do
  bumper_version.bump_build
  bumper_version.write('VERSION')
end

Tasks: compileIt, createCleanBuildFolder & copyBinaries

After the version has been set, it’s time for compilation so that we have something to test and deploy. It is the compileIt task that is being executed, but it states that before compileIt can execute, createCleanBuildFolder needs to have been executed; which in turn just creates a clean build folder. The copyBinaries task just copies the binaries to a folder named Binaries located in the build folder. This simplifies the creation of the ZIP- and NuGet packages.

desc "Creates clean build folder structure."
task :createCleanBuildFolder do
  FileUtils.rm_rf(env_buildfolderpath)
  FileUtils.mkdir_p("#{env_buildfolderpath}Binaries")
end

desc "Clean and build the solution."
msbuild :compileIt => :createCleanBuildFolder do |msb|
  msb.properties :configuration => @env_buildconfigname
  msb.targets :Clean, :Build
  msb.solution = "#{@env_solutionfolderpath}#{@env_projectname}.sln"
end

desc "Copy binaries to output."
task :copyBinaries do
  FileUtils.cp_r(FileList["#{@env_solutionfolderpath}Source/#{@env_projectname}/bin/#{@env_buildconfigname}/*.*"], "#{env_buildfolderpath}Binaries/")
end

Read more about the MSBuild task.

Task: unitTests

As of now, this solution has no integration tests. Just simple unit tests that needs to be executed. By convention I have determined that all my pure unit test assemblies should end with UnitTests, hence I only extract those assemblies and pass them to the NUnit test runner.

desc "Run unit tests."
nunit :runUnitTests do |nunit|
  nunit.command = "#{@env_solutionfolderpath}packages/NUnit.2.5.10.11092/tools/nunit-console.exe"
  nunit.options "/framework=v4.0.30319","/xml=#{env_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml"
  nunit.assemblies = FileList["#{@env_solutionfolderpath}Tests/**/#{@env_buildconfigname}/*.UnitTests.dll"].exclude(/obj\//)
end

In your scenario, you will probably have more test assemblies and might not want to have the NUnit-Console as a dependency to every project. Perhaps there should be a tool repository or something instead? Since I’m using the NuGet NUnit package in my unit test project, I get the tools placed in the packages repository for my solution which I then use. Learn more about the NUnit task.

The task I have defined also makes use of NUnit console runner switches. I have used two options:

  • nunit.options '/framework=v4.0.30319': tells the testrunner to use the .Net framework 4.0 to execute the tests.
  • nunit.options '/xml=#{env_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml': specifies the name and path of the resulting XML-file.

Note! It says: nunit.options, plural and not singular. If you provide two lines with different values for nunit.options, then last in wins.

I have used the Rake FileList helper to resolve all the unit test assemblies to be executed. It also takes some of My environment vars into account, so that I don’t have to hard code and manage the assemblies to treat as unit tests by hand.

Task: createZipPackage

Not much to say here. Just ZIP the Binaries folder under the Build folder using the ZIP task.

desc "Creates ZIPs package of binaries folder."
zip :createZipPackage do |zip|
     zip.directories_to_zip "#{env_buildfolderpath}Binaries/"
     zip.output_file = "../#{env_projectfullname}.zip"
end

Task: createNuGetPackage

There’s actually specific tasks for managing NuGet specifications and packages. I have decided to keep my NuSpec file and not generate it using either NuGet.exe from the projectfile, nor via the Albacore NuSpec task. I tried the NuGetPack task but couldn’t get it to use the NuGet.exe switch version, which I wan’t, since I would like to inject the build version into the package. Instead I relied on the simple Exec task, to call NuGet.exe with the switches I want.

desc "Creates NuGet package"
exec :createNuGetPackage do |cmd|
  cmd.command = "NuGet.exe"
  cmd.parameters = "pack #{@env_projectname}.nuspec -version #{env_buildversion} -nodefaultexcludes -outputdirectory #{env_buildfolderpath} -basepath #{env_buildfolderpath}\Binaries"
end

What have we accomplished?

Just use the command prompt and type:

rake

and you will get tested and packaged binaries, in versioned build folders:

Note that files are getting updated

When executing the version tasks, two files will get updated. The VERSION-file that contains the current version number as well as the SharedAssemblyInfo.cs file.

What’s next?

In the next part, Part 3, I will integrate GitHub and TeamCity so that our buildserver can get something to build.

//Daniel

Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 1

This is simply going to be my documentation of how I have put up a Continuous integration flow with TeamCity, Rake, Albacore, GitHub and NUnit for a .Net project.

Environment

The environment for this article is a live environment, NOT a test on a Windows 7 machine, but I’m instead setting this up on a VPS with Windows Server 2008 R2 hosted at the excellent providers Tilaa. The TeamCity installation will be accessible via a public URL: http://ci.foo.com. To achieve this we will make use of IIS 7 Reverse proxying. Why? Felt simpler and I will probably make use of the site to provide reports etc. via e.g http://ci.fool.com/reports

Install TeamCity

Start by downloading the installation media from: http://www.jetbrains.com/teamcity/ This article will use v6.5.1 and the Proffesional edition. The installation is fairly simple and is documented using the following screenshots.

Make TeamCity public accessible

As of right now our TeamCity webserver is only accessible from the server where we installed it on. To make it public accessible, using the URL: http://ci.foo.com (we installed it on http://ci.foo.com:8080) we will use the IIS 7 Application Request Routing module but we will NOT setup a webfarm as other articles do; but instead setup a Reverse proxy on a normal IIS-site.

Install Application Request Routing module

I will install this module using Microsoft’s Web platform installer. Fire it up an locate the URL rewriting module (Products –> Server). Install it and let it include the modules it depends on.

NOTE! I have already installed the URL Rewriting module, hence it’s not selected as a dependency. It’s also worth noting that it’s not enough with the URL Rewriting module to setup a Reverse proxy.

What’s left?

That’s it for now. Part 2 will be written soon, and then we will look at using Rake and Albacore for building our Visual Studio solution and running our unit tests.

//Daniel