Monday 22 June 2009

One Click Deployment with Visual Studio, Web Deployment Project and Web Deployment Tool

One of the things I’m keen on getting setup is a great solution for one click deployment.  Lucky for me one of Microsoft’s new tools is the Web Deployment Tool, but as it’s very new information on or about it is very limited and it’s quite complicated to figure out.  Fortunately once you do figure it out, it’s remarkably easy to use, as long as you have a little server knowledge and know how to use IIS.

Visual Studio

I’m using Visual Studio 2008.  This is apparently a lot easier in VSTS 2010, but I’m not all that keen on getting the Beta to work on our production web site, so I’ll be sticking with 2008 for some time.  You don’t need to do anything in particular to Visual Studio however, just install it.

Web Deployment Project

This first came out for Visual Studio 2005 and is a great tool.  Scott Gu has the best tutorial I know of on how to use it, you can find that here.  It’s a tutorial for 2005, but it works just the same in 2008.

Web Deployment Tool

The only thing I can say about this is that it is very difficult to use.  Not because the tool is all that complicated, in fact it’s remarkably simple, but because there are so many uses for it and so little information yet.  In its defence, it’s a new tool and currently only in BETA so I shouldn’t complain.  It is, however, very useful once you understand how it can work for you.

What I did

Assuming you already have a project setup in Visual Studio 2008 (or 2005) this should be pretty easy.  Read Scott Gu’s tutorial first on Web Deployment Projects because I’m going to assume that you know a little about these first. 

1. Create a Web Deployment Project

Add a web deployment project to your project.  If you’re developing a web site, just right click the website and choose the Add Web Deployment Project option.  You’ll get a new project with no files and a default name of <YourWebSite>_deploy.

As you’ve ready through Scott Gu’s tutorial you’ll know a little about this file.  One of the things I find most useful about it is the ability to overwrite sections of your web.config during the build deployment.  You will need a config file for each section you want to replace, though I expect it’s uncommon for there to be more than 4-6 of these sections.  I created a subdirectory called config and stored all my config files in there naming them after the section they were replacing, I.E. ProdAppSettings.config.

image

You’ll notice I’ve got a ProductionLog4Net.config file.  This didn’t actually work and I couldn’t get the default tool to replace this for me, if anyone reading this knows how to get the WebDeploymentProject to replace log4Net config sections please let me know.

2. Setup the Web Deployment Tool

This is the hardest step, mostly due to lack of information on how this tool works and most importantly how it can be useful to deploy directly from visual studio.  Firstly you’ll need to download the latest version of the tool, I used the 1.0 RC.  You’ll need to install two copies of this, one on your local machine and one on the server you’re going to deploy to.  On your local, you can install as minimal as you like because all you really need is MSDEPLOY. 

On the remote machine, your deployment server (production or test or whatever you call it), you’re going to need to install everything.  You need the Remote Agent Service and the IIS 7.0 Deployment Handler. If you really want you could probably get away without the PowerShell Cmdlets or the UI module for IIS Manager, but I think you’ll find use for them at some point.

image

Once the install is done you’re going to need to start a couple of services

image

The Web Deployment Agent Service and the Web Management Service should enable you to deploy from a remote location.  Now it’s best to test this, on your local machine fire up the Msdeploy Command Console, if you’ve in stalled the Web Deployment Tool locally with defaults you’ll find it under IIS 7.0 Extensions in the Programs list.  All it is really is a command prompt pointing at the right directory, so if you can’t find it I’m sure you’ll figure something out.

3. MSDeploy – Confusing

So MSDeploy is a little confusing to start with, lots of options and not much documentation.  I’ve used it in a particular way, but you can use it in many many ways.  What is boils down to is a synchronisation tool that you can use to synchronise files between directories and web servers (which really are just virtual directories anyway).  Run it without any commands and it’ll give you the idea.

What I want is to synchronise my local output from my Web Deployment Project with my remote web server.  This is easy.

The command is:

msdeploy -verb:sync -source:iisApp=C:\MyDir\MySite -dest:iisApp=<Website>, computerName=<RemoteDeploymentServer>, username=<UserWithAccess>, password=<Password> -skip:objectName=dirPath,absolutePath=<DirectoryYouDontWantToSync>-skip:objectName=dirPath,absolutePath=<DirectoryYouDontWantToSync2>

The sync verb will tell the deployment tool to synchronise the local directory and the remote one.  The  source is your local directory, the destination is the IIS website on the remote server.  You can skip directories that you don’t wan to sync, otherwise those directories would be deleted during the sync.

At this point I’d try it with a test from the out put of your Web Deployment Project.  I didn’t run into any problems once I understood how it worked, however you might.  I imagine the most likely problem is going to be a firewall restriction, however if you don’t have that it should work.  If not let me know.

4. One Click Deployment

I don’t want to have to leave visual studio and run some silly script just to deploy my site.  I want to do it with one click, or even better, as part of my build!  Well the web deployment project is great for this.

image

Choose “Open Project File” and find at the end of the XML the AfterBuild section.  Then just create an Exec command and set the Command to your msbuild command created above.

<Target Name="AfterBuild">
   <Exec Command="msdeploy -verb:sync -source:iisApp=$(OutputPath) -dest:iisApp=MyWebSite,computerName=DeploymentServer,username=DeploymentUser,password=password -skip:objectName=dirPath,absolutePath=DynamicImages -skip:objectName=dirPath,absolutePath=DynamicDirectory" ContinueOnError="false">
   </Exec>
 </Target>

$(OutputPath) is the output path of your Web Deployment Project.

5. Run it!

If everything went according to plan, when you build it will now deploy your project to your web server.  There are a few things you should finish off before you’re done though.

Firstly, I would only set the web deployment project to build when your are in release mode.

image

That way your debug build are not deployed anywhere.  You could also not build it at all so that deployment is only done when you build the deployment project specifically.

Also, every time you do a build it’s going to release all your source every time.  This is  because the output files for your project will be replaced every time with new versions.  Easy change really, just tell your web deployment project not to merge the output and you’ll be fine.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugSymbols>false</DebugSymbols>
    <OutputPath>removed from paste</OutputPath>
    <EnableUpdateable>true</EnableUpdateable>
    <UseMerge>false</UseMerge>
    <SingleAssemblyName>MyWebsite.dll</SingleAssemblyName>
    <AssemblyPrefixName>
    </AssemblyPrefixName>
    <ContentAssemblyName>
    </ContentAssemblyName>
    <DeleteAppCodeCompiledFiles>true</DeleteAppCodeCompiledFiles>
    <UseWebConfigReplacement>true</UseWebConfigReplacement>
  </PropertyGroup>

It will still deploy your DLL files every time because they are built with every rebuild, but with shadow copy in IIS this is not an issue.

Conclusion

So I now have one click deployment to my remote web server, right from inside visual studio.  I suppose it’s a little dangerous because any developer can now deploy right into the live environment, but as this is a small company here there is little risk of that.  If you don’t like that idea, you can setup a staging environment where you do deploy to and use the Web Deployment Tool to allow on demand synchronisation between the staging environment and the live one.

2 comments:

Anonymous said...

I think I may have ran across a post you made about this a long time ago, and have a reply from MS about why you are not able to replace your custom sections in the web.config using web deployment projects. This was a while ago though, so maybe it's already fixed.

Scott Owen
kateowenlaw.com

-----Original Message-----
Sent: Friday, June 01, 2007 2:41 PM
To: Scott Guthrie
Subject: web deployment project custom web config sections

Scott,

I stumbled upon your blog the other day regarding web deployment projects.
(http://weblogs.asp.net/scottgu/archive/2005/11/06/429723.aspx)

There was a post outlining a problem I am experiencing:
---------------------------------------------------------
# re: VS 2005 Web Deployment Projects
Friday, May 26, 2006 3:01 PM by Eric Schoen I'm having trouble figuring out how to update custom sections in Web.Config.
Typically, my web service application is quite happy for me to (1) implement the config section handler in the App_Code directory, and (2) specify the name of the handler in the <section> element without qualifying the type with an assembly name. This is great for a dynamic web site, because I frankly don't know the ultimate assembly name.

However, when the ReplaceConfigSection task runs under the wdproj, it appears to do so in a context in which the <section> element doesn't do too much good. If I leave the assembly name out of the section handler, the task tries to load the handler type from System.Web (and fails). If I put the name of the precompiled assembly in the type specification, the task fails saying it can't find the assembly. If I split the section handler out into a separate assembly and put its name into the handler type specification, the update task can't find the separate assembly either.

Any clues as to how to replace sections in web.config that are custom defined would be great!
---------------------------------------------------------

I didn't see a follow up post, and wasn't sure if anyone ever outlined the
problem for you. Eric did a great job fortunatly. I'm attaching some code
which outlines the basic problem. The web.config is very simple; I left the code with the build problem. Removing siteSettings=sitesettings.config in the wdp will eliminate it.

I'll be watching the blog, so feel free to just post back there for all to see if you haven't seen it already.

Thanks,

Scott Owen


-----Original Message-----
From: Scott Guthrie
Sent: Tuesday, June 05, 2007 5:38 PM
To: Scott Owen; Bradley Bartz
Subject: RE: web deployment project custom web config sections

Brad - do you know if what Scott is trying to-do below is possible using a web deployment project?

Thx!

-----Original Message-----
Sent: Wednesday, June 06, 2007 12:56 PM
To: Scott Guthrie; Scott Owen
Subject: RE: web deployment project custom web config sections

I don't know of any way to do this. Regrettably the ReplaceConfigSection task uses the configSource attribute which will result in loading the types. But the WDP runs in the context of MSBuild and will be unable to find dynamically generated types.

A better approach would be to use a standard text replacement with no dependencies on the generated types.

Unknown said...

Hi,For the past several years the developers have been using self-service tools for Web Design Cochin to build and deploy hundreds of applications and services to the Amazon cloud. One of those tools is Asgard, a web interface for application deployments and cloud management. Thanks.....