Format prices correctly in #MSSQL using currencies in #ISO4127 format.

If you want to specify a price including a currency, you can always write EUR 1,234 or USD 1,234, but it’s more concise to write $1,234 or €1,234, and users expect that format. You can always handle this at application layer, but here’s how to do it at Database layer.

Here, I’ve created a table of the currencies I needed, – it’s not complete, and I hope that someone can post a link to a complete table.

create table CurrencyLocales
 id int identity(1,1),
 currency varchar(3),
 locale varchar(5)

insert into CurrencyLocales (currency,locale) values ('AUD','en-AU')
insert into CurrencyLocales (currency,locale) values ('BRL','pt-BR')
insert into CurrencyLocales (currency,locale) values ('CAD','en-CA')
insert into CurrencyLocales (currency,locale) values ('CZK','cs-CZ')
insert into CurrencyLocales (currency,locale) values ('DKK','da-DK')
insert into CurrencyLocales (currency,locale) values ('EUR','en-IE')
insert into CurrencyLocales (currency,locale) values ('GBP','en-GB')
insert into CurrencyLocales (currency,locale) values ('HUF','hu-HU')
insert into CurrencyLocales (currency,locale) values ('MXN','es-MX')
insert into CurrencyLocales (currency,locale) values ('MYR','en-MY')
insert into CurrencyLocales (currency,locale) values ('NOK','nb-NO')
insert into CurrencyLocales (currency,locale) values ('NZD','en-NZ')
insert into CurrencyLocales (currency,locale) values ('RUB','ru-RU')
insert into CurrencyLocales (currency,locale) values ('SEK','sv-SE')
insert into CurrencyLocales (currency,locale) values ('SGD','en-SG')
insert into CurrencyLocales (currency,locale) values ('USD','en-US')

create index idxCurrency on CurrencyLocales(currency)

-- example
select *, FORMAT(1234, 'C', locale) as formattedPrice  from CurrencyLocales
4CZKcs-CZ1 234,00 Kč
5DKKda-DK1.234,00 kr.
8HUFhu-HU1 234,00 Ft
11NOKnb-NOkr 1 234,00
13RUBru-RU1 234,00 ₽
14SEKsv-SE1.234,00 kr
Categories: Uncategorized

Runing Hosted CapMonster Locally in C#

If you use CapMonster Cloud, then you may find that the per-request pricing does add up over high volumes, if you have spare computing power, then you can run CapMonster Hosted on your own server., or if you are running a batch-process on your own local PC, then this could be a big cost saver.

It’s not free, since you need to buy a license from CapMonster for the base sofware, I used the Lite version for $37, available here: – Then you also need the sitekey add on, which is $10 per month, available here; – But this now allows you solve 100,000 captchas per day, instead of the $0.6 * 100 = $60 per day cost of the equivalent on CapMonster Cloud at the same volume.

So, After downloading the required software, it will start a server on (port 80) by default that exposes the same API as – but obviously with a differnt endpoint (local vs remote).

The problem is that if you use the NuGet Package here; then you will notice that this does not offer the API endpoint to be configurable.

What I did was clone the repo from and then set then change the ApiBaseUrl specified in Endpoints.cs – or make it a public property, and modify it in your client code.

So, this could be a good cost saving tip, for heavy users of CapMonster.

Categories: Uncategorized

Using AWS CloudFront as a proxy

Typically, CloudFront is used to serve your own website, so that it can leverage AWS’s CDN, and various edge servers in many countries, so that data is not transferred accross the world with every HTTP request.

But, you can also use it as a proxy, by pointing CloudFront at someone else’s website. This means that when you visit the CloudFront URL, the request to the third party website will come from AWS rather than from your local machine.

It’s not as anonymous as a good proxy, since there are various headers that would undoubtedly expose you, based on the request made to HTTPBIN below;

  "args": {}, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "en-US,en;q=0.9", 
    "Dnt": "1", 
    "Host": "", 
    "Sec-Ch-Ua": "\"Google Chrome\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\"", 
    "Sec-Ch-Ua-Mobile": "?0", 
    "Sec-Ch-Ua-Platform": "\"Windows\"", 
    "Sec-Fetch-Dest": "document", 
    "Sec-Fetch-Mode": "navigate", 
    "Sec-Fetch-Site": "none", 
    "Sec-Fetch-User": "?1", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ Safari/537.36", 
    "X-Amzn-Trace-Id": "Root=1-636908d7-xxxxxxxx"
  "origin": "", 
  "url": ""

Here X-Amzn-Trace-Id could probably be tied to you.

Categories: Uncategorized

Extract Assemblies.blob / Assemblies.manifest from Xamarin APK

When unzipping a Xamarin-built APK, you may notice that in the \assemblies folder there are no longer a list of DLLS, but two files, Assemblies.blob and Assemblies.manifest, where the manifest contains a list of filenames, and their associated Hashes, and the blob file contains the compressed data. All this gives the APK a smaller footprint on device. (Even though the APK is zipped anyway, but I presume that someone has done the maths!)

To uncompress the Assemblies.blob file, you’ll need python installed on your machine – and clone the repo from

With this script, you can decompress the assemblies.blob / manifest using the syntax;

usage: [-h] [–blob BLOB] [–manifest MANIFEST]

After this, you have a load of Lz4 files. You pick the file you’re interested in, and then git clone the repo

Then using this script, you then run the command;

python [filename].lz4

Which gives you the DLL that you can import into dotnetpeek or ILSpy.

Categories: Uncategorized

Verify a #SouthAfrican #VAT number via an API

If your company deals with South African companies, and you need to verify the VAT number provided by them, to ensure it matches the same company, then here is an API that can do this automatically for you.

Firstly, register with RapidAPI, and go to this page once registered, you will get a RapidAPI key, which you will need to run the below code example;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;

var client = new RestClient("");

var request = new RestRequest
    Method = Method.Post
request.AddHeader("X-RapidAPI-Key", "**********");
request.AddHeader("X-RapidAPI-Host", "");
request.AddHeader("Content-Type", "application/json");
var body = JsonConvert.SerializeObject(new { vat = "4910202524" });
request.AddParameter("application/json", body, ParameterType.RequestBody);
var response = client.Execute(request);
var company = JObject.Parse(response.Content ?? "{}");
var resultTable = company["Table"] ?? new JObject();
var tradingName = resultTable["TRADING NAME"] + "";
var area = resultTable["AREA DESC"] + "";
Console.WriteLine($"{tradingName} is registered in {area}");

The code above is a console app for .NET Core in C#, and will require the following NuGet packages, which can be installed as follows;

Install-Package RestSharp 
Install-Package Newtonsoft.JSON
Categories: Uncategorized

#TLS client authentication sends target host as plaintext

TLDR; Github repo is here;

First and foremost, I am not highlighting a security flaw in TLS, I’m just pointing out a parameter that should never be “hijacked” for purposes of client identification, since it is sent in plaintext over an TLS (aka SSL) connection, and thus easily read by anyone who may be intercepting the connection.

This example is in C#, and at TCP level, a HTTPS connection needs to call “AuthenticateAsClient” before it can exchange content with the server. This step is where the client can provide to the server an X509 client certificate, to prove who the client is. Often the client does not provide an X509 certificate, and the server must use something else to authenticate the client.

The parameters to AuthenticateAsClient as the TargetHost, and an optional list of certificates. The TargetHost parameter is meant to indicate to the server which certificate to use, but it should never be used to pass any authentication credentials, like a user id – because, as the screenshot shows, the target host is passed in plaintext, and can be intercepted.

Here is my sample client;

client.Connect("", 500);
var s = client.GetStream();
var bMessage = Encoding.UTF8.GetBytes("HELLO WORLD");
var ssl = new SslStream(s);
ssl.AuthenticateAsClient("SOME SECRET INFORMATION", null, SslProtocols.Tls12, false);
ssl.Write(bMessage, 0, bMessage.Length);

Here, I am connecting to a local server on port 500, then using SSL (TLS) to connect to it. I authenticate as a client, passing something I shouldn’t in the Target Host.

On a seperate thread, I am listening for incomming data; and outputting it to screen, and it’s really obvious how the TargetHost appears in plain text. Note that the incomming stream is not decrypting the SSL, it is just printing it raw to the screen.

So, Once again, this isn’t anything to get worried about. By default, Http client libraries won’t expose this property, you need to be down at TCP level to change it, so you’re not likely to “accidentally” leak data this way. Generally if you are writing TCP level code, you’re heading in the wrong direction – but if you do think that this property could be a short-cut to client authentication – don’t do it!

Categories: Uncategorized

Handling the effect of HttpContext null in a separate thread in ASP.NET

If you have an ASP.NET page that needs to respond quickly, but perhaps has a slow background task to do, that would be ideal to perform in a background thread. However, suddently you find that HttpContext is null, so you can no longer access server features in the background thread.

The case could be a webhook, where a third party calls your server, and has a timeout of a few seconds before they kill the connection to your server. but you have some large processing to do, that won’t be done in time, or potentially won’t be done in time.

Otherwise, it could be just a performance optimization, you have a few things you need the user to see, but there are other tasks that can happen in the background, that the user doesn’t need to wait for.

Here’s the problematic code:

    protected void Page_Load(object sender, EventArgs e)
        var asyncJob = new Thread(() => HandleJob());

    private static void HandleJob()

But this code fails, because HttpContext.Current will be null in the context of the thread. It also will fail silently, since the page will load fine.

The Fix? – move any variables that you might need to access outside of the Thread

    protected void Page_Load(object sender, EventArgs e)
        var jobId = Request.QueryString["jobId"];
        var asyncJob = new Thread(() => HandleJob(jobId));

    private static void HandleJob(string JobId)

Categories: Uncategorized

Get a user’s profile picture from their Email address in #PHP using AvatarAPI

The new Avatar API “v2” has code examples for cUrl (Command Line), Ruby, Python and Node, but PHP was overlooked, so here is a code example to help users get their PHP code up and running;

$email = "";

$json = '{ 
    "username" : "your-username-here",
    "password" : "yout-password-here",
    "email" : "$email"

$json = eval('return "' . addslashes($json) . '";');

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => '',

$response = curl_exec($curl);

if (curl_errno($curl)) {
	// Optional (but recommended) error handling.
    $error_msg = curl_error($curl);
	echo $error_msg;

echo $response;



Note that you can remove the line CURLOPT_SSL_VERIFYPEER – I just had a local issue with SSL certs.

The output will look something like this;

  "Name": "",
  "Image": "",
  "Valid": true,
  "City": "",
  "Country": "",
  "IsDefault": true
Categories: Uncategorized

Car Registration #API available in #Malta

Malta has a population of just over half a million inhabitants, and with the number of cars on the road at 415,000 as of March 2022 (Source CEIC data), meaning that most households have multiple cars, which is not overly surprising as as rather wealthy island nation. Today, we’ve launched our Maltese website that provides an API that allows users determine the make / model and VIN of vehicles registered in Malta.

Car registration plates in Malta use the /CheckMalta endpoint and return the following

● Make / Model
● Year
● Engine Size
● Engine Number
● Power
● Fuel
● Body Style
● Tonnage
● Number of Seats
● Representative image

Sample Registration Number:

Sample Json:

  "Description": "PEUGEOT 307",
  "RegistrationYear": "2004",
  "CarMake": {
    "CurrentTextValue": "PEUGEOT"
  "CarModel": {
    "CurrentTextValue": "307"
  "MakeDescription": {
    "CurrentTextValue": "PEUGEOT"
  "ModelDescription": {
    "CurrentTextValue": "307"
  "VehicleIdentificationNumber": "VF33HNFUE4S024189",
  "EngineSize": "1587",
  "Power": "109",
  "FuelType": "PETROL",
  "Body": "HATCHBACK",
  "NumberOfSeats": "4",
  "EngineNumber": "10FX4X2148207",
  "Tonnage": "2",
  "ImageUrl": ""
Categories: Uncategorized

Serializing a #CookieContainer in C#

If you are using C# to interact with websites, then a common pattern, is that you may log in with one request, and then perform an action with the logged in user with a second request. When you wish to repeat the action, then you may end up logging in again, even though you could have potentially recycled the session from the first log in, which saves both time, and bandwidth.

In order to do so, you will need to somehow store the cookies to disk, and then reload them for the second request.

Using XmlSerialiser in this case won’t work, since the Cookie object contains a Uri object, which is not serialisable, also JSON serialiser (Newtonsoft.JSON) is problematic, since it’s not precisely a 1:1 representation of the CookieContainer (I’m not exactly sure what it misses, please feel free to add comments below with your experience).

I found, that although marked as “obsolete” by Microsoft, the BinaryFormatter provides a faithful representation of the CookieCollection.

This is some code I wote to serialize a Cookie Collection

private static void StoreCookieCollection(IEnumerable cookies, string cookieFile)
	cookieFile = Path.GetTempPath() + cookieFile;
	if (File.Exists(cookieFile)) File.Delete(cookieFile);
	var formatter = new BinaryFormatter();
	var fs = new FileStream(cookieFile, FileMode.Create);

And the reverse for de-serializing it:

private static CookieCollection LoadCookieCollection(string cookieFile)
	cookieFile = Path.GetTempPath() + cookieFile;
	if (!File.Exists(cookieFile)) return null;
	var age = File.GetLastWriteTime(cookieFile);
	if (DateTime.Now - age > TimeSpan.FromDays(1)) return null; // a day old
	var formatter = new BinaryFormatter();
	CookieCollection cc;
	using (Stream reader = new FileStream(cookieFile, FileMode.Open))
		cc = (CookieCollection)formatter.Deserialize(reader);
	return cc;

Bon apetit!

Categories: Uncategorized
%d bloggers like this: