Change settings for eventlog in Service installer

I was developing a Windows service. Everything went smooth until I was asked to add logging for the service into a separate log file in the event viewer. I want to share my journey with you so it may help finding a solution for similar or the same issue.

After I had learned to install a service using a service installer, I ran into some troubles configuring the event viewer. My service had three logging options. First is to a text file on disk, second is to the Windows Event Viewer and I added an extra option to send a message to a messaging app. All service issues where logging fine. As a last option I was asked to log to a separate log in the event viewer like this:

First I tried adding all kind of options to my logging library to check, add and change the logging destination. That didn’t work and I found that the log needed to be set during initial installation of the service. Reason that previous attempts failed was that when changing these settings, the application needs admin privileges and changing logging options afterwards needed the machine to be rebooted etc.

I searched the internet for a solution and after a couple o hours I stumbled upon this article: https://stackoverflow.com/questions/115488/what-is-the-most-reliable-way-to-create-a-custom-event-log-and-event-source-duri

The post of Simon Mattes in this article helped me out. I altered the code a bit for my own use:

public ProjectInstaller()
{
InitializeComponent();
//Skip through all ServiceInstallers.
foreach (ServiceInstaller ThisInstaller in Installers.OfType())
{
//Find the first default EventLogInstaller.
EventLogInstaller ThisLogInstaller = ThisInstaller.Installers.OfType().FirstOrDefault();
if (ThisLogInstaller != null)
{
//Modify the used log from "Application" to the same name as the source name.
//This creates a source in the "Applications and Services log" which separates your service logs from the default application log.
ThisLogInstaller.Log = "TestApplication"; //ThisLogInstaller.Log = ThisLogInstaller.Source;
ThisLogInstaller.Source = "TestSource";
}
}
}

Check out this post on adding an installer to your application: http://kannekens.nl/registering-installing-a-windows-service-part-2/


Debugging Windows Service in Visual Studio

After some searching and testing how to debug a windows service, I found that for me the following solution is working very well.

First register your service as a service on your machine. This can be done with a few simple steps. How to do this is described in this article: http://kannekens.nl/registering-installing-a-windows-service/

Next add a line / lines Debugger.Break(); in your code where you want the debugger to start. Now compile in debug mode clicking in Visual Studio menu: Build, Build Solution while the Configuration Manager is set to Debug.

After the application compiled successfully we can stop and start the service to ensure these modifications are run:

I used the tips from https://docs.microsoft.com/en-us/dotnet/framework/windows-services/how-to-debug-windows-service-applications and https://stackoverflow.com/questions/104235/how-can-i-use-debugbreak-in-c.

Right click the Visual Studio application and select more…, Run as administrator

Click Debug, Attach to Process in the Visual Studio menu.

This will open a dialog where you need to select the right process to debug. Check the Show processes from all users checkbox. Find your Service process and click Attach.

Simple unit tests in Visual Studio solutions

In Visual Studio it is really simple to add unit tests that are automatically run in your build script. Right click your solution to add a test project:

Add a few test methods:

Check this Step-By-Step for an explanation:

https://visualstudiomagazine.com/articles/2013/07/29/test-driven-development-with-visual-studio-2012.aspx

Check this link for some Unit test basics:

https://docs.microsoft.com/en-us/visualstudio/test/unit-test-basics?view=vs-2017

/// <summary>
/// Test if flipcoins throws as many times as requested
/// </summary>
[TestMethod()] public void FlipCoinsTest1Times()
{
//Arrange
int odd, even;
int times = 1;

//Act
CoinFlipper coinFlipper = new CoinFlipper();
coinFlipper.FlipCoins(times, out odd, out even);

//Assert Assert.IsTrue(times == odd + even);
}

Open Test explorer window

Right click a selection of tests and select “Run selected tests”.

When the tests are OK, we can check in the solution. Default the Build in Azure will run libraries with names containing *test*.

The results for this solution: 8 tests passed.

Hosted Build has errors for missing reference Crystal reports libraries

I was planning a migration for my solution from a build on my local machine to a build in Azure Devops. I want to use the Hosted VS2017 because then I do not have to worry about maintaining local Build servers.

When I added the solution to Azure and set up a build pipeline I encountered the following errors in the MSBuild log:

2019-01-10T10:11:49.9382855Z ##[error]Notepad\CrystalReportsViewer.cs(8,7): Error CS0246: The type or namespace name ‘CrystalDecisions’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9412999Z ##[error]Notepad\CrystalReport1.cs(153,53): Error CS0246: The type or namespace name ‘RequestContext’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9414407Z ##[error]Notepad\CrystalReportsViewer.cs(14,16): Error CS0246: The type or namespace name ‘ReportDocument’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9415960Z ##[error]Notepad\CrystalReport1.cs(19,35): Error CS0246: The type or namespace name ‘ReportClass’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9430403Z ##[error]Notepad\CrystalReport1.cs(24,32): Error CS0115: ‘CrystalReport1.ResourceName’: no suitable method found to override
2019-01-10T10:11:49.9432260Z ##[error]Notepad\CrystalReport1.cs(33,30): Error CS0115: ‘CrystalReport1.NewGenerator’: no suitable method found to override
2019-01-10T10:11:49.9433304Z ##[error]Notepad\CrystalReport1.cs(42,32): Error CS0115: ‘CrystalReport1.FullResourceName’: no suitable method found to override

I found a solution for this issue adding a pre-build event:

First I needed to add the CRRuntime msi and a pre-build.bat file to my solution:

The content for the pre-build file is an administrator installation of the CRRuntime msi. The command is:
msiexec /a “%1CRRuntime_64bit_13_0_23.msi” /quiet /norestart /log “%1CRRuntime_64bit_13_0_23_install.log”. I only want this to be installed when building a release (in Azure). For this I added the condition to only install for release builds.

if %2 == “release” msiexec /a “%1CRRuntime_64bit_13_0_23.msi” /quiet /norestart /log “%1CRRuntime_64bit_13_0_23_install.log”

Last I have added a pre-build event command line for the solution:
“$(ProjectDir)pre-build.bat” “$(ProjectDir)” “$(ConfigurationName)”

That’s that. Now the host will install the Crystal reports run time before building the solution.