Remember, C# does not have an exponent operator

This is a cautionary tale for developers who switch between programming languages often.

Whilst reviewing some logs, I noticed that durations of pauses between API requests were incorrect. They were expected to double on every subsequent attempt, starting from a fixed base interval; for example, 5 seconds, 10 seconds, 20 seconds, 40 seconds, and so on. Instead, they were changing in an odd manner: 15 seconds, 30 seconds, 60 seconds, 0 seconds, and so on.

A colleague and I reviewed the following C# code but did not spot anything wrong.

int tmp = RetryIntervalInMs * (2 ^ retryCounter);

These calculated durations kept puzzling me throughout the day as they were mathematically impossible given the programmed exponential growth.

Later that night, when I did some embedded development in C, I suddenly realised what was wrong.

I had used the ^ operator in C#, intending it to mean ‘raised to the power of’ as in some other language — which I cannot even remember now — whereas it was actually an XOR operator. Even two of us reviewing the code together did not spot that mistake.

The fix was to use the Math.Pow(int, int) method, as follows.

int tmp = RetryIntervalInMs * (int)Math.Pow(2, retryCounter);

Avoiding time drift in virtual machines

If you use a virtual machine, you might have noticed that its system time starts to lag after it has been in the ‘powered on’ state for some time. To address this, it is useful to run an NTP (Network Time Prococol) client within the VM to have its time synchronised regularly.

On Windows, this is enabled by default and uses time.windows.com.

On a Debian-based Linux distribution, you can install NTP with apt install ntp and start it with sudo systemctl start ntp.

Caveat with AddInitialRequestCultureProvider() in ASP.NET Core

AddInitialRequestCultureProvider() in ASP.NET Core localisation seems to have an undefined behaviour when it is used in both services and application builder configurations to add a custom RequestCultureProvider.

If you want to use a custom RequestCultureProvider to customise how the applicable culture is determined for an incoming HTTP request (for example, by looking up the chosen culture of a user in the database), you must configure the provider in the services collection as described in the section ‘Use a custom provider’.

You must also call IApplicationBuilder.UseRequestLocalization(), but you must not pass any argument to the method. If a RequestLocalizationOptions argument is specified here, it supersedes what is configured in the services collection, and your custom RequestCultureProvider does not work.

Typically, you configure the middleware in the application builder before the services. But in order to emphasise the significance of setting the localisation options only in the services configuration, I have reversed this order on purpose.

How can you minimize the impact of the persistence layer on your domain models?

This is a blog response to the question ‘How can you minimize the impact of the persistence layer on your domain models?’ posted on reddit /r/dotnet, showing how I would have implemented the solution in the purest form of OOP that is possible with C#.

(Note: The implementation of the factory and persistence classes is simplified for demonstration purposes.)

So here is the code. It is tested with .NET 5 on Windows 10.

using System;
using System.Data;
using System.Diagnostics;

namespace Example.Domain
{
    // Let's pretend this namespace is in a separate assembly so that
    // the 'internal' scope modifier applies

    public interface IAccount
    {
	string Username { get; }

	bool IsEnabled { get; }

	void Disable();
    }

    public interface ISavedAccount : IAccount
    {
	int Id { get; }
	
	void Enable();
    }

    // Not accessible from outside assembly
    internal abstract class AccountBase : IAccount
    {
	public string Username { get; protected set; }

	public bool IsEnabled { get; protected set; }

	internal AccountBase(string username)
	{
	    Username = username;
	}

	public void Disable()
	{
	    IsEnabled = false;
	}
    }

    // Not accessible from outside assembly
    internal class MyAccount : AccountBase
    {
	internal MyAccount(string username)
	    : base(username)
	{
	}
    }

    // Not accessible from outside assembly
    internal class MySavedAccount : AccountBase, ISavedAccount
    {
	public int Id { get; private set; }

	internal MySavedAccount(int id, string username, bool isEnabled)
	    : base(username)
	{
	    Id = id;
	    if (isEnabled) 
	    {
		Enable();
	    }
	}

	public void Enable()
	{
	    IsEnabled = true;
	}
    }

    public static class AccountFactory
    {
	public static IAccount Create(string username)
	{
	    return new MyAccount(username);
	}

	public static ISavedAccount Create(int id, string username, bool isEnabled)
	{
	    return new MySavedAccount(id, username, isEnabled);
	}
    }
}

namespace Example.Persistence
{
    using Example.Domain;

    public static class AccountStorage
    {
	static readonly DataTable dt;

	static AccountStorage()
	{
	    dt = new DataTable();
	    dt.Columns.Add("id", typeof(int));
	    dt.Columns.Add("username", typeof(string));
	    dt.Columns.Add("enabled", typeof(bool));
	}

	public static DataRow AddAccountRow(ref IAccount account)
	{
	    var dr = dt.NewRow();
	    dr["id"] = dt.Rows.Count+1;
	    dr["username"] = account.Username;
	    dr["enabled"] = account.IsEnabled;
	    dt.Rows.Add(dr);

	    // This variable does not point to a valid account after it has been saved
	    account = null;

	    return dr;
	}

	public static DataRow UpdateAccountRow(ISavedAccount account)
	{
	    var dr = FindAccountRow(account.Id);
	    dr["username"] = account.Username;
	    dr["enabled"] = account.IsEnabled;
	    return dr;
	}

	public static DataRow FindAccountRow(int id)
	{
	    for (var i=0; i<dt.Rows.Count; ++i)
	    {
		DataRow dr = dt.Rows[i];
		if (((int)dr["id"]) == id)
		{
		    return dr;
		}
	    }
	    return null;
	}
    }
}

namespace Example.Client
{
    // Let's pretend this namespace is in a separate assembly so that it
    // doesn't see the 'internal' definitions from the Example.Domain
    // namespace

    using Example.Domain;
    using Example.Persistence;

    class Program
    {
        static void Main(string[] args)
        {
	    var account = AccountFactory.Create("joebloggs");

	    // FAIL! A new account does not have an id
	    // Debug.Assert(account.Id > 0);

	    // FAIL! A new account cannot be enabled
	    // account.Enable();

	    var newrow = AccountStorage.AddAccountRow(ref account);

            Debug.Assert(account == null, "The account object is no longer valid");

	    Debug.Assert(((int)newrow["id"]) > 0, "The 'id' value is set");
	    Debug.Assert("joebloggs".Equals(newrow["username"]), "The 'username' value is set");
	    Debug.Assert(! (bool)newrow["enabled"], "The 'enabled' value is not set");

	    var savedaccount = AccountFactory.Create((int)newrow["id"], (string)newrow["username"], (bool)newrow["enabled"]);
	    savedaccount.Enable();
	    Debug.Assert(savedaccount.IsEnabled, "The account is enabled");

	    var unused = AccountStorage.UpdateAccountRow(savedaccount);

	    var loadedrow = AccountStorage.FindAccountRow(savedaccount.Id);
	    var loaded = AccountFactory.Create((int)loadedrow["id"], (string)loadedrow["username"], (bool)loadedrow["enabled"]);

	    Debug.Assert(loaded.Id > 0, "An id is assigned");
	    Debug.Assert("joebloggs".Equals(loaded.Username), "The username is set correctly");
	    Debug.Assert(loaded.IsEnabled, "The account is enabled");
        }
    }
}

The line below might be questionable because we are effectively passing ownership of the account object to the persistence layer, but we could assume that there is a contract that formalises this.

	    // This variable does not point to a valid account after it has been saved
	    account = null;

.vimrc

packadd! matchit
filetype plugin indent on
syntax on
set directory=~\vimfiles\swap undofile undodir=~\vimfiles\undo ruler visualbell incsearch ignorecase hlsearch smartcase showmatch autoindent backspace=2 wildmenu
set grepprg=rg.exe\ --vimgrep\ -i
set grepformat=%f:%l:%c:%m
nnoremap <leader>b <Esc>:ls<Cr>:b *
nnoremap <leader>e <Esc>:e *
nnoremap <leader>s <Esc>:split +b *
nnoremap <leader>E <Esc>:e %:h\*
nnoremap <leader>S <Esc>:s %:h\*
nnoremap <leader>w <Esc>:bw
nnoremap <leader>y "+y
vnoremap <leader>y "+y
nnoremap <leader>Y "+Y
nnoremap <leader>p "+p
vnoremap <leader>p "+p
nnoremap <leader>P "+P
nnoremap <BS>      <Esc>:let @/=""<Cr>
nnoremap <C-s>     <Esc>:up<Cr>
inoremap <C-s>     <Esc>:up<Cr>
nnoremap <A-Down>  <Esc>:cnext<Cr>
nnoremap <A-Up>    <Esc>:cprevious<Cr>

rg.exe is part of ripgrep.

Disabling Bluetooth auto-suspend with module options

In my previous post I showed how to restart Bluetooth on Debian Linux. Here I explain how to disable Bluetooth auto-suspend by using a kernel module option.

Kernel modules can be passed parameters that affect how they work. The parameters accepted by a module can be identified with the command modinfo. In the example below modinfo btusb displays the parameters for the Bluetooth module.

$ sudo modinfo btusb
...
parm:           disable_scofix:Disable fixup of wrong SCO buffer size (bool)
parm:           force_scofix:Force fixup of wrong SCO buffers size (bool)
parm:           enable_autosuspend:Enable USB autosuspend by default (bool)
parm:           reset:Send HCI reset command on initialization (bool)

The option enable_autosuspend is the one that interests us. It can be set in a configuration file in directory /etc/modprobe.d/.

options btusb enable_autosuspend=0

Here I have file btusb_autosuspend-disable.conf to disable Bluetooth auto-suspend.

Restarting Bluetooth on Debian Linux

On my laptop I use a Bluetooth keyboard and a Bluetooth mouse. Occasionally the Bluetooth adapter in the laptop shuts off completely, which means that it is not even possible to restart the Bluetooth service with sudo systemctl restart bluetooth.service.

My troubleshooting points to powersaving as the cause of this, but the TLP setting that is supposed to prevent autosuspend on Bluetooth devices does not seem to prevent this sudden death of the Bluetooth connection. As a temporary workaround I am using the commands below to restart Bluetooth from the shell.

$ sudo rmmod btusb && sudo modprobe btusb && sudo systemctl restart bluetooth.service

This solution works on Debian testing bullseye with kernel x86_64 Linux 5.5.0-2-amd64.