Showing posts with label deployment. Show all posts
Showing posts with label deployment. Show all posts

Friday, 30 November 2007

Plans for IIS 7.0 web app deployment framework

Just reading through ScottGu's .NET Web Product Roadmap and noticed this (emphasis mine):

"We will also shortly begin sharing details of a new web application deployment framework for IIS that enables you to easily automate the deployment of web applications on either a single server or across a web farm of machines.  It will make it easy to version your web applications (including allowing you to quickly roll back to previous versions), as well as automatically provision them across multiple servers.  It also enables the full automation of deployment tasks (including via both command-line and PowerShell scripting APIs)."

This sounds like much more fun that other approaches I have tried.

ScottGu also mentions that the first public preview of ASP.NET 3.5 Extensions (including ASP.NET MVC) will be released next week! Woohoo! More toys! :-)

Wednesday, 22 August 2007

Example of deploying web apps using WiX

As a follow up to my recent post on deploying web applications via MSBuild, I wanted to see how tough it was to do the same thing using a WiX-built installation package. My basic aim is to deploy a simple web applications to localhost, including configuring and IIS virtual directories and application. I am going to assume that the web application has already been compiled to a directory called PrecompiledWeb (which is the default when building via MSBuild). I am using the development build of WiX 3.0 (3.0.2925.0).

The first step was creating a new WiX Setup project in my VS 2005 solution (this VS integration package is called Votive). This creates a .wixproj file, which stores the information necessary to build your installation package. As of WiX 3.0 it can be built using MSBuild. 

To this project I added references to WixIIsExtension.dll (found in C:\Program Files\Windows Installer XML v3\bin\ in my case). This is to get access to some of the IIS-related actions. The WixUtilExtension.dll is also useful for creating users (amongst other things). To get these extensions to work properly I had to work around a bug in the current build that causes the Cultures property to set incorrectly in the .wixproj file. Search for "bug" on Jeff Wharton's post for information on this. It basically just means manually setting the culture nodes to "en-US" or your current project's culture.

Next I edited the default .wxs file created by Votive (or create a new one using Add --> New Item --> WiX Product File).

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension">
  <Product Id="(your guid0 here)" Name="Sample"
           Language="1033" Version="1.0.0.0" Manufacturer="Me"
           UpgradeCode="(your guid1 here)">
    <Package InstallerVersion="200" Compressed="yes" />
    <Media Id="1" Cabinet="WixSample.cab" EmbedCab="yes" />
    <iis:WebSite Id='DefaultWebSite' Description='Default Web Site'>
      <iis:WebAddress Id='AllUnassigned' Port='80' />
    </iis:WebSite>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="INSTALLDIR" Name="Sample">
        <Directory Id="MyWebSiteDir" Name="MyWebSite" />        
      </Directory>
    </Directory>
    <Feature Id="SampleFeature" Title="Sample" Level="1">
      <ComponentGroupRef Id="MyWebSite" />           
    </Feature>
  </Product>
</Wix>

This file sets up the basic install package structure. The iis:WebSite node is there just to provide a reference to the default web site on localhost. The Directory tags define the directory structure that will be created by the installer. In this case, it is just going to going to create a structure like C:\Sample\MyWebSite. The Feature tag defines exactly which Component we are installing. In this case we are installing the group of Components called MyWebSite. We have not defined these yet, so lets add another .wks file to do this now (Add --> New Item --> WiX File).

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension">
  <Fragment>
    <ComponentGroup Id="MyWebSite">
      <ComponentRef Id="MyWebSiteRoot" />
      <ComponentRef Id="MyWebSiteBin" />
      <ComponentRef Id="MyWebSiteVirtualDir" />
    </ComponentGroup>
    <DirectoryRef Id="MyWebSiteDir" FileSource="$(var.SolutionDir)\PrecompiledWeb\Sample.MyWebSite">
      <Component Id="MyWebSiteRoot" Guid="(your guid here)">
        <File Id="Default" Name="Default.aspx" />
        <File Id="Web.Config" Name="Web.Config" />
        <File Id="PrecompiledApp.Config" Name="PrecompiledApp.config" />        
      </Component>
      <Directory Id="MyWebSiteDir_Bin" Name="bin" FileSource="$(var.SolutionDir)\PrecompiledWeb\Sample.MyWebSite\bin">
        <Component Id="MyWebSiteBin" Guid="(your guid here)">
          <File Id="App_Web_gmetwu2v.dll" Name="App_Web_gmetwu2v.dll" />
          <File Id="App_Web_gmetwu2v.pdb" Name="App_Web_gmetwu2v.pdb"/>
        </Component>
      </Directory>
      <Component Id="MyWebSiteVirtualDir" Guid="(your guid here)">
        <CreateFolder />
        <iis:WebVirtualDir Id='MyWebSiteVirtualDir' Alias='MyWebSite' Directory='MyWebSiteDir'
                           WebSite='DefaultWebSite'>
          <iis:WebApplication Id='MyWebSiteApp' Name='MyWebSiteApp' Isolation='medium' />
        </iis:WebVirtualDir>
      </Component>
    </DirectoryRef>
  </Fragment>	
</Wix>

This file explicitly lists every web site file that is going to be distributed within our installer. The reason why I have done this in a separate .wks file is because it is a giant PITA to do this, especially for large web sites, and double especially as the App_Web_*.dll file name will change on every build, so ideally you would automate the creation of this file as part of the initial project build. WiX 3.0 comes with the Heat utility (formerly Tallow) that is meant to help with this.

Other than the file definitions, you will also see the node that will create the IIS web virtual directory and application. You can also do neat things like configure application pools at this step. You'll notice the WebSite attribute of the iis:WebVirtualDir node is "DefaultWebSite", which was the ID of the iis:WebSite node in our first file, so this virtual directory will be hosted from our default IIS website on localhost.

You can now build your .wixproj from VS, and you should end up with an installer. After running the installer, you should have the sample application available at http://localhost/MyWebSite (with source files at C:\Sample\MyWebSite). Uninstalling should remove the files and IIS configuration entirely.

Tuesday, 21 August 2007

Example of deploying web apps using MSBuild

Here is a sample MSBuild script that will deploy two web apps from Sample.sln to localhost. It is very nasty, but worked ok for me.

First, we create our XML .build file and import SDCTasks for our IIS operations. The remaining code snippets go in the <Project /> node.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\SDCTasks\Microsoft.Sdc.Common.tasks"/> 
  ...
</Project>

Next we declare and define a DeploymentPath, and also set the solution file (SLN) we are going to be building. I have then defined two WebProject items. This is used for batching, which is the MSBuild way of repeating a single task with different inputs each time. Each WebProject item includes the name of the IIS web that will be created, as well as the SourceFolder that contains the ASPX files and web /bin after building the SLN (which by default builds to a PrecompiledWeb directory). All these variable names are arbitrary -- the only native MSBuild nodes are PropertyGroup and ItemGroup.

  <PropertyGroup>
    <DeploymentPath>C:\InetPub\wwwroot</DeploymentPath>    
  </PropertyGroup>
  <ItemGroup>
    <ProjectReferences Include="Sample.sln" />
  </ItemGroup>
  <ItemGroup>
    <WebProject Include="MyWebService">
      <WebName>Sample_MyWebService</WebName>
      <SourceFolder>$(MSBuildProjectDirectory)\PrecompiledWeb\Sample.MyWebService</SourceFolder>      
    </WebProject>
    <WebProject Include="MyWebSite">
      <WebName>Sample_MyWebSite</WebName>
     <SourceFolder>$(MSBuildProjectDirectory)\PrecompiledWeb\Sample.MyWebSite</SourceFolder>      
    </WebProject>
  </ItemGroup>

The next step is defining the build target. This delegates the build/compilation step to msbuild itself (rather than explicitly calling the CSC compiler which can also be done), by calling msbuild on the SLN file we defined in the ProjectReferences variable.

  <Target Name="Build">
    <MSBuild Projects="@(ProjectReferences)" Targets="Build" />
  </Target>

Next we have the deployment step. This replaces the web.config in the compiled app with a web.config.local file we have (so you can change configuration for deployment), does a basic file copy to move the files to the deployment path, then creates a virtual directory and web application at the deployment path to allow the ASPX files to execute.

  <Target Name="Deploy">
    <!-- Replace web configs in build directory with deployment configuration -->
    <Delete Files="%(WebProject.SourceFolder)\Web.Config" />
    <Copy
      SourceFiles="%(WebProject.SourceFolder)\Web.Config.local"
      DestinationFiles="%(WebProject.SourceFolder)\Web.Config" />
    <!-- Copy webs from build to deployment-->
    <Folder.Copy
    Source="%(WebProject.SourceFolder)"
    Destination="$(DeploymentPath)\%(WebProject.WebName)" />
    <!-- Create Webs on Localhost -->
    <Web.WebSite.CreateVirtualDirectory
        VirtualDirectoryName="%(WebProject.WebName)"
        Path="$(DeploymentPath)\%(WebProject.WebName)"
        AppCreate="true" />
  </Target>

Note the %(WebProject.property) style references. These are the batches I mentioned earlier, which means that tasks containing %(..) within attributes will repeat for each WebProject ItemGroup defined. This just saves us from duplicating the Folder.Copy task for each web in the SLN (for example), which can be helpful if you are deploying several web applications in the one deployment step.

For good measure we can also clean up after ourselves.

  <Target Name="Clean">
    <Web.WebSite.DeleteVirtualDirectory VirtualDirectoryName="%(WebProject.WebName)" />
    <RemoveDir Directories="$(DeploymentPath)\%(WebProject.WebName)" />
    <RemoveDir Directories="$(MSBuildProjectDirectory)\PrecompiledWeb" />
  </Target>

You can execute this from the command prompt:

msbuild sample.build /target:clean,build,deploy

This was mainly done for a proof-of-concept, and after running it I had my two web apps deployed and running on localhost as expected (er, hoped). You can obviously do a lot more useful stuff than this, like checking out from source control first, creating remote webs, virtual directories and application pools, running unit tests, and varying deployment options based on command line arguments. The main drawback of this approach is that you do not get a nice, self-contained package/installer for the deployment, and as such you will need direct network access to the deployment server as well as the relevant permissions.

Now to try similar stuff using WiX...

Friday, 17 August 2007

Automating releases with WiX and MSBuild

Sayed Ibrahim Hashimi has a comprehensive article (and sample script) on automating the creation of installation packages using MSBuild and the Windows Installer XML toolkit, or WiX. WiX is Microsoft's toolset for building Windows install packages, released under an open source licence. Microsoft used WiX to develop the Office 2007 installer.

Relevant links:

Thursday, 16 August 2007

Web Deployment Projects

In recent travels searching for deployment options using MSBuild, I have come across Microsoft's Web Deployment Projects (WDP) add-on. This has been around forever (well, since 2005), but at the time it was released my work didn't have much need for it.

WDP consists of a new utility (aspnet_merge.exe), some MSBuild tasks (Microsoft.WebDeployment.targets and DLL) and an add-in to VS 2005 that allows you to create a deployment project file from the VS 2005 UI. It does not actually require VS 2005 to be installed, so you can also install it on a build server.

Adding a Web Deployment Project to your solution simply creates an MSBuild project file (using the new WebDeployment tasks), so you can use it to complement existing MSBuild functionality you might have (such as scripts using SDC Tasks). Some of the options WDP gives you include compiling to a single or multiple assemblies, modifying web.config elements based on target configuration, creating IIS virtual directories for the output folder, pre- and post-build targets for customisation of the build process, and the ability to prevent the compiled web site from being updateable (no source-ASPX distributed to the server). Even if you do not use the VS add-in part of WDP, you can still get benefits from using the included MSBuild tasks as part of your normal build scripts.

MSDN has a good introductory article on using WDP. There is also a forum hosted at the official ASP.NET site. ScottGu also has a nice post about it.

Tuesday, 14 August 2007

MSBuild task library links

I have been having a look at using MSBuild for deployment, including things like setting up IIS webs and application pools. Guy Smith-Ferrier has a nice PDF introducing the basic concepts like properties, items, targets etc. There is also the MSBuild Reference on MSDN to help get you started.

That's fine for building projects using the standard MSBuild tasks, but how about configuring IIS during deployment? It should not be too awful implementing your own custom task, but there already seems to be a decent number of task libraries floating around, such as MSBuild Community Tasks Project and SDC Tasks.

Using these it should be fairly straight forward to do things like pulling code from source control, building, running unit tests, then deploying to a server along with the relevant configuration.

UPDATE: Microsoft's Web Deployment Projects also provide some additional MSBuild tasks relating to deploying web applications.