The complete deployment is basically split into two parts: deploying the database and deploying the site's files. If your web server supports SQL Server Express (only recommended for small workgroups), deploying the database is as simple as copying the contents of the App_Data folder to the remote server's App_Data folder, and the .mdf and .ldf files will automatically be attached to the remote SQL Server Express that is installed on the web server! However, production deployment normally requires a full-featured SQL Server 2005 (not the Express edition), for security, performance, and scalability reasons. Because of this, you need to find some way to turn the current SQL Server Express database into a SQL Server 2005 database. As for the site's files, you have different options here, as you'll see shortly.
One important point to consider is the fact that we did all our development using the VS2005's integrated web server (ASP.NET Development Server, based on Cassini) and not IIS. The integrated web server is fine for local testing but your site must be tested on IIS before deploying to a production server. Therefore, before deploying the site to the remote server you'll first test it on a local installation under IIS, replicating the configuration you have on the production server as much as possible. This will be a test of your deployment procedures and configuration, in addition to the obvious test of your code and pages. The following sections provide a detailed tutorial of the steps to take for a complete local deployment of the database and the application, and later you can follow the same steps for production deployment.
When using a shared hosting service, you will typically have an empty database on a shared SQL Server 2005 database which you can access remotely through the SQL Server Management Studio (SSMS) desktop application (the new replacement for both Enterprise Manager and Query Analyzer), or with an online web front-end provided by the hoster. However, they usually don't give you the access rights to upload an .MDF file and attach it by running the sp_attach_db stored procedure (which was introduced in Chapter 3), because that would require administrative rights, and nor do you have permission to restore a database from backup files generated on your local server. Your hosting company's support staff may do this for you if you make a special request, but they may not. However, most hosting companies have some kind of web application that lets you run queries and SQL scripts on your remote database; and as mentioned earlier, they do allow you to connect remotely with SSMS (SSMS is usually better than the hosting company's web application).
When deploying to a particular server under your control (as opposed to a shared hosting company server), you can just create a new database on the server, and then create a new login and give that login permissions in your new database. This is not an end-user account; it's the account that our web site will use to access the database. The following SQL commands will do this (please select a good password in place of 'password'):
USE Master GO CREATE DATABASE TheBeerHouse GO USE TheBeerHouse GO EXEC sp_addlogin 'BeerHouseUser', 'password', 'TheBeerHouse' EXEC sp_grantdbaccess 'BeerHouseUser', 'BeerHouseUser' EXEC sp_addrolemember 'db_owner', 'BeerHouseUser' EXEC sp_addrolemember 'db_datareader', 'BeerHouseUser' EXEC sp_addrolemember 'db_datawriter', 'BeerHouseUser' GO
To set up a remote database just like your local database, you need to create all its objects: tables, stored procedures, views, triggers, indexes, constraints, roles, etc. In addition to your own objects, you also have to re-create all the objects required by the SQL Server providers used by ASP.NET for features such as membership, profiling, personalization, and web events.
There are many ways to create all the database objects in a new remote database, but the following are among the best options (only the first option is covered in detail due to space constraints):
Make SQL scripts from your development server and execute those scripts on the new server (the code download for this book has SQL scripts, or you can make them yourself).
Use SQL Server Management Studio (SSMS) to copy the whole database from your local development database directly to the new server.
Copy your .mdf (database file) and .ldf (log file) from your local computer to the remote computer, and attach them to the remote instance of SQL Server.
Use SSMS or SQL commands to create a backup of your local database to a file, and restore from the file on the new server.
Use the new SQL Server Integration Services, which is a powerful and flexible replacement for the older DTS services.
Write your own data migration program using the SQL Server Management Objects (SMO), which is a new set of classes that enable you to manipulate SQL objects from a .NET program (SMO replaces the older SQL-DMO COM objects).
Option 2 is the easiest, but it requires you to have administrator access on both computers (not possible for a shared hosting deployment). In fact, options 2, 3, and 4 are normally not available for shared hosted sites, and options 5 and 6 may not be available in some shared hosting environments. This leaves option 1 as the most portable option that will always work for every situation. The only problem with option 1 is that you can't script data for image columns (used in the aspnet_profile table), so you need an alternate way to populate the data once the objects have been created.
Most of the aforementioned options are easiest to implement using SQL Server Management Studio (SSMS) on your local development computer, where both the local and remote databases are registered in the configuration. Many people using Visual Studio 2005 only have the Express edition of SQL Server 2005 on their own computer, and SSMS doesn't come with this edition. Fortunately, Microsoft does have a free version of SSMS for use with the Express edition: search the MSDN web site for the newest version of SQL Server Management Studio Express. Either edition of SSMS (full or express) can be used for this purpose. Due to space constraints here, I can't cover SSMS in detail, but I'll walk you through some of its most useful features that are helpful for deployment.
There's a convenient shortcut for creating the ASP.NET required objects (for profiles, membership, etc.): If you remember from Chapter 3, all those objects can be created by executing the aspnet_regsql command-line tool and specifying the target server and database. Of course, this requires that you can access the remote SQL Server over the Internet (i.e., you can connect to it from your desktop and not only from the web server running your site). This is the syntax you can use to install the ASP.NET 2.0 tables on a remote server at a specified IP address:
aspnet_regsql.exe -U username -P password -S 111.222.333.444 -d DBname —A all
An alternative, in case you can't access your remote database this way, is to use the hoster's database manager (or SSMS) to manually run a set of SQL scripts to create those objects. Microsoft has provided these scripts under the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 folder. These script files must be run in the following order:
Important! All of these scripts reference a database named aspnedb. Your database is probably named differently, so you'll need to edit the scripts to specify the name of your database (you should make copies and only edit the copies, of course).
As you can see, it's very easy to create the standard objects, but you normally don't have to do this as a separate step. Instead, you can just script these objects along with your own objects, as you'll see in the following section.
You can generate SQL CREATE scripts from your local development database, and then execute them on the remote database server.
Although Visual Studio 2005 is not quite as good as SSMS when it comes to generating scripts, it can be used for this. Using Visual Studio 2005, you can add a Database Project to your solution (select File ð Add ð New Project and then select Other Project Types ð Database ð Database Project) and then script objects one by one by browsing the local database on Visual Studio's Server Explorer window and clicking the Generate Create Script to Project command from the object's context menu (see Figure 12-1).
Although this method of creating SQL scripts works fine, it's not the most convenient approach because you have to generate scripts one object at a time, into separate files, and then merge everything together.
It's easier to generate one script that contains all the objects using SSMS. If you loaded the .MDF data file on your computer but haven't attached it to the local database yet, you can do this by means of the Attach… command from the Databases item's context menu (see Figure 12-2).
From the dialog box that pops up you select the .MDF file to attach and the name you want to give it in the SQL Server 2005 instance. For example, in Figure 12-3 the ASPNETDB.MDF file is being named after TheBeerHouse.
If you receive an error when attaching the file from SQL Server 2005's dialog box, ensure that it is not being used by some other process, and is not already attached to Visual Studio's Server Explorer tool. In the former case, just stop the guilty process; in the latter case, simply detach the file by means of the Detach comment, reachable from the database file's context menu.
Once the database is attached to your local database, you can launch the Script Wizard by selecting the database from the Explorer window, and then clicking Tasks ð Generate Scripts… from the context menu (see Figure 12-4).
In a single step you can choose to script all tables, stored procedures, user-defined functions, roles, and views, and you have many more options to optionally script primary and foreign keys, check constraints, triggers, indexes, and so on (see Figure 12-5). This includes all the objects required by the ASP.NET features and providers, so if you follow this approach there will be no need to execute the individual scripts previously listed.
Once you have generated the script to create all the objects, you can execute the script on your new database to recreate the whole schema. This can be done with SSMS, or any other tool that lets you execute SQL commands on your new database. First, you have to register your remote database in SSMS (select View ð Registered Servers, and then right-click in that window to add a new registered server). Then do a File ð Open on your creation script, and have it connect to the remote server (make sure your database is selected in the drop-down list in the toolbar area), and run your creation script by pressing Execute or using the F5 shortcut key (see Figure 12-6).
The script we created and executed created the objects but didn't populate the tables with data. While developing the site on your local computer, you created quite a lot of data to define article categories, forums, polls, products, users, and so on, and you'll want to import all that information into the new database instead of recreating it from scratch. You might think that you could generate a script with INSERT statements for all the records from all your tables, and then execute it on the new database. However, neither Visual Studio's Server Explorer, nor your local installation of SSMS have the ability to create SQL INSERT scripts for your data, and you may end up coding the statements manually. If you only need to script a few dozen records, writing statements by hand may be feasible, but if you have to generate hundreds or thousands of INSERT statements for any table, then you will want to look at one of the many third-party tools that can automatically generate the script for you.
If you can connect to both the local and remote database by means of SQL Server Management Studio (SSMS) things are much easier. When you use the tool's Import Data feature, it allows you to choose all tables, but you can't select the order in which they will be imported, and you'll get many import errors if the tool tries to insert data into a detail table that has a foreign key to a master table for which the data hasn't been imported yet. To solve the problem, you need to temporarily disable the referential integrity checks during the import, so that the tool can insert data into a table even if the records reference other records that are not present in the master table yet. To do this you use the ALTER TABLE <tablename> NOCHECK CONSTRAINT ALL statement for every table, as follows:
ALTER TABLE tbh_Articles NOCHECK CONSTRAINT ALL ALTER TABLE tbh_Categories NOCHECK CONSTRAINT ALL ALTER TABLE tbh_Comments NOCHECK CONSTRAINT ALL ...do the same for all other tables required by ASP.NET and your application
After disabling constraints, select the target database in which you want to import the data (this may be a local database or a database on the remote server) in the Object Explorer, and select Tasks ð Import Data… from its context menu (see Figure 12-7) to open the Import and Export Wizard.
In the first wizard step you select the source database, which will be the TheBeerHouse database attached to the .MDF SQL Server Express file (see Figure 12-8).
In the second step you choose the destination database, which will already be selected. If you're targeting a remote database (not on your own computer), you probably also need to modify the options to choose SQL Server Authentication, and your credentials to connect to it. In the next step you select all the tables you want to import, which will be all tables starting with aspnet_ and tbh_ (see Figure 12-9).
You could omit the following tables if you prefer: sysdiagrams and aspnet_WebEventEvents. Also, make sure you do not select the objects beginning with vw_aspnet, as these are views that don't contain their own data in reality. Before proceeding to the next step you must go into the import options of each selected table, by clicking the Edit… button on the right side of the grid listing the objects. Select the Enable Identity Insert option (see Figure 12-10) to ensure that records are imported with their original identity values (for columns such as ApplicationID, CategoryID, ArticleID, PollID, etc.). This is necessary so inserted rows will respect the referential integrity (other tables have foreign keys that reference the specific values in these identity columns, so we have to insert the original values instead of letting it assign new values). You might think it's a good idea to select Delete Rows in Destination Table so that you won't get duplicate key errors if you're re-importing the data. This won't work, however, because it will try to use truncate statements that don't work on any table that has foreign keys (even if the constraints are off). So you need to use a script to delete all rows first if you want to re-import data, rather than use this checkbox.
Complete the wizard and check the box that lets you save the SSIS package, and check File System. When you see the Package Protection dialog, select "Encrypt all data with password" and specify a password. Select a filename for this package and run the actual process; it will import all rows as specified.
Save the SSIS package in a file so you can easily rerun this import in the future without having to do all the setup steps again (just double-click on that file). However, be careful because you have to empty your tables before doing this and you don't want to do this once you have real users in a production environment! Figure 12-11 shows the screen providing feedback about the process, with the number of rows successfully imported for each table.
The last thing to do is re-enable the constraints we previously disabled, by running the following statements on the remote database, from a Query window:
ALTER TABLE tbh_Articles CHECK CONSTRAINT ALL ALTER TABLE tbh_Categories CHECK CONSTRAINT ALL ALTER TABLE tbh_Comments CHECK CONSTRAINT ALL ...do the same for all other tables required by ASP.NET and custom features
The entire import takes a couple of minutes to complete, and you end up with a perfect replication of the local SQL Server database.
When you're done, remember to detach the original SQL Server Express .MDF file used as a source; otherwise, you will no longer be able to open it from Visual Studio and run the site against it. This is not a concern if you used a full edition of SQL Server 2005 on your development computer.
Now you can change the connection string used by all ASP.NET providers, and by our own custom modules, so that it no longer points to the local SQL Server Express database file, but instead points to the remote database. The updated web.config file will then contain something similar to the following (the connection string has to be on one line; it had to be split for this book, but the provider name can be on the next line):
<connectionStrings> <remove name="LocalSqlServer"/> <add name="LocalSqlServer" connectionString="server=111.222.333.444; Initial Catalog=DBname;uid=username;pwd=password" providerName="System.Data.SqlClient"/> </connectionStrings>
There are three main methods to deploy the site's files:
You can simply copy all files to the remote hosting space, including .aspx and .ascx files, .cs source code files, etc. Visual Studio 2005 includes a tool that allows you to copy the web project's file to another directory on the local machine, to a UNC path, to an IIS virtual application, or to a remote FTP site. This is the simplest option, but it's sometimes not desirable because your source code files will be copied as is, in "clear-text" format on the server, and many developers don't like this. As long as you deploy the site on your own in-house server that's fine, of course, but as soon as you need to deploy on a shared hosting space you'll probably want to pre-compile the source code so that you protect it (at least a bit, as it can always be decompiled if one really wants to see your code) from prying eyes.
Even if your source code files are deployed to the server, they still cannot be downloaded by users due to the IIS settings, but it's probably best not to have them on the server at all.
In addition to pre-compiling the site's source code files (the .cs files), you can also pre-compile the files containing the markup code (such as .aspx and .ascx files). Then, you'll only deploy the compiler-generated .dll assemblies, plus the .aspx/.ascx files as usual. However, because you pre-compiled the markup files, their content was stripped out by the compilation process, and they now only contain a placeholder string. For the actual deployment you can use an FTP client to copy the pre-compiled files to the server. In addition to offering better protection of your code, you're also making it harder for anyone to change your site's UI: This is particularly important if you sell the site as a packaged product and you put copyright notices and logos on the pages, and you don't want your client to remove or change them. Another advantage is that your code won't have to be compiled the first time a user accesses the site (but there will still be a JIT compile to go from IL to native code), which leads to slightly better performance the first time your site is accessed after deployment, or after IIS recycles the application.
You can generate an installer program that takes care of the complete setup of the web application, including extracting the site's files from CAB files, copying them to a folder selected by the user, creating a virtual directory/IIS application on the destination server, executing SQL scripts to create and pre-fill the database, and more. This option is particularly attractive to those of you who are developing a site that will be sold as a packaged application. In that case, it's standard to give users an installer program that takes care of the application's setup as much as possible. Note, however, that this approach isn't always useful because the user must have administrative rights on the destination server to install the site, and he needs to launch your installer program directly on the server itself. Therefore, this is not viable if you're targeting a shared hosting space. You can, however, create the installer anyway, so that clients will have the option to use it if they decide to deploy to their own server, or they can use FTP to deploy the site to a shared hosting service.
The following sections explore these options in more detail.
One of the problems that developers need to be aware of when developing web sites with Visual Studio 2005 is that the built-in web server is not equivalent to IIS. It's normally very good, but you need to be aware that your web site may function differently in some ways when deployed to a real IIS server. For this reason you should always deploy your site to IIS and test it before deploying it to a production server. To demonstrate the new Visual Studio Copy Web Site built-in tool, I'll show you how to copy the site to an IIS application, so that you can test the site on a real web server. Only professional and server versions of Windows have IIS, and even then it's not installed by default. If you have a home version of Windows you'll have to deploy to a different system that has IIS installed. First create a virtual folder/IIS application from the IIS Administration console, as shown in Figure 12-12.
Note that I've created the application under a site named WroxServer because on my local machine the Default Web Site is taken by Windows SharePoint Server. Pro versions of windows only allow IIS to have the Default Web Site, but server versions allow multiple web sites to be defined.
Ensure that ASP.NET version 2.0 is selected in the ASP.NET tab of the folder's Properties window: It is normally set to version 1.1 by default if the computer has both versions. Then, from Visual Studio 2005, click the Copy Web Site… item from the IDE's Website menu. First you must connect to the destination, which can be a normal folder, an IIS/HTTP site, or an FTP site. In Figure 12-13, I'm connecting to the TheBeerHouse application folder (created above) on my local IIS server.
The tool's user interface is simple: Once you select the destination, you can choose to copy everything from the source (the local copy of the site's files) to the destination, to copy everything from the destination back to the source (useful when someone else has updated the site and you want to download the latest version to your computer), or to synchronize the files on the source and destination according to their date. To deploy all your files, including source code, first make sure your web.config file has the connection string for your remote database. Then, connect to your remote site on the right side, and then select everything on the left, except for the App_Data folder, and copy it to the right side. Figure 12-14 illustrates the tool after a successful complete copy.
Although you can choose an FTP site as the destination for the copy, Visual Studio's Copy Web Site feature is slower than most third-party FTP clients, and it hung a few times while I was testing this feature. Because of this, I prefer using an external FTP client instead of the Copy Web Site feature when I am deploying to a remote site using FTP. Personally, I like the freeware FileZilla FTP client (http://filezilla.sourceforge.net/). However, the Copy Web Site feature works well when copying to a local folder or an IIS application.
If you deploy the site by copying all the files (including the source code), the pages and the source code files are compiled dynamically at runtime when they are first requested by a user. This is called in-place compilation, and the generated assemblies are compiled into a temporary folder. As an alternative, instead of deploying source files, you can use the aspnet_compiler.exe tool (located under C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727) to pre-compile the source code files and (optionally) the markup files. This is the command you could use to pre-compile everything (this should all be entered on one line):
aspnet_compiler.exe -p c:\Projects\ASP.NET\TheBeerHouse\TBH_Web -v /TheBeerHouse c:\Deployment\TheBeerHouse
The -p parameter specifies the source directory, and the -v parameter specifies the virtual directory used at runtime by the site. The path at the end of the command is the destination directory for the compiler output files. If you look under the c:\Deployment\TheBeerHouse\bin folder, you'll find multiple .dll assembly files, plus one .compiled XML file for each .aspx and .ascx file (see Figure 12-15).
The files named with a .compiled extension contain XML text that shows the relationship between the virtual path of a page or user control and the corresponding type compiled into one of the assemblies. If you look into any of the .aspx files, you won't find any HTML/ASPX markup code, but rather the markup string printed below:
After executing the aspnet_compiler, you take all the output generated by this tool and upload it to the remote server, typically via FTP. If you're deploying to a server within your network you might simply copy the files to a shared folder on that server. However, even local servers are often isolated behind a firewall, so FTP may be needed anyway.
Compiling the markup code may definitely be appealing in some circumstance, such as for packaged commercial products for which you don't want the client to change anything; however, if you're deploying to your own site this may not be particularly useful or necessary. Furthermore, it would complicate updates, because every time you need to change a line of markup you'd have to recompile everything and re-deploy the generated files. In the case of deploying to your own sites, it's simpler to pre-compile only the source code files but not the markup files. To do this, just add the -u switch (which stands for updateable) to the command line, as follows:
aspnet_compiler.exe -p c:\Projects\ASP.NET\TheBeerHouse\TBH_Web -v /TheBeerHouse -u c:\Deployment\TheBeerHouse
With this command no .compiled files will be generated under the /bin folder, and the content of the aspx and .ascx files won't be removed. However, the CodeFile attribute of the @Page and @Control directives will be removed, and the Inherits will be updated with a reference to the type compiled into one of the generated assemblies.
Note that all static files (images, .htm files, .css stylesheet files, etc.) are always copied "as is" to the target folder. These are never included as part of a pre-compile.
However, there's a small deployment issue when using one of the two pre-compile commands described above: The assemblies they generate always have a different name, which makes it difficult to update the site locally and then replicate the changes remotely, because the assembly names will be different after each pre-compile. If you don't want to leave old and unused assemblies in the remote /bin folder, you need to delete them first and then upload all new .dll files. This is very annoying and time-consuming, so you can add the -fixednames compiler switch to cause the aspnet_compiler to create an assembly for each file it compiles, using a fixed name scheme. This is good because it allows you to update the site locally, recompile it, and then upload only the changed assembly file. This is the modified command line:
aspnet_compiler.exe -p c:\Projects\ASP.NET\TheBeerHouse\TBH_Web -v /TheBeerHouse -u -fixednames c:\Deployment\TheBeerHouse
I covered the syntax of the command-line tool for completeness (and because many of you will want to script this procedure), but you don't have to remember all the various switches because Visual Studio provides a simple integrated UI for aspnet_compiler, which you can access by clicking Build ð Publish Web Site. Figure 12-16 shows the graphical front-end that it provides, making it easy to select your options, and to select a local or remote IIS site, or an FTP site, as the destination for the operation, in addition to a local folder.
Some of you may be concerned about the large quantity of assemblies produced by the pre-compilation step. In large projects with hundreds of pages, the /bin folder will contain a lot of files, and it may be more convenient for deployment if you could combine all those .dll files into a single assembly file. There's no way to do this with the tools included in VS2005 and the standard installation of the .NET Framework 2.0, but Microsoft listened to its customers, and after releasing VS2005, they later released a free package called "Visual Studio 2005 Web Deployment Projects," which can be downloaded from http://msdn.microsoft.com/asp.net/reference/infrastructure/wdp/default.aspx. After installing the package, you'll find a new command-line tool called aspnet_merge.exe under the C:\Program Files\MSBuild\Microsoft\WebDeployment\v8.0 folder. As its name suggests, it enables you to merge the multiple assemblies generated by the aspnet_compiler tool into a single dll. When you run this program you only need to specify the path of the pre-compiled web site where it can find the assemblies you want to merge:
The preceding command generates a dll for each of the web site's folders containing files that were pre compiled by aspnet_compiler. This is useful when you have folders that include a sub-application supported by different developers (such as the administration console), and you want to have separate assemblies for separate sections so that you can update them independently on the production server. In other cases, however, you may prefer to merge everything into a single assembly: You can do so with the -o switch, which specifies the name of the assembly being generated:
aspnet_merge.exe c:\Deployment\TheBeerHouse -o MB.TheBeerHouse.dll
Note that the tool can be used whether the aspnet_compiler.exe pre-compiled the markup code or not. But this tool never merges in any external libraries referenced by the web site's source files and pages, such as the MB.TheBeerHouse.CustomEvents.dll and the FredCK.FCKEditorV2.dll assemblies. It only merges assemblies generated by aspnet_compiler.exe.
As for aspnet_compiler, there's also a front-end UI for aspnet_merge. The Visual Studio 2005 Web Deployment Projects package is installed as an add-in for VS2005, and it adds a new project type called a "Deployment Project." You add a new deployment project to your solution by clicking the Add Web Deployment Project… option on the IDE's Build menu, or via the same option on the context menu of the web site in the Solution Explorer window. You create the project by choosing its name and location from the dialog box shown in Figure 12-17.
The project added to the Solution Explorer contains no files; you have to double click the project name to open its configuration dialog box, from which you can specify a number of options. Among other things, you can specify how you want the pre-compiler to work, and how you want the files merged. In the first field of the dialog box (see Figure 12-18), you specify the output folder and choose whether the user interface pages and controls should be pre-compiled (which is the updateable option, corresponding to the -u switch of the aspnet_compiler.exe tool).
In the second tab, Output Assemblies (see Figure 12-19), you specify whether you want to compile everything into a single assembly, have an assembly for each folder, have an assembly for the user interface pages and controls, or have an assembly for each class and page being compiled (this last option means you don't want to use aspnet_merge.exe). From here you can also specify the version information of the generated assemblies. If this information is not provided, the settings specified in the web.config file located under the /App_code folder will be used instead (if the file is present, which is not a requirement).
The third tab, Signing (not shown here), enables you to sign the generated assemblies with a key file generated by the sn.exe command-line tool, to give them a strong name. This isn't normally desired for your own sites, but may be useful when you're creating a packaged application and you want to ensure that your assemblies will not be tampered with. In the last tab, Deployment (see Figure 12-20), you can choose to replace one or more sections of the site's web.config file with the content from another file. For example, if you write connectionStrings=connectionStrings.LocalSql.config, the whole <connectionStrings> section will be replaced with the content of the connectionStrings.LocalSql.config file at the end of the build process. This enables you to have a connection string pointing the SQL Server Express database to be used while testing the site locally, and later have it automatically replaced with a connection string referencing a local or remote SQL Server 2005 database after building the project for deployment. You can specify additional sections to replace, one per line. You can also use this window to specify a virtual directory to be created during the build process, and whether the App_Data folder will be deleted from the files generated (useful when you will use a SQL Server 2005 database after the build, in which case you do not want to deploy your express files under App_Data).
Once you've completed the configuration, you can build the project. At the end of the build process you'll find a copy of the site with the pre-compiled and merged assemblies, plus all other files such as pages, controls, images, stylesheets, and so on in the output folder. You can then take this entire output and upload everything to the production server, typically via FTP.
Deployment projects simply consist of an XML file used to pass options to MSBuild.exe, the new Microsoft build tool capable of compiling and building complex projects and solutions. MSBuild is an extensible tool that uses configuration files that can contain many different options. And if an option or a task that you'd like doesn't exist yet, you can create it as a C# class, and have MSBuild call it. Many of the configuration settings described here were implemented as custom settings and tasks by the developers of the Web Deployment Projects add-in. There are many more available options in addition to those you can configure from the Properties window explored earlier, such as the option to exclude files from the build, create new folders, grant the ASP.NET account write access to a folder (only on your local machine, though — you'll still need to replicate these security settings on the remote production server), execute external programs, and much more. You can add more settings and tasks (i.e., operations to run before or after the build and the merge processes) directly from the XML configuration file, which can be opened by clicking the Open Project File option from the Web Deployment project's context menu. Covering MSBuild is beyond the scope of this book, but you can find a lot of good documentation about this on the web, and in the documents that come with the Web Deployment Projects package.
By default, all projects added to the solution are built in Visual Studio when you launch the primary project, i.e., the web site. Building the deployment project takes quite a lot of time, however, depending on the size of the site (on my machine it takes around 30 seconds to generate the pre-compiled site), and it is not something you want to do while testing the site locally. In order to avoid this waste of time, you can just exclude the project from the Debug Build from the Build ð Configuration Manager… dialog box.
Creating an installer package that you can give to your clients, and that completely installs and sets up your site automatically, may be simpler than you think. In the old days, the setup programs were typically created with tools such as InstallShield or Wise Installation System, but starting with VS.NET 2003 they can be created with VS itself, thanks to the Web Setup Project types you find by selecting Other Project Types ð Setup and Deployment, from the Add New Project dialog box (see Figure 12-21).
The Web Setup Project is tailor-made for creating installers for web-based applications. You add one such project to your current solution, and then you must tell it which files you want to include in the package. You could choose files one by one, but there may be thousands of files (including images and all static content files), so instead you can add the output of another project to the package (see Figure 12-22), and, in particular, the output of the Web Deployment project created earlier (see Figure 12-23). This includes everything you need (pages, controls, pre-compiled assemblies, and static content), so you shouldn't need to add anything else. If you do, however, then you could still add individual files from other sources — for example, if you wanted to include a manual that isn't among the web site's deployment-related files.
After you create the project, it pre-configures the creation of a Web Folder in the File System editor, as the destination for the installation process (see Figure 12-24): You can change its default name, the default page, application mappings, and related options that you would have manually configured from the virtual directory's Properties window in the IIS Administration console.
The default user interface includes steps for choosing the destination server and the folder name, and default options for the execution of the installation process. You can, however, open the User Interface editor (click the sixth icon from the left in Server Explorer's toolbar, after ensuring that the Setup project is selected) and add, remove, or modify steps. For example, you can put an image banner on them to customize their default appearance. Or, as shown in Figure 12-25, you can add a step that shows a license file, which users must agree to before proceeding.
After you've configured everything, you can build the project, and you'll end up with a setup.exe file that launches an .MSI file. Figure 12-26 shows the installer at runtime, demonstrating the step where you choose the destination server and folder, and the classic progress bar.
Creating a setup program in a matter of minutes is very cool! This basic setup does quite a lot of things (it creates a destination folder, turns it into an IIS virtual application with the proper settings, and copies all the necessary files into it), but it could be further extended with custom steps and actions. For example, you could create an additional step that enables users to choose whether they want to use a SQL Server Express database or a SQL Server 2005 database; and in the latter case it could execute .SQL scripts to automatically create the database and the required objects. Covering these advanced topics is beyond the scope of this book, as it pertains to the Installer projects and desktop programming in general, but I wanted you to know that you can create some useful setup programs using only Visual Studio. However, in some situations where you have advanced needs, there is still some benefit to be obtained from third-party installation builders such as InstallShield and Wise.