Wednesday, June 21, 2006

ASP.NET 2.0 Deployment : Installer for updating Web.Config settings during Setup - Part II

In Part I of the article we saw how Visual Studio 2005 Web Deployment Projects help in deployment of ASP.NET 2.0 applications. Let us now look at how we can make use of this add-on in building an MSI that also sets the configuration settings.

The first step is to add an installer class in your web project. This installer class will be used in setting the configuration settings in web.config. The following steps will discuss on adding the installer class:

1. Right click on your web project, and then click Add New Item.
2. Under Templates, click Class, and then give the name of the class as InstallerClass.cs.
3. This will get added in the App_Code folder in your web application.
4. Right click on the Web Project, and then click Add Reference. Add the following references to the Web project:
System.Configuration.Install
System.Configuration
System.Windows.Forms
5. Open InstallerClass.cs, and then replace it with the following code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Configuration.Install;
using System.ComponentModel;
using System.Collections;
using System.Windows.Forms;
using System.Xml;
///
/// Summary description for InstallerClass
///

[RunInstaller(true)]
public class InstallerClass : System.Configuration.Install.Installer
{
private System.ComponentModel.Container components = null;
public InstallerClass()
{
components = new System.ComponentModel.Container();
}
protected override void OnBeforeInstall(IDictionary stateSaver)
{
string server = this.Context.Parameters["DATASOURCE"];
string userId = this.Context.Parameters["USERID"];
string password = this.Context.Parameters["PASSWORD"];
string newConnectionString = "User Id=" + userId + ";Password= " + password + ";Data Source =" + server + ";";
string xmlConfigFile = "";
xmlConfigFile = Context.Parameters["INSTALLDIR"] + "web.config";
UpdateConfigFile(xmlConfigFile, newConnectionString, "connectionString");
}
public void UpdateConfigFile(string filepath, string newValue, string keyName)
{
XmlReaderSettings xmlReaderSettings = null;
XmlDocument doc = null;
XmlReader xmlReader = null;
XmlWriterSettings xmlWriterSettings = null;
XmlWriter writer = null;
try
{
xmlReaderSettings = new XmlReaderSettings();
doc = new XmlDocument();
xmlReader = XmlReader.Create(filepath, xmlReaderSettings);
doc.Load(xmlReader);
xmlReaderSettings.CloseInput = true;
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
if (node.Name == "connectionStrings")
foreach (XmlNode childNode in node.ChildNodes)
{
if (childNode.Name == "add" && childNode.Attributes["connectionString"] != null && childNode.Attributes["name"].Value == keyName)
{
string connStr = childNode.Attributes["connectionString"].Value.ToString();
string newConnStr = newValue;
childNode.Attributes["connectionString"].Value = newConnStr;
}
}
}

xmlReader.Close();
xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
xmlWriterSettings.CloseOutput = true;
writer = XmlWriter.Create(filepath, xmlWriterSettings);
doc.Save(writer);
}
catch (Exception)
{
//Handle exeptions
}
finally
{
writer.Close();
}
}
}

6. Save the file and build your web project.

In Part I of the article we discussed on how to add a Web deployment. Make sure the Web Deployment Project is added to the Web project and the settings are done as detailed in Part I of this article. Rebuild this Web Deployment project also.

The next step is to build an MSI. The following steps explain the same:

1. Right click on the solution node in Solution Explorer, point to Add, and then click New Project.
2. Select Setup and Deployment under Other Project Types from the Project Types box.
3. Select Web Setup Project under Templates, and then give a name MyNewWebSiteSetup.
4. Right click MyNewWebSiteSetup on Solution Explorer, point to Add, and then click Project Output.
5. From the Project dropdown, choose (i.e. the Web Deployment project that you have added and compiled). You will find that Precompiled Web Outputs from (Active) is added to your Setup project.
6. Right click MyNewWebSiteSetup on Solution Explorer, point to Add, and then click Assembly.
7. From the Browse tab, browse to the folder where your Web Deployment Project is present. Under the MyNewWebSite_deploy -> Debug -> Bin path you will find the single assembly of the Web Project that was created, named MyNewWebSiteAssembly
(refer Point 5 in Part I of the article).
8. Right click MyNewWebSiteSetup on Solution Explorer, point to View, and then click User Interface.

9. Under the Install node, right click on Start and then click Add Dialog.
10. From the Add Dialog pop up choose Textboxes (A) and then click OK.
11. Right click Textboxes (A) node and then click Properties Window.
12. In the Properties window, set the following properties:
BannerText - Configuration Settings

BodyText- Please provide values for Configuration Settings
Edit1Label-DataSource:
Edit1Property- DATASOURCE
Edit2Label-UserId:
Edit2Property- USERID

Edit3Label-Password:
Edit3Property- PASSWORD

Edit4Visible-False

13. After setting the above properties, close the Properties window.
14. Right click MyNewWebSiteSetup on Solution Explorer, point to View, and then click Custom Actions.
15. On the left pane, right click Install node under Custom Actions, and then click Add Custom Action.
16. In the Look in dropdown list in Select Item in Project dialog, select Web Application Folder.
17. Click the Add File button and then choose the single assembly dll that is present under the MyNewWebSite_deploy -> Debug -> Bin -> MyNewWebSiteAssembly.dll.

Note : If you have not set any path when adding, it would be present in C:\Documents and Settings\ My Documents\Visual Studio 2005\Projects\ GridViewWeb\ MyNewWebSite_deploy\ Debug\bin\ MyNewWebSiteAssembly.dll.

18. Right click MyNewWebSiteAssembly.dll on the left pane, and then click Properties Window.

19. In the Properties Window, set the CustomActionData property to the following:
/datasource=[DATASOURCE] / userid=[USERID] /password=[PASSWORD] /INSTALLDIR="[TARGETDIR]\"

These are precisely the properties we use in the InstallerClass.

20. Right click MyNewWebSiteSetup on Solution Explorer, and then click Build.
21. You can test the installation of MSI using the Install option when you right click MyNewWebSiteSetup on Solution Explorer.

You will find that you can set the connection string properties at runtime during installation of your Web Application.

22. Set your project in Release mode, and then take a build again to take the final installable.

While picking up the single assembly dll was straight forward in ASP.NET 1.1, in ASP.NET 2.0, this has been made possible with the Visual Studio Web Deployment Project Add on. This makes adding the Custom Actions possible.

10 comments:

கார்த்திகேயன் said...

Sir,

I am working in asp.net2.0 /vb2005.

At present, i have one doubt, that is - I want to create a db connection at the beginning of a session of an application (my appl is a website), and use that connection throughout the program until the session ends. Whenever, we want to use the connection, i need not re-connect or re-open the connection but can use the existing connection by make use of connection string.

if it is written in session_start and session_end, i dont think it is got executed in the beginning. and if i place it at the login page, whenever user presses F5/refresh to reload the login page, new connection is created everytime without closing the invalid connections...

what can i do? please give me a suggestion....

Thanks,
Karthikeyan

Steve Dye said...

Hi, thanks for the providing a great article! However, I would like to point out a couple of bugs in the sample code you provided:

1. The XMLReader should be closed before the XMLWriter is created (I was getting an object could not be created error).

2. Point 19 should read: /datasource=[DATASOURCE] / userid=[USERID] /password=[PASSWORD] /INSTALLDIR="[TARGETDIR]\"

Lakshmi said...

Hi Steve,

Thanks for your comments.
1. I didn't get any such error. Anyway, I've made the change.
2. It was type o. Thanks for pointing it out.

Lakshmi

KCM said...

Hey guys, During the installation process when the texbox appears to get values from user, Datasource, userid its ok when we enter Password, its visible, I want to change the textbox to appear as a paswword thatis *********, Any help.
Thanks
KCM

Joepsel said...

Nice article! By the way, there is also another way to edit your Web.config programmatically. You can use the System.Configuration and System.Web.Configuration classes:

Configuration Config = WebConfigurationManager.OpenWebConfiguration(WebPath);
Config.AppSettings.Settings["PathSharedFiles"].Value = PathSharedFiles;
Config.ConnectionStrings.ConnectionStrings["MyDatabase"].ConnectionString = ConnectionString;
Config.Save();

Amr Ammar said...

i counter a problem while installatin "error 2869".
i'm running a windows vista and i have an administrative privileges

Mayur said...

Hi Lakshmi I was trying this out but I am unable to add the assembly when I right click on install to add customn action.

Jeff said...

I am getting the below runtime error on building the web project after adding installerclass.vb

BC30002: Type 'System.Configuration.Install.Installer' is not defined.

Jeff said...

I am gettin the below runtime error on builiding
the web project

BC30002: Type 'System.Configuration.Install.Installer' is not defined.

Jeff said...

Hi Lakshmi,

I dont get any error now. And the websetup file also works fine and creates the msi file.
When I run the msi file it ask me about the connectionstring and creates a virtual directory. But the problem is that it does not change the connectionstring in the deployed web.config file. Please help.