Gorgo.Live.ToString()

Mariusz, Gorzoch tech Blog

Creating installer for WCF window service host

leave a comment »

Few days ago I was asked to move one of my WCF services to the production enviroment. In general I could move it, thru manual process (zip, xcopy, installutil… blablabla), but this time I wanted to do this right, that is thru "Setup" project. I wanted to be sure that if someone in the future will decide to upgrade my solution, then he will have a really nice setup to unistall current version and install new one. OK, so I have my WCF project, which will be hosted as windows service, and now … where to start ?
 
1. First we need to create "Visual studio setup project". This is easy part, we just go to Visual Studio, click "New project", select "Other project types"->"Setup and deployment" and "Setup Project". Give him a nice name, and hit "OK". This will create empty setup project for you.
 
2. When Project is created, then now we need to add our resources which need to be installed. In my case there is four projects:
 
they are (from the top to bottom)
– Windows service project, which is hosting my WCF service
– DataAccess library used by the service implementation
– WCF service contracts
– WCF service implementation
 
so, we are adding those project we need to switch into "File system view" (Right click on the "Setup project" name -> View -> File System). Now we need to add our outputs, by "Right click" on "Application folder"->Add->"Project output". This will popup screen were we can choise "Project" and select what we want to add to our "Setup" project:
 
 
we are selecting all "Primary outputs" for all projects we want to add to "Setup" project. If you do so, we can say that the easest part was done. Now we need to customize the project a little bit.
 
3. We need to force our "Setup" project to install "windows service" during project instllation. To do so, we need to go to custom actions ("Right click" on the setup project name -> View -> Custom actions). When the new view pop-up, please right click on "Custom Actions" and click "Add custom action", then choise your "Windows service project" (from Application folder) and click OK. This should add your project output to all custom actions (Install,Commit, Rollback, Uninstall). If you do so, then you are almost ready to go.
 
4. Twek-up of service configuration file. The last think I needed to do was the tweak-up of the configuration file. I don’t know what about you, but in my case I store base address of my WCF service inside "service window host" configuration file. This base address need to be tweak-up depend on the machine where the service is installed. To achive this during installation we need to create "Custom action". (Here is an example of custom action to change content of web.config file). In an nutshell to do so, you need to create new project of "project class library" and add to it "Installer class" item. Then go into "code" side of new added item and override "Commit" function. In my case code of this function looks like this:
 
     [RunInstaller(true)]
    public partial class AdjustWCFConfig : Installer
    {
        public AdjustWCFConfig()
        {
            InitializeComponent();
        }
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
            string ServerName = Environment.MachineName;
            StreamWriter installLog = new StreamWriter(@"c:\installation.log");
            installLog.AutoFlush = true;
            installLog.WriteLine("Installation started at ‘{0}’", DateTime.Now.ToLongTimeString());
            installLog.WriteLine("Server name : {0}", ServerName);
            try
            {
                //we are using reflection to fine where configuration file is located
                Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
                string strConfigLoc = asm.Location;
                string strTemp = strConfigLoc;
                strTemp = strTemp.Remove(strTemp.LastIndexOf(@"\"), strTemp.Length  – strTemp.LastIndexOf(@"\"));
                installLog.WriteLine("FileInfo : {0}", strTemp);
                FileInfo fi = new FileInfo(strTemp + @"\Hempel.Product.ProductWindowsServiceHost.exe.config");
                if (!fi.Exists)
                {
                    throw new InstallException("Missing configuration file");
                }
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(fi.FullName);
                //saving content of conf file
                installLog.WriteLine("——configuration file—");
                installLog.WriteLine(xmlDoc.OuterXml);
                installLog.WriteLine("——end of configuration file—");
                //Adjusting configuration file
                installLog.WriteLine("Adjusting configuration file with proper base address");
                XmlNode current = xmlDoc["configuration"];
                installLog.WriteLine("’configuration’ node found");
                current = current["system.serviceModel"];
                installLog.WriteLine("’system.serviceModel’ node found");
                current = current["services"];
                installLog.WriteLine("’services’ node found");
                current = current["service"];
                installLog.WriteLine("’service’ node found");
                current = current["host"];
                installLog.WriteLine("’host’ node found");
                current = current["baseAddresses"];
                installLog.WriteLine("’baseAddresses’ node found");
                current = current["add"];
                installLog.WriteLine("’add’ node found");
                current.Attributes.GetNamedItem("baseAddress").Value =
                    String.Format("http://{0}:8889/Hempel.Product.ProductWindowsService/Product/", ServerName);
                installLog.WriteLine("Adjustement completed, saving configuration file");
                xmlDoc.Save(fi.FullName);
            }
            finally
            {
                installLog.WriteLine("Ending edit of configuration file");
                installLog.Close();
            }
        }
    }
 
This code will open configuraiton file of my service window and tweak-up the baseaddress of the service.
 
Now, save, build, and go to the setup project and as shown before you need to add output of our new "class project" to the setup "File system"->"Application folder". When you do so, then go to "Custom action" view, and right click on the "Install"->"Add custom action" and point to the new class library output project. The same thing do for "Commit". Your "Custom view" should looks like this:
 
 
Notice here, that this is importent that you add your new "Custom action" to "Install" and "Commit", even if you are overwriting only "Commit" action. If you will not add you custom action to install, then you will get "File can not be found" exception during installation (Here you can find more about it).
 
If you did everything right, then you are done
 
Done!
 
ps. my SON done a first step yesterday… I need to say that I’m really proud of him, and quite envy him that he done so huge step  forward in his life with such a little move. I don’t make any more such huge progess in such a short time and I’m just wondering if he should really learn from me or maybe it should be the other way around, that I should start to learn from him 🙂
 
(here is my little hero)
 
 
Advertisements

Written by Mariusz Gorzoch

10 July 2009 at 13:13

Posted in WCF

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: