About Me

Showing posts with label windows service. Show all posts
Showing posts with label windows service. Show all posts

Friday, May 13, 2011

How to start and stop windows service during building the Visual Studio solution's project.

I have a Visual Studio solution that contains few projects. One of them is a windows service.
You may know how it might be frustrating to turn it off and during each build of the solution.
Today i had a lot of small fixes in the service. Each of them requires to be tested. So my service had to be turned off and on every time. Somewhere in the middle, I lost my patience and decided to make my life easier.

As you may know, each Visual Studio project file you are working on is actually a MSBuild script.
MSBuild is a great script language that can help you to automate things you usually do to compile and build your project. Also it can do a lot of other things. You can read a MSBuild reference about it.
Each time when you building the project, it makes Visual Studio to execute the script.
So, in our case, the obvious solution is to specify a commands that stops the service then makes a build and then starts it again. That commands should be added into YourProject.csproj file.

Unfortunately default MSBuild package of commands does not have one for managing services. But, there is a great library http://msbuildtasks.tigris.org that can do that. As you may see, there is a "ServiceController" task in the list of available commands in the list. That one the command we are going to use.
Download the MSBuild.Community.Tasks.msi package from the "Download the latest release section" of the same page and install it to your computer. The installer will create a directory with the library that contains the task we need - MSBuild.Community.Tasks.dll

The next step is to find the place where we can inject that commands. As I told above, that should be YourProject.csproj file. Open it with Notepad and find there two targets - BeforeBuild and AfterBuild


As you see,  they are empty and commented out.
You need to uncomment it and add calling of "ServiceController" commands:


<target name="BeforeBuild">
    <servicecontroller action="Stop" servicename="ServiceName"/>
</target>
<target name="AfterBuild">
    <servicecontroller action="Start" servicename="ServiceName"/>
</target>

If we try to build our project now, we may get an exception. That's because Visual Studio's MSBuild process does not know the command we specified. All we need to do is to add a reference to the MSBuild.Community.Tasks.dll library that  we downloaded and installed:

<usingtask assemblyfile="..\lib\MSBuild.Community.Tasks.dll" taskname="ServiceController"/>

You may add the "UsingTask" line right after project definition and specify a path to the library in the AssemblyFile attribute.
After that you can freely reload your project in the Visual Studio, compile your service and forget that horrible time when you had to stop and start after each build.

Wednesday, February 16, 2011

Dynamic windows service name

Today i had to install few instances of the same windows service.
Of course they should be named differently.

I found that the name should be set to the ServiceName property of service installer.
This means, that i need to pass a name of the service when I installing it.

I found few solutions, but the most usefull for me, is when the installing is asking me for exact name before it installs the service.
Here is the code that should be placed into the service installer codebehind file (in my case it is ProjectInstaller.cs):
[RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }

  private void BeforeInstallEventHandler(object sender, InstallEventArgs e)
  {

   // Add steps to perform any actions before the install process.

   Console.WriteLine("BeforeInstallEventHandler Called");

   Console.WriteLine("Enter the name you would like this service installed as:");

   serviceInstaller.ServiceName = Console.ReadLine();

   PersistServiceName(serviceInstaller.ServiceName);

   Console.WriteLine("Attempting to install service as: " + serviceInstaller.ServiceName);

  }

  private void BeforeUninstallEventHandler(object sender, InstallEventArgs e)
        {

            Console.WriteLine("BeforeUninstallEventHandler Called");

            serviceInstaller.ServiceName = RetrieveServiceName();

            // Add steps to perform any actions before the Uninstall process.

            Console.WriteLine("Code for BeforeUninstallEventHandler");

        }

  /// 
  /// Storing name of the service to the 
  /// config file, for using duing uninstall
  /// process
  /// 
        private void PersistServiceName(string serviceName)
        {

            TextWriter tw = new StreamWriter("Service.config", false);      

            tw.WriteLine(serviceName);

            tw.Close();

        }

  /// 
  /// Getting stored service name from
  /// the file during uninstall process
  /// 
  /// 
        private string RetrieveServiceName()
        {

            string serviceName;


            TextReader tr = new StreamReader("Service.config");

            serviceName = tr.ReadLine();

            tr.Close();

            Console.WriteLine("ServiceName" + serviceName);

            return serviceName;      
        }
    }

Project installer has few events. The code above is using two of them - BeforeInstallEventHandler and BeforeUninstallEventHandler. First one is using to ask the user the service name and store it to the config file.
The second one is using during uninstallation process to retrieve service name from the file and pass it to uninstall process.
Thus, don't forget to open ProjectInstaller.cs designer and assign its BeforeInstall and BeforeUninstall events with appropriate handlers (BeforeInstallEventHandler and BeforeUninstallEventHandler)