donderdag 13 maart 2014

Working with windowsservices

Windows services

Voor het installeren van een windowsservice kun je gebruik maken van de windows installer.

Voor het instellen van bijv. configuratie settings kun je in de installer custom actions en schermen doorgeven
in de eigenschap CustomActionData kun je variabelen uit een scherm halen.
bijvoorbeeld door /Connectionstring="[connstring]" te gebruiken.
[connstring] is dan de variabele inputveld in een installerscherm.

In de windowsservice zelf dien je een inheritance van de System.Configuration.Install.Installer klasse te maken en daarin de Install en/of OnBeforeInstall methodes te overriden.

In deze methodes kun je de Context uitlezen, waarmee je de variablen van de installer kunt opvragen.

Context.Parameters["Connectionstring"]

Servicenaam instellen

Wanneer je de servicenaam wilt instellen moet je dit in de OnBeforeInstall doen. Wil je configuratie settings wegschrijven in de app.config dan kun je dat in de Install doen.

Met de windows installer kun je maar 1 product tegelijk installeren, het is dus niet mogelijk om dezelfde installer te gebruiken om verschillende services met dezelfde broncode te installeren. Mocht je dit wel willen, dan moet je in de installer een nieuwe ProductCode en UpgradeCode meegeven.

Voorbeeld voor het instellen van de servicename en deze opslaan in de app.config.

public partial class ProductInstaller : System.Configuration.Install.Installer
    {
        private ServiceProcessInstaller serviceProcessInstaller;
        private ServiceInstaller serviceInstaller;
        public ProductInstaller ()
        {
            InitializeComponent();
            serviceProcessInstaller = new ServiceProcessInstaller();
            serviceInstaller = new ServiceInstaller();

            //# Service Account Information
            serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
            serviceProcessInstaller.Username = null;
            serviceProcessInstaller.Password = null;

            serviceInstaller.StartType = ServiceStartMode.Manual;        
            serviceInstaller.ServiceName = "test";
            serviceInstaller.DisplayName = serviceInstaller.ServiceName;
            serviceInstaller.Description = serviceInstaller.ServiceName;

            this.Installers.Add(serviceProcessInstaller);
            this.Installers.Add(serviceInstaller);
       
        }

        protected override void OnBeforeUninstall(IDictionary savedState)
        {
            base.OnBeforeUninstall(savedState);
            string serviceName = Context.Parameters["ServiceName"];
            serviceInstaller.ServiceName = serviceName;

            //# Service Information
            serviceInstaller.DisplayName = serviceName;
            serviceInstaller.Description = serviceName;
        }

        protected override void OnBeforeInstall(IDictionary savedState)
        {
            base.OnBeforeInstall(savedState);
            string serviceName = Context.Parameters["ServiceName"];
            serviceInstaller.ServiceName = serviceName;

            //# Service Information
            serviceInstaller.DisplayName = serviceName;
            serviceInstaller.Description = serviceName;
        }

        protected override void OnAfterInstall(IDictionary savedState)
        {
            base.OnAfterInstall(savedState);
            EditSettings();
        }
        private void EditSettings()
        {
            var  executingAssembly =  System.Reflection.Assembly.GetExecutingAssembly();
            var configFile = new System.IO.FileInfo(string.Format("{0}.config",executingAssembly.Location));
            var configXml = new System.Xml.XmlDocument();
            configXml.Load(configFile.FullName);

            System.Xml.XmlElement appSettings = configXml["configuration"]["appSettings"];

            foreach (System.Xml.XmlNode node in appSettings)
            {
                if (node.Name == "add")
                {
                    switch (node.Attributes.GetNamedItem("key").Value)
                    {
                        case "ServiceName":
                            node.Attributes["value"].Value = serviceInstaller.ServiceName;
                            break;
                    }
                }
            }

            configXml.Save(configFile.FullName);
        }
    }


Mislukt het de-installeren van een service?

handmatig een service verwijderen: commandprompt opstarten als administrator
> sc delete "servicename"

vervolgens de bestanden die geinstalleerd zijn, handmatig uit de registry halen. (zit ergens in components)

woensdag 5 maart 2014

C# operators - veelvuldig casten?

Wanneer je veelvuldig objecten van type A naar type B moeten converteren / casten kun je gebruik maken van de zogenaamde operator in c#

De operator is expliciet en impliciet te gebruiken door het keyword implicit of explicit te gebruiken vooraf de operator.

Bij het gebruik van een impliciete conversie mag er geen exception optreden en ook geen dataverlies tussen beide objecten zijn.

Een operator is een static method zonder methode naam.
In het geval van een impliciete conversie krijg je dan een volgend scenario:

class Patient
    {
        public string Achternaam { get; set; }
        public string Voornaam { get; set; }
        public string PatientNummer { get; set; }

        public static implicit operator Patient(Klant klant)
        {
            var p = new Patient()
            {
                Achternaam = klant.Achternaam,
                Voornaam = klant.Voornaam
            };
            return p;
        }
    }


voor Explicit geldt het volgende:
class Klant
    {
        public string Achternaam { get; set; }
        public string Voornaam { get; set; }

        public static explicit operator Klant(Patient patient)
        {
            var k = new Klant()
            {
                Achternaam = patient.Achternaam,
                Voornaam = patient.Voornaam
            };
            return k;
        }
    }

Met bovenstaande klasses kun je dus de volgende code schrijven:

 var k = new Klant()
            {
                Achternaam = "Vos",
                Voornaam = "Patrick"
            };
Patient p = k;

Voor de implicit operator hoef je dus geen cast mee te geven en worden alle gegevens van Klant overgezet naar Patient.

Om van een Patient een klant te maken wordt de explicit operator gebruikt en dien je wel een cast te gebruiken

var p = new Patient()
            {
                Achternaam = "Bedlegerig",
                Voornaam = "Jan",
                PatientNummer = "1234A"

            };
 Klant k = (Klant) p;