08 februari 2007

Anpassa web.config under installation av webbapplikation

Installationsavdelningen där jag sitter och knackar kod gillar inte att pilla med en web.config för testmiljön och en annan för produktionsmiljön. Detta ledde mig fram till en utmaning att skapa ett installationsprojekt som on-the-fly kunde modifiera web.config-filen utifrån val under installationsprocessen. Kanske finns det bättre alternativ att använda för att uppnå detta men nedan beskriver jag en väg som fungerade för mig.

Om vi först kikar snabbt på web.config så har jag modifierat taggen appSettings

<appSettings>
<add key="PackingSlipWebService.PackingSlip" value="@WEBSERVICE_PACKINGSLIP"/>
<add key="AuthorizationWebService.Authorize" value="@WEBSERVICE_AUTHORIZATION"/>
</appSettings>

I fältet value har jag angett två variabler som jag sedan tänkt ersätta under installationsprocessen med rätt värden.

Lägg till ett nytt Web Setup Project till din Solution.
Högerklicka på projektfilen och välj Add/Project Output och sedan Content files.
Lägg till ett nytt formulär i User Interface Editor genom att högerklicka under formuläret Start och välja Add Dialog. Välj sedan ett fördefinierat formulär med två radioknappar. I mitt fall skall jag låta användaren välja mellan att installera till antingen en test- eller en produktionsmiljö. Button Property är en parameter som är viktig att notera. I exemplet har jag kallat den för ENVIRONMENT.


Nu lämnar vi installationsprojektet för en stund. Vi måste nämligen skapa en klass med kod som skall köras under installationsprocessen.

Högerklicka på din solution och välj att lägga till ett nytt projekt av typen Class Library.

När projektet är skapat kan du radera Class1.cs och sedan lägga till en ny komponent genom att högerklicka på projektet och välja Add/Component och sedan Installer Class.

Så här ser koden i klassen ut i mitt projekt. Byt ut lämpliga avsnitt så att det passar ditt ändamål.

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Reflection;
using System.Xml;

namespace InstallerClassLibrary
{
[RunInstaller(true)]
public partial class InstallerConfiguration : Installer
{
public InstallerConfiguration()
{
InitializeComponent();
}

public override void Install(IDictionary stateSaver)
{
ModifyWebConfig();
}

private void ModifyWebConfig()
{
int i = 0;
string file = "";

if (Context.Parameters["ENVIRONMENT"] == null)
throw new InstallException("Parameter ENVIRONMENT is missing.");

try
{
string assemblyName = "SMTPackingSlipInstallLibrary.dll";
Assembly assembly = Assembly.GetExecutingAssembly();
string assLocation = assembly.Location;
string mapPath = assLocation.Substring(0, assLocation.IndexOf(assemblyName));

file = mapPath + "web.config";

FileInfo fileInfo = new FileInfo(file);
if (!fileInfo.Exists)
throw new InstallException("Following file is missing: " + file);

UpdateConfigFile(file);

}
catch (Exception e)
{
string message = i.ToString() + "; " + e.Message + "; " + file;
throw new Exception(message);
}
}

public void UpdateConfigFile(string filepath)
{
string s = "";

try
{
string environment = Context.Parameters["ENVIRONMENT"];

// Loads the config file into the XML DOM.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(filepath);

string appSettings = xmlDocument.InnerXml;

string packingSlipString;
string authorizationString;

if (environment == "1")
{
packingSlipString = "http://packingslipservice.smt.sandvik.com/PackingSlip.asmx";
authorizationString = "http://wde2prod.is.sandvik.com/Sandvik.WebServices.Authorization/AdministrateUser.asmx";

}
else
{
packingSlipString = "http://packingslipservicetest.smt.sandvik.com/PackingSlip.asmx";
authorizationString = "http://wde2test.is.sandvik.com/Sandvik.WebServices.Authorization/Authorize.asmx";
}

// Replace values in web.config
appSettings = appSettings.Replace("@WEBSERVICE_PACKINGSLIP", packingSlipString);
appSettings = appSettings.Replace("@WEBSERVICE_AUTHORIZATION", authorizationString);

xmlDocument.InnerXml = appSettings;

// Save web.config
xmlDocument.Save(filepath);
}
catch (Exception e)
{
throw new Exception("Error: " + s + " " + e.Message + " *** " + e.InnerException);
}
}
}
}

Då går vi tillbaka till installationsprojektet och väljer Custom Actions Editor.
Under mappen Install väljer du Add Custom action...
Klicka sedan på Add Assembly eller Add File och lägg till den dll-fil som skapades vid kompileringen av InstallLibraryprojektet.
Markera sedan filen som poppat upp under Installmappen och fyll i Custom Action Data med /ENVIRONMENT = [ENVIRONMENT]. Detta betyder att valet av deploymentmiljö kommer att vara tillgängligt i InstallLibraryprojektet via variabeln ENVIRONMENT.



Nu är det bara att kompilera installationsprojektet och köra msi-filen. Om allt rullar på som det ska så skall @-parametrarna i web.config bytas ut mot olika värden beroende på om det är en test- eller produktionsmiljö.

Plita gärna ner nån rad med synpunkter nedan!