about
framework & approach
knowledge network
news & events
technology council
why join?

Friday, July 14, 2006

Web Deployment Project is the answer!

Well, I finally figured out a solution to my deployment issues. Until a couple of days ago, I thought Web Deploymetn and Web Setup projects were the same thing. Why? Well, maybe because

  1. Web deployment projects were an added feature that didn't make it to the final release of VS 2005
  2. Even after installing the add-on, the project type doesn't appear in the traditional project template selector.


Considering other poeople have covered this topic at great length apprently (I feel pretty dumb being out of the loop for 8 months...), here are 2 links that will guide you through the process:

ScottGu's Blog entry

Microsoft's official page w/ download

In short, it takes care of most deplyment issues (other than testing and database changes) I was referring to in my previous post. After messing around with it, here's more info that might save you some time:

Adding a web delpoyment project to your site

Select the web site in your solution explorer, then go to Build > Add Web Deployment Project. Very counter-intuitive, it reminds of the process of adding a "Project Installer" to a Windows Service (coming up in a future post).

Don't remove the project from the solution unless you're sure you don't it anymore. There's no UI to re-add it as an existing item, so you'd need to manually edit the solution file I guess.

"aspnet_merge.exe" exited with code 1 error

One of the nice features of the web deployment project is merging all page assemblies into one, reducing the number of dlls deployed. But under certain circumstances the build will fail. For example, if 2 classes have the same name (imagine 2 user controls or pages called "Default" for instance), the build fails, and the error code is so vague it'll make you want shoot your computer.

I read one post where the recommended solution was to re-create the web site from scratch, adding each file one at a time and recompiling until you find which one is causing the error when merging. If you site is large, you can imagin how frustrating this can be. If this happens to you, here's what to do:

Open Tools > Options, then Projects and Solutions > Build and Run.
At the bottom of the form, under "MSBuild project build ouput verbosity", select "Diagnostic". From then on the build output will show which class is causing the problem.

Web.config section replacement - tips and tricks

Another nice feature. It solves my deployment context problem, I no longer need to edit web.config manually. To change web.config depending on the environment, you have 2 options: use an external config file altogether, or only change specific sections. This process is pretty straight forward, but watch for this one little trick: section replacement only works with sections, not section groups. This means you cannot change the whole system.web or system.net config tags.

Here's a concrete example. My mail settings configuration changes between testing and production environments. When I tried adding

system.net/mailSettings=config\mailSettings.Production.config

to the section replacement field, the build failed. It turns "mailSettings" is a section group. I had to go dow to the "SMTP" setting for this to work:

system.net/mailSettings/smtp=config\mailSettings.SMTP.Production.config

Now it works like a charm.
Alos notice the path to the replacement file is a physical local path, thus requiring the use of a backslash ("\"). Using a forward slash ("/") will cause the build to fail.

Excluding folders and files from the deployed build

The description of WDPs says you can exclude files and folders from the build. AFAIK, the only UI feature that allows you to do this is the "remove App_Data from ouput" checkbox. If you need to do more than that, you'll have to edit the project file itself. I'd recommend reading about MSBuild to understand all of its power. That's beyond the scope of this post. But here's a quick example.

I placed all my replacement config files (testing and production) in a config subfolder under the root of my web site. When in debug mode, I use the testing config files and build directly to the testing server. When in release, I use the produciton config files and build to a "Release" folder, ready for packaging and copy to production.

To make this perfectly clean, I also wanted to clean up the output by removing any pdb files that might have been created (code libraries always create those, even in release mode, unless you change that setting in the project's build options), any xml documentation, and my config folder.

I managed to do this by editing the deployement project file. At the end of the file, I used the AfterBuild target to delete the specified folder and files:

<target name="AfterBuild">
<removedir directories="$(OutputPath)\config">
<delete files="$(OutputPath)\bin\*.xml;$(OutputPath)\bin\*.pdb" / >
</ target>

You can get even more fancy and add a condition to it (for instance, only delete .pdb files in release mode), create folders etc...

Wednesday, July 12, 2006

Visual Studio 2005 web site publishing nightmare

During every release, my stress level used to go up 10x. It shoudn't have to be that way. Here are my main deployment issues, with workaounds when applicable.

Did I change my config settings to reflect the production environment?

Not an easy one. Maintaining mutliple web.config files is a pain, so I'm using only one, with development, testing and production settings. I comment them out and uncomment each group of settings (appsetings, connection strings, assembly settings, email ...) depending on the environment. There's still room for user error, so if you have a better solution, please let me know.

I built all code libraries in Release mode, but did I forget to change the Web.Config compilation debug attribute to "false"?

As I have written before, running your app in debug mode can have disastrous effects on bandwidth useage and overall performance if you rely heavily on Webresource.axd as an image and javascript provider. For this reason, I would recommend making the following change to machine.config on the production server - this overrides the debug attribute in web.config:

<configuration>
<system.web>
<deployment retail=”true”/>
</system.web>
</configuration>

Did I include all my license files?

You may have noticed that when publishing a web site in VS 2005, .lic and .licx files don't get copied automatically. This has been a real pain for months - for instance I kept forgetting to include my aspnetemail license; the site would seem to be running fine, but emails would consistently fail. Thankfully, there's a fix! Just edit your web.config compilation settings:

<configuration>
<system.web>
<compilation>
<buildproviders>
<remove extension=".lic">
<add extension=".lic" type="System.Web.Compilation.ForceCopyBuildProvider">
</buildproviders>
</compilation>
</SYSTEM.WEB>
</configuration>


This will force all *.lic files to be copied when publishing/precompiling your site.

Data and logic are out of sync on development and production machines. Some files are newer on the production server (images and docs uploaded by users for example), others are newer on my development machine (webforms, usercontrols, dlls, styles etc...)

Use virtual directories for all resources modified at runtime. This way, you don't have to worry about overwriting new data when deploying a new release.

Applying database changes

Versioning and deploying new code is easy, but what about your database? Personally, I keep a log of all database changes during development. The file is kept in SVN and can be modified by all developers. It looks like this:

- Created view_Catalog
- Updated spCatalogItem_GetDetails
...

Very simple. When we're ready to release, we move production data to the testing server, generate a sql file reflecting all the database changes tracked in the log, run the query on the testing database. If it's successful, we do the same on production.

UI testing

If you're building a tiered application, you're probably writing unit tests as well. That's great, but how do you test the UI? If you're like me and can't afford a QA team, you're the one clicking all over your web app to make sure everything works properly. But every developer hates this, and has a tendency to only test things that are supposed to work.

I started implementing NUnitAsp for critical user interactions (account registration, downloads, credit card purchases...). It works fine when using MS web controls, and it's a first step in the right direction; but if you are using 3rd party UI components, you'll need to write your own testers. Moreover, there's no support for Ajax and javascript... so if you build fancy user interactions, you're out of luck.

One thing to consider is the atlas UpdatePanel. Partial page rendering can be turned on or off easily through the Script Manager; so in theroy you could turn it off, run your UI unit tests, then turn them on on production. This is just an idea though, I haven't tried it yet...

Also, I found this project in SourceForge. On paper, it looks interesting...

Link to NUnitWeb

Consider Web Deployment projects

Web Deployment Projects offer more build options, such as creating a virtual directory, replacing web.config sections, toggle debug compilation setting and more. See my next entry.

Web deployment projects resources:
Microsoft Web Deployment Project resource page

Web Application projects?

Microsoft recently released a template for this new project type. I haven't tried it yet, but apparently it's similar to web app projects in VS 2003. That's nice, it's a much cleaner approach when building an enterprise web application.

Microsoft Web Application Project resource page