Azure click once publish for test and production CI/CD

Change config and sign a click once deployment for test in an Azure build application:

I have the following release pipeline in Azure:

Continuous Integration pipeline that will build for every check in on master branch. This build will trigger a Continuous Delivery pipeline that will deploy the release for the click once application to test. The same installation wil be deployed to production after approval in test on this pipeline.

I want the same build that I tested to go to production. The click once is compiled for release. The app.config I have in source is the production version. So once installed the app will default be configured to connect to production datasources.

For test however I want the app.config to be replaced with a app.config.debug version. This is a app.config that contains the test and debug datasources.

After putting this config file in the deployment the signature for the click once is no longer valid. I resigned the click once manifest for the changed config with a tool from Microsoft .NET SDK.

I used the mage.exe (from .NET framework Tools). Path for my installation: C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools\mage.exe.

I added 3 files to the source directory:

mage.exe
app.config.debug
ACertificateFile.pfx. This pfx is the same I used in the project to sign the manifest file.

After adding these 3 files to the source folder I added a copy step in the build pipeline to add these files to the app.publish folder:

And a script to update the app.config and resign the manifest has to be executed before copying the files to the local deployment server.

@echo on
for /f “delims=” %%F in (‘dir “$(system.defaultworkingdirectory)_Bla.WPF.BLA-.NET Desktop-CI\$(System.TeamProject)-$(Build.BuildNumber)\Application Files” /B /AD’) do set deployDir=%%F
set “to=$(system.defaultworkingdirectory)_Bla.WPF.BLA-.NET Desktop-CI\$(System.TeamProject)-$(Build.BuildNumber)\Application Files\%DeployDir%”
set “from=$(system.defaultworkingdirectory)_Bla.WPF.BLA-.NET Desktop-CI\$(System.TeamProject)-$(Build.BuildNumber)”

copy /Y “%from%\App.config.debug” “%to%\BLA.exe.config.deploy”

ren “%to%*.deploy” *.
“%from%\mage” -sign “%to%\BLA.exe.manifest” -CertFile “%from%\ACertificateFile.pfx”
“%from%\mage” -update “%to%\BLA.exe.manifest” -CertFile “%from%\ACertificateFile.pfx”
“%from%\mage” -update “%from%\BLA.application” -appmanifest “%to%\BLA.exe.manifest” -CertFile “%from%\ACertificateFile.pfx”

ren “%to%*.*” *.*.deploy
ren “%to%*.manifest.deploy” *.
del “%from%\mage.exe”
del “%from%\App.config.debug”
del “%from%\ACertificateFile.pfx”

Important steps to publish a click once app using Azure

Publish in Azure pipeline:

step 1 Build solution with parameter /target:publish

YAML: #Your build pipeline references an undefined variable named ‘Parameters.solution’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972

#Your build pipeline references the ‘BuildPlatform’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971

#Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971

steps:

– task: VSBuild@1

  displayName: ‘Build solution **\*.sln’

  inputs:

    solution: ‘$(Parameters.solution)’

    msbuildArgs: ‘/target:publish’

    platform: ‘$(BuildPlatform)’

    configuration: ‘$(BuildConfiguration)’

Step 2: Copy artifact files to publish folder

NuGet pack with include referenced projects

Yesterday I wanted to build a NuGet package with a dll that references a project in the same solution. The referenced project however was not added to the installation package when I packed a new Nuget package.

I searched the internet and found some remarks about adding a parameter includereferencedprojects.

Then I came to my pack command in Azure and saw that the parameter was not in the Nuget pack task.

The YAML i had:

At first I didn’t know how to add the includereferencedprojects parameter. I then changed the “automatic package versioning” in “pack options”. I set it to “Off” and an extra checkbox was presented:

I checked the box:

And set the versioning back to the previous value.

Now my YAML included the includereferencedprojects parameter.

After I started a new build with this pipeline, the referenced project dll’s were added to my package.

How to select duplicate values in a SQL table

First make a selection of duplicate values using count:
SELECT
col1, COUNT(col1) AS CountOf
FROM test
GROUP BY col1
HAVING COUNT(col1)>1

Then join this selection with the table on table keys:

select [key],a.col1 from
test a
inner join (SELECT
col1, COUNT(col1) AS CountOf
FROM test
GROUP BY col1
HAVING COUNT(col1)>1) b on a.col1 = b.col1

Git merge branche Development into master

Today the standard source control with Visual Studio is GIT. This source control has a lot of powerful features and options.

For me it took some investigation, testing and searching the internet on how to best merge a development branch (or a bugfix branch, etc.) into the main (master) branch.

git checkout master
git merge –squash Development
git commit OR git commit -m “This is a merge from branch to branch at moment x”

What these commands will do is compact all commits to the development branch and add them to the master in one separate commit.

ATTENTION: When you check the source tree you will also notice that there is NO “merge branch” line.

Next I have added an extra branch, commit a change. Last action was to merge the branch using “git merge HotfixOnMaster”:

After merging a complete branch without squashing. Every commit remains in the master history:

Alternative found on makandracards.com:
Squash several Git commits into a single commit
This note shows how to merge an ugly feature branch with multiple dirty WIP commits back into the master as one pretty commit.

git checkout master # Switch to the master branch and make sure you are up to date.
 git fetch # this may be necessary (depending on your git config) to receive updates on origin/master
 git pull
 git merge feature_branch # Merge the feature branch into the master branch.
 git reset origin/master # Reset the master branch to origin's state. Git now considers all changes as unstaged changes. We can add these changes as one commit. Adding, will also add untracked files.
 git add --all
 git commit

Note that this is not touching the feature branch at all. If you would merge the feature branch into the master again at a later stage all of its commits would reappear in the log.
https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit

Report progress in a task in C sharp

One of my first questions starting programming in Visual Studio WPF was how to run processes without freezing the GUI.

After learning the basic concepts of backgroundworkers and tasks in c sharp programming I wanted to know how to report task progress while the task was not yet finished.

I found all kind of solutions to update a progress bar. I also found solutions to use the result for a specific task.

Think still missing for me was to get a screen to show task progress, with detailed logging while the task was still running. In the end this article helped me finding a solution: https://social.technet.microsoft.com/wiki/contents/articles/19020.progress-of-a-task-in-c.aspx

To implement this logic in a solution I started with a form on which I added a button and a listbox.

The button got the following implementation:

private async void ButtonAsyncFileProcessing_Click(object sender, RoutedEventArgs e)
{
    var progressIndicator = new Progress<MyTaskProgress>(ReportProgress);
    await MyMethodAsync(progressIndicator);
}

For the progress indicator I added the following class:

public class MyTaskProgress
{
    //current progress
    public int CurrentProgressAmount { get; set; }
    //total progress
    public int TotalProgressAmount { get; set; }
    //some message to pass to the UI of current progress
    public List<string> CurrentProgressLogging { get; set; }
}

The async method I used for testing was this:

async Task MyMethodAsync(IProgress<MyTaskProgress> progress)
{
    int sleepTime = 1000;
    int totalAmount = 10000;
    List<string> log = new List<string>();

    for (int i = 0; i <= totalAmount;)
    {
        await Task.Delay(sleepTime);
        log.Add(string.Format("On {0} Message", i));
        progress.Report(new MyTaskProgress
            {
                CurrentProgressAmount = i, TotalProgressAmount = totalAmount, CurrentProgressLogging = log });
        i = i + sleepTime;
    }
}

The ReportProgress method used in the button click progressIndicator:

private void ReportProgress(MyTaskProgress progress)
{
UpdateScreen(progress.CurrentProgressLogging,
string.Format("{0} out of {1}",
progress.CurrentProgressAmount,
progress.TotalProgressAmount));
}

And this last method calls a UpdateScreen method:

private void UpdateScreen(List<string> info, string status)
{
    lbOutput.Items.Clear();
    foreach (string s in info)
    {
        lbOutput.Items.Add(s);
    }
    buttonAsyncFileProcessing.Content = "AsyncFileProcessing" +
    "\n" + status;
}

The article that helped me understanding Tasks and backgroundworkers is: https://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html

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/


Registering / installing a Windows service part 2

In this article I want to describe an easy way to add an easy installer to a Windows Service project.

Steps are: – Add the installer for the service
– Configure the service parameters
– Add parameters to start up of the program


Add the installer for the service can be done when you open the service.cs. This will show a gray screen with two links:

Right click this screen and select Add installer in the pop up menu. This will add a ProjectInstaller.cs file with a ProjectInstaller class inside.

Open the Projectinstaller file. This will show two components.

Change settings for the two components according to your needs.

Last step is to add the installer to the program start up. For this we need to change the Program.cs.

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {
        if (args.Length > 0)
        {
            //Install service
            if (args[0].Trim().ToLower() == "/i")
            {
                System.Configuration.Install.ManagedInstallerClass.InstallHelper(
        new string[] { "/i", Assembly.GetExecutingAssembly().Location });
            }

            //Uninstall service                 
            else if (args[0].Trim().ToLower() == "/u")
            {
                System.Configuration.Install.ManagedInstallerClass.InstallHelper(
        new string[] { "/u", Assembly.GetExecutingAssembly().Location });
            }
        }
        else
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
            new ServiceMonitor()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Can’t Sync Windows 10 PC Clock to The Internet

While a workgroup computer is connected to the internet, it might not be able to reach the time servers configured. The error: “An error occurred while Windows was synchronizing with time.windows.com. The peer is unreachable.” is displayed.An error occurred while Windows was synchronizing with time.windows.com. The peer is unreachable.

I’ve found a method to add your local time server to these entries and sync time with a local time server.

Please note: Availability of certain settings can be disabled via distributed Computer policies. These policies are managed by the Computer / Domain administrator.

First you have to start the registry editor with the command regedit.

Navigate to the container: “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers”. In this container add a new entry right clicking in the window. Add a new entry with the next number as name.

Double click the entry and add the IP address of the local time server.

Next go to the control panel and navigate to Internet Time Settings via: “Time & Language”, then “Additional date, time, & regional settings” in bottom part “Related settings”. Open “Date and Time” and then select the third tab named “Internet Time” and click the button “Change settings…”.

Select your local time server and press “Update now”.

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.