Iis – How to deploy your .NET Web Application? (Recommendations, please!)

deploymentiisvisual studioweb-applicationsweb-server

We've recently upgraded our ASP.NET Website to a Web Application and we're shocked by the sudden leap in difficulty when deploying it. Considering how common a task this must be, I was wondering what plug-ins/software people use to deploy a rapidly evolving, remotely stored, project (ie. a website)?

There must be a better way than just "Publishing" in Visual Studio and then having to manually FTP the files that have changed? Not least because the site goes down when we're uploading our .DLLs.

There are so many fiddly file exceptions that I'd must rather automate the process as much as possible, to prevent accidental uploads.

With our old solution (on our WebSite) we used Dispatch for ASP which totally rocked and made the entire process one click. Unfortunately it's not great for DLLs (as previously mentioned).

So how does your team do it?

Thanks for any advice.

PS – I've read that Visual Studio 2010 is supposed to address these shortcomings in VS2005/08, but until then…

Best Answer

I would strongly recommend using Continuous Integration.

We use a combination of TeamCity for CI, Rake and Albacore for automating the build.

TeamCity will check the code out of your source code repository, then, using Rake, build the application, execute unit tests and even run your database scripts if you so desire. After a successful build you can package your source code in a zip file or copy it to a destination of your choice.

We use Git, although TeamCity works with all source control systems.

Using TeamCity and Rake would be similar to using CruiseControl and NANT, without the XML file editing. Of course, you can use TeamCity with NANT if you prefer.

A short sample pulled from a rakefile.rb which performs the build. IMHO, easier to read and debug than an XML file.

require 'albacore'
require 'rexml/document'
require 'find'

VERSION_NO = "1.0"

OUTPUT_PATH = "output"
WEBOUTPUT_PATH = "output/web"
ADMINOUTPUT_PATH = "output/admin"

CONFIG = "Release"

WEB_PATH = "app/Company.Website.Web"
ADMIN_PATH = "app/Company.Website.Admin"
PACKAGE_PATH = "build/package"
DB_SCRIPT_PATH = "Company.Website.DB"
SOLUTION = "Company.Website.sln"

ARTIFACTS_PATH = "d:/build/artifacts/"

DEPLOY_WEB_PATH = "d:/deploy/company/website/"
DEPLOY_ADMIN_PATH = "d:/deploy/company/admin/"

task :default => ['setuptest','assemblyinfo','config','msbuild','createdb','sqlcmd','deploy']


task :setuptest do |setup|
  if ENV['BuildNumber'].nil? then ENV['BuildNumber'] = "000" end

  VERSION_NO = VERSION_NO + '.' + ENV['BuildNumber']
  puts 'Version Number : ' + VERSION_NO

  ZIPFILE_WEB = 'Company.Website.Web.' + VERSION_NO
  ZIPFILE_ADMIN = 'Company.Website.Admin.' + VERSION_NO  

  DB_SERVER = "WEB2"
  DB_DATABASE = "Website"  
  CREATEDB_SCRIPT = "app/Company.Website.DB/00CreateDatabaseTEST.sql"
end

  assemblyinfotask do |asm|
    asm.version = VERSION_NO
    asm.company_name = "Company Name"
    asm.copyright = "Copyright 2010"
    asm.output_file = "CommonAssemblyInfo.cs"
  end

  task :config do
    FileUtils.cp 'NHibernate.test.config', 'NHibernate.config'
  end

  msbuildtask do |msb|
    msb.properties = { :configuration => :Debug }
    msb.targets [:Clean, :Build]
    msb.solution = "Company.Website.sln"
  end

  sqlcmdtask :createdb do |sql|
    puts "executing sql scripts..."
    sql.log_level = :verbose
    sql.path_to_command = "sqlcmd.exe"
    sql.server = DB_SERVER
    sql.database = "master"
    sql.scripts << CREATEDB_SCRIPT
  end

  sqlcmdtask do |sql|
    puts "executing sql scripts..."
    sql.log_level = :verbose
    sql.path_to_command = "sqlcmd.exe"
    sql.server = DB_SERVER
    sql.database = DB_DATABASE
    sql.scripts << "app/Company.Website.DB/01CreateTables.sql"
    sql.scripts << "app/Company.Website.DB/02InsertReferenceData.sql"
  end

  task :deployprep do

    FileUtils.remove_dir 'app/Company.Website.Web/obj'
    FileUtils.remove_dir 'app/Company.Website.Admin/obj'

  end

  ziptask :zipweb do |zip|
    puts "creating zip package in " + ZIPFILE_WEB
    zip.directories_to_zip = ["app/Company.Website.Web"]
    zip.output_file = ZIPFILE_WEB  + '.zip'
    zip.output_path = File.dirname(__FILE__)
  end

  ziptask :zipadmin do |zip|
      puts "creating zip package in " + ZIPFILE_ADMIN
    zip.directories_to_zip = ["app/Company.Website.Admin"]
    zip.output_file = ZIPFILE_ADMIN  + '.zip'
    zip.output_path = File.dirname(__FILE__)
  end  

Albacore is suite of Rake tasks specifically build for deploying .NET application.