A pleasant walk through computing

Comment for me? Send an email. I might even update the post!

Catching Up on Coding - The Syllabus

I’ve been a software developer for twenty years, but am behind in some skills. So, like Dack Rambo in the 70s TV show “Sword of Justice,” I’m taking myself to school. Just without the prison. Or the awesome hair.

Next Episode: TDD Part 1

 

Teaser

“The deal of the cards begins the game.”

Act 1 – The Project

I’ve already started a hobby project named EduAgent. The purpose of EduAgent is:

Allow a user to block and allow applications on remote Windows computers.

The application’s architecture is simple enough:

  • An agent, which is a Windows service running on client computers.
  • A web application that has bidirectional communication with agents.
  • A shared library.
  • A database.

That should be enough complexity for me to apply each area I want to improve in.

Act 2 – The Skills

I’ve done some work in most of these. However, it’s been awhile, and every job listing seems to ask for them (regardless of what’s actually in use).

  • TDD (xUnit)
  • SOLID
  • DDD
  • Design Patterns (major)
  • Git
  • Dependency Injection
  • REST/WebAPI
  • MVVM (Angular/Typescript)
  • CSS Preprocessing (SASS)
  • Azure (maybe)
  • Security
  • Scalability (maybe)

Act 3 – The Rules

Each post will be on a subject, and will include:

  1. How much I (think) I know about the subject
  2. The problem to solve
  3. Before and after code samples
  4. Lessons Learned
  5. References

Tag

How much will my experience help me? I’m betting, a lot. After all, I’ve got all those old TV show heroes to help me out.
“The spade is the sword of justice. Its rapier marks the end.”
image
“The spade is the sword of justice. Its rapier marks the end.”

Quickly Enable Mercurial Keyring for BitBucket

These instructions will work generally for pushing to any remote URL, but the example is specifically for BitBucket. The steps specifically require TortoiseHg, which includes Mercurial Keyring. If not using Tortoise, you would need to install Keyring yourself.

Mercurial Keyring

Instructions

Open Tortoise Hg Workbench, Open File > Settings > Global (or repository) Settings > Extensions

Check mercurial_keyring

image

Click OK,  Close and restart Workbench as directed.

image

Open File > Settings > Repository Settings. Click Edit File

image

In the repository’s .hg\hgrc file, add the following setting. Including the username at the start of the URL eliminates the need for an “admin” setting. Note that the password is not stored here.

# Generated by TortoiseHg settings dialog
[paths]
BitBucket=https://bladewolf55@bitbucket.org/bladewolf55/eduagent

Save, close Workbench and reopen.

Push the repository. You’ll be prompted for the password. After a successful push, you won’t be prompted again for the password. It has been locally stored encrypted.

Create an Easily Debuggable Windows Service

In a previous job, I needed to create Windows services. One thing that had tripped me up in the past was being able to debug the service. I figured someone (or ones) had solved this, so I did a bunch of research, consolidated what I found, documented it, and am finally (three years later?) posting it.

With the setup, below, you’ll have a Windows service that:

Runs in debug mode as you’d expect, without having to set unnecessary breakpoints.

Can run as a console app, allowing you to simply double-click the exe. This is useful for many things:

  • Output running messages to the console (the same info you’re logging, most likely).
  • Perform one-off runs for things like integration services that run on a schedule.
  • Easily run elsewhere without having to install as a service.

In addition, my steps include Nice-to-Dos like file and service naming, startup type, etc. These are more for me than you, so that I don’t have to look them up again, so think of them as a bonus.

The example below creates a sample FileImport service. Note that Visual Studio Express doesn’t have a Service project, but you can still create a service. (Sadly, I’m not covering that here, but might do so in a future post.)

Create a new Windows Service project.

image

Change the Assembly output type to Console Application (for debugging).  This, in my opinion, is the big deal. I can now write my program just like I would a console application, which is how I want to think of a service.

This is also a good time to change the assembly information (title, company, etc.).

image

Select Servic1.cs. Rename the Service1.cs file/class name, e.g. to FileImport.cs.

imageimage

image

Select FileImport.cs and view the designer (Shift F7), change ServiceName, e.g. FileImport

image

Rick-click design surface and choose Add Installer

image

Open ProjectInstaller.cs designer, select ServiceInstaller1 and edit:

image

  • Description
  • DisplayName, e.g. “Sample File Import”
  • ServiceName. Should be correct from Service1 designer change, otherwise FileImport
  • StartType, e.g. Automatic

image

If desired, in ProjectInstaller designer, select ServiceProcessInstaller and edit

  • Account = User (set to NetworkService or LocalService if desired.)

image

image

Open FileImport.cs code view, create a public member Start() for debugging.

namespace FileImport
{
    public partial class FileImport : ServiceBase
    {
        public FileImport()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }

        public void Start(string[] args)
        {
            OnStart(args);
        }

    }
}

Change Program.Main() to this (or similar).

namespace FileImport
{
    static class Program
    {
        /// 
        /// The main entry point for the application.
        /// 
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new FileImport()
            };
            // If you don’t want the exe to run as console when double-clicked, then use:
            //   if (System.Diagnostics.Debugger.IsAttached)
            if (Environment.UserInteractive)
            {
                Console.WriteLine("Service running, press  to stop.");
                ((FileImport)ServicesToRun[0]).Start(null);
                Console.ReadLine();
                ((FileImport)ServicesToRun[0]).Stop();
            }
            else
            {
                ServiceBase.Run(ServicesToRun);
            }
        }
    }
}

At this point, you can run the project. It will open a console window and wait.

image

If you install the service, when the service is started it behaves like any other service, i.e. doesn’t display the console window.

Our service isn’t doing anything, so let’s see what the benefit is to creating a service as a console app instead of the default Windows app. We’re not going to do anything fancy like multithreading, I just want to give a flavor. In FileImport.cs, use the following code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace FileImport
{
    public partial class FileImport : ServiceBase
    {
        Timer _timer = new Timer(5000);

        public FileImport()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            _timer.Elapsed += OnTimerElapsed;
            _timer.Start();
        }

        private void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("The time is--or, to be precise, was: " + DateTime.Now.ToString());
        }

        protected override void OnStop()
        {
            Console.WriteLine("Stopping. Here's one method where you'd handle processes that shouldn't be interrupted, gracefully stop them, then end the service. Press  to finish stopping.");
            _timer.Stop();
            _timer.Dispose();
            //etc.
            Console.ReadLine();
        }

        public void Start(string[] args)
        {
            OnStart(args);
        }

    }
}

Run the program and it will output something like this.

image

Now, if you were to install and run this as a service, you still wouldn’t see anything. But you can imagine adding appending text to a file (for example) in the OnTimerElapsed event.

        private void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            string msg = "The time is--or, to be precise, was: " + DateTime.Now.ToString() + "\r\n";
            System.IO.File.AppendAllText(Environment.ExpandEnvironmentVariables("%USERPROFILE%\\TestFileImport.txt"),msg);
            Console.WriteLine(msg);
        }

Of course, I can drop into the debugger as expected.

image

There you go! A simple way to build better Windows services.

References

http://einaregilsson.com/run-windows-service-as-a-console-program/