Here's my five latest blog posts - or you can browse a complete archive of all my posts since 2008.

Faking the HTTP Request URL in ASP.NET MVC

Because I always, always, forget how to do this: here’s how you fake, spoof, whatever you want to call it the HTTP request in ASP.NET Core. Useful if you’ve got controller actions that do things like generate absolute URL links to put into outgoing emails, and you want them to reflect the URL where the code was actually running (so code running on localhost sends mails with links to localhost, code running on test.example.com links to test.example.com, and so on), and you want to write tests for that code because why wouldn’t you write tests?

Looks like this:

protected ControllerContext SimulateControllerContext(string uriString) {
	var uri = new Uri(uriString);
	return new ControllerContext {
		HttpContext = new DefaultHttpContext {
			Request = { Scheme = uri.Scheme, Host = new HostString(uri.Host) }
		}
	};
}

var controller = new WhateverController() {
	ControllerContext = SimulateControllerContext("https://example.com")
}

I’ll normally mix this up with a little extension method, usually while wishing that the people who wrote the very excellent Path.Combine had elbowed their way into the room where they were building System.Uri and Got Involved:

public static class UriExtensions {
	public static Uri Append(this Uri uri, params string[] paths)
		=> new(paths.Aggregate(uri.AbsoluteUri, (current, path)
			=> $"{current.TrimEnd('/')}/{path.TrimStart('/')}"));

	public static Uri GetWebsiteBaseUri(this HttpRequest request)
		=> new($"{request.Scheme}://{request.Host}/");
}

(also, yay blogging with Sveltia means no more messing around with git. Write, publish. done.)

"Faking the HTTP Request URL in ASP.NET MVC" was posted by Dylan Beattie on 15 February 2025 • permalink

Posting with SveltiaCMS from my phone

And here’s the ultimate acid test for low-friction blogging… how quickly can I write and publish a post using my phone? Well, the layouts are a little janky:

Composing a blog post in Chrome on an iPhone using Sveltia CMS

…but it works. Nice. Expect more off-the-cuff blogging.

"Posting with SveltiaCMS from my phone" was posted by Dylan Beattie on 13 February 2025 • permalink

SveltiaCMS, Jekyll and GitHub Pages

I used to blog a lot. Back in the good old days of Windows Live Writer and Blogger, when I could click “New post”, bash out a few hundred words, paste an image or two, and… done.

In 2020 I moved all my stuff from Blogger to Jekyll and GitHub Pages, because I wanted more control over the content on my site. It worked, and I love Jekyll dearly and it’s a fantastic tool, but it kinda killed my blogging because even a two-paragraph post meant git pull, create a new Markdown file, make sure to get the filename right (and filenames are based on dates, so it if you don’t get around to posting it the day you started it you’ve gotta rename stuff), git add, git commit, build… yeah.

So I asked around for whatever’s the closest thing to Windows Live Writer - with the caveats that cntent stays in Markdown, and for now it stays on Github. I own my content. I want it under my control, in a portable format.

Chris Simon pointed me at Decap CMS, which looked really interesting: it’s a JS app that runs from a subfolder inside your static site, connects directly to GitHub, and edits Markdown files right in your repo. Except (a) I managed to crash their live demo editor within fifteen seconds by trying to paste an image into it (I know! Pasting an image! Into a blog post! Totally weirdo edge case that’ll never happen in real life!), and (b) once I’d figured out how to Not Paste Images, I couldn’t get the auth for it running reliably. It uses Netlify to authenticate with GitHub – GitHub can’t do pure JS authentication ‘cos it needs a server to handle the post-authentication callback – and seemed to have some problems using Netlify to authenticate when the site I was trying to edit wasn’t hosted on Netlify.

Then I found Sveltia CMS. It’s the same idea: CMS as a JS app, in a subfolder of a static website, that pushes stuff straight to a GitHub repo - along with a Cloudflare worker app that handles the authentication bit.

So if you’re reading this? It worked: this was posted from Sveltia, which is hooked into dylanbeattie.net/admin, and maybe means bashing out those quick 2-paragraph blog posts might just be as easy as it was in the days of Live Writer.

"SveltiaCMS, Jekyll and GitHub Pages" was posted by Dylan Beattie on 13 February 2025 • permalink

Windows Defender detects Trojan:Script/Wacatac.B!ml in a zipped .NET 9 AOT binary

Earlier today, somebody alerted me that Rockstar binary releases for Windows were being blocked by Windows Defender… and sure enough, since I switched the build system from .NET 8 to .NET 9, the Windows ZIP file releases on the releases page are being incorrectly identified as being infected with Trojan:Script/Wacatac.B!ml malware.

It’s not just Rockstar, though. It’s any .NET 9 binary compiled with AOT enabled and then compressed in a ZIP file. Try it. First, create a new .NET 9 console app:

dotnet new console -o HelloWorld

Then edit the .csproj file and add StripSymbols and PublishAot directives:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net9.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>
    <!-- ADD THIS PropertyGroup to create native binary EXE builds -->
    <PropertyGroup Condition="'$(Configuration)'=='Release'">
        <DebugSymbols>False</DebugSymbols>
        <DebugType>None</DebugType>
        <PublishAot>true</PublishAot>
        <StripSymbols>true</StripSymbols>
    </PropertyGroup>
</Project>

Now publish a binary release:

dotnet publish -c Release -o published

Look in /published and you’ll see a single binary HelloWorld.exe

Create a ZIP file containing that EXE - in Windows Explorer, right-click, Send to > Compressed (zipped) folder:

creating a ZIP file using Windows Explorer

Right-click the ZIP file, Scan with Microsoft Defender…

Microsoft Defender Trojan result

For a second opinion, upload the ZIP file to VirusTotal.com, and you’ll probably see that Microsoft Defender thinks it’s infected with a trojan. I’ve had multiple hits reporting Trojan:Script/Wacatac.B!ml and one reporting Trojan:Win32/AgentTesla!ml

"Windows Defender detects Trojan:Script/Wacatac.B!ml in a zipped .NET 9 AOT binary" was posted by Dylan Beattie on 09 December 2024 • permalink

Running Corel Linux on QEMU

In my latest YouTube video, I talk about Corel Linux, which I think is one of the most interesting “what if?” scenarios in the history of mainstream computing, and show some clips of Corel Linux actually running. It’s not easy getting a 25-year-old Linux distro to boot on a modern PC - but here’s how I did it.

Install QEMU

VirtualBox, HyperV et al won’t work here - Corel Linux is just too old to support most of the virtual hardware they expose to their guest operating systems. Instead, we’re going to use QEMU.

Download it from https://www.qemu.org/, install it, get it running. Check it works by running qemu-system-i386 at a terminal window:

> qemu-system-i386 --version
QEMU emulator version 9.0.0 (v9.0.0-12054-g923cf646f4)
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers
> 

Create a virtual disk

This will create a 2Gb virtual disk file called corel_linux_hd.img:

qemu-img create corel_linux_hd.img 2G

Download Corel Linux

I used the ISO image of Corel Linux 1.2 deluxe from https://archive.org/details/corel_linux_1.2

While you’re there, you might also want to download CorelDRAW and WordPerfect Office https://archive.org/details/CorelForLinux/CorelDRAW%209%20Linux/

Run the installer

qemu-system-i386 -hda corel_linux_hd.img -cdrom corel_linux_1.2.iso -m 256 -vga cirrus

You should get this:

image-20240524131917442

and then this…

image-20240524131927733

and then this:

image-20240524132009470

Yeah. This is where it gets interesting: the Cirrus VGA driver provided by QEMU displays garbled text until we get into the OS and hack it, but we can’t do that until we’ve got it installed, so we’ll need to walk through the installation without being able to read anything.

You probably also don’t have any mouse support, so use Tab to move forwards, Ctrl-Tab to move backwards, and the Spacebar to click:

image-20240524132852073

Don’t change anything here - “Install Standard Desktop” is already selected so just press Enter:

image-20240524132431754

The next few screens, accept all the defaults - tab to Next> if it’s not already focused, press Enter:

image-20240524132552504

image-20240524132659002

and finally, Install:

image-20240524132725616

If you get to here, you’re on the right track:

image-20240524133012196

Once it’s installed, let it reboot, then at the loading screen select Linux - Text Mode

image-20240524133627515

It’ll happily chunter away for a few screens worth of messages, and then you’ll get a login prompt.

Log in a root with a blank password. (Don’t ask. It was the early 2000s. Things were different then.)

Now we need to configure X11 so that it won’t try to use various accelerated hardware features that don’t work in QEMU.

This bit comes from Ethan Gates’ Corel Linux in QEMU post on forums.eeasi.cloud – thank you Ethan! – and that post was in turn inspired by Hayden Barnes’ post The one in which I kind of get Corel Linux 1.2 to work 21 years later - thank you Hayden!

Use vim to edit /etc/X11/XF86config. Find the section called “Device”, add three lines:

Option "no_bitblt"
Option "noaccel"
Option "sw_cursor"

image-20240524140407311

Save the file, reboot (shutdown -r now), and select Corel Linux from the boot menu:

image-20240524140634742

Networking support

Networking support in QEMU is powerful, flexible, and incredibly complicated.

Here’s how I made it work. Disclaimer: I don’t 100% understand exactly what all this does… I tried just about every combination I could think of until I found something that worked.

First, you’ll need to install a TAP network driver. This adds another network interface to Windows, which emulates a physical network card. Apparently.

I installed mine using chocolatety:

choco install tapwindows

Then, in Windows network settings:

  1. Rename the new TAP connection to TapWindows
  2. Right-click your main network connection (ethernet, wifi - whatever connects your Windows machine to the internet)
  3. Properties > Sharing > Allow other network users to connect…
  4. Choose your TapWindows connection as the “Home networking connection”

You’ll get a popup about your LAN adapter. The wording here is misleading - it’s not your LAN adapter, it’s whichever adapter you selected as you” Home networking connection”:

If you remember using Internet Connection Sharing with a dial-up modem… this is the same tech, only we’re pretending that QEMU is our house network, TapWindows is the network card connecting our PC to the rest of the house, and “Ethernet” is the dial-up modem that connects to the internet.

image-20240524141328089

Now, run QEMU using this command line:

I’m using Powershell so a backtick ` is a line continuation character.

qemu-system-i386 -hda corel_linux_hd.img `
-m 256 -vga cirrus -audiodev driver=dsound,id=pa1 -device sb16,audiodev=pa1 `
-netdev tap,id=mynet0,ifname=TapWindows `
-device pcnet,netdev=mynet0

That’s telling QEMU “create a network connection using TAP, call it mynet0, and connect it to the TapWindows interface on the host PC”, and then on the next line “then create a virtual device using the pcnet and connect it to the mynet0 network”.

For me, this worked 80% of the time. When it didn’t work, it’s because something meant the Linux guest couldn’t get an IP address from Internet Connection Sharing’s DHCP server. Manually setting the guest IP to 192.168.137.2, subnet 255.255.255.0, gateway 192.168.137.1 usually fixed this.

That got me to the point where I could boot Linux, open Netscape, point it at http://info.cern.ch/, and browse the world’s first website.

image-20240524142321136

Stuff I Couldn’t Figure Out

I couldn’t get audio working. QEMU audio works fine - I created a Windows 2000 guest just to test this - and I tried both the ac97 and sb16 virtual audio devices in QEMU, but no luck yet.

I also couldn’t figure out how to change the CD-ROM. When you’re running QEMU, Ctrl-Alt-F2 drops you into an emulation console where you can use info block to see which devices/images are connected, and change ide1-cd0 <filename.iso> to change the virtual disk:

image-20240524142715085

But… then I couldn’t work out how to get Corel Linux to mount the disk image, so to install WordPerfect, CorelDRAW!, etc. I had to shut down the VM and then boot it specifying the -cdrom command line switch:

qemu-system-i386 -hda corel_linux_hd.img `
-m 256 -vga cirrus -audiodev driver=dsound,id=pa1 -device ac97,audiodev=pa1 `
-netdev tap,id=mynet0,ifname=TapWindows `
-device pcnet,netdev=mynet0 `
-cdrom .\wordperfect_office_2000_deluxe_cd_1.iso

Ah, the nostalgia.

"Running Corel Linux on QEMU" was posted by Dylan Beattie on 27 May 2024 • permalink