Friday, October 22, 2021

Service decomposition and service design

Finding the boundaries of your system and decompose it into multiple services sounds easy, but it certainly isn’t.

If you are interested in this topic, check out the blog series by Vadim Samokhin:

Remark: After writing this post, I noticed that Vadim created a blog post linking to the series above and included also some other related posts.

Thursday, October 21, 2021

Azure AKS–Save some money using spot node pools

One of the ways you can save some money using Azure is by using spot node pools for your Azure Kubernetes Service cluster.

What’s a spot node pool?

Using a spot node pool allows you to take advantage of unused Azure capacity at a significant cost savings. At any point in time when Azure needs the capacity back, the Azure infrastructure will evict spot nodes. Therefore, Spot nodes are great for workloads that can handle interruptions like batch processing jobs, dev/test environments, large compute workloads, and more.

Remark: A spot node pool can't be the cluster's default node pool. A spot node pool can only be used for a secondary pool.

Pricing for a spot node pool

Pricing for spot instances is variable, based on region and SKU. For more information, see pricing for Linux and Windows. You do have the option to set a max price. In case the price is exceeded the spot node is evicted from your cluster.

Schedule a deployment to use the spot node pool

A spot node pool has the label and the taint We use this information to add a toleration in our deployment.yaml:

In case you have multiple spot node pools, you can use a nodeselector to select a specific pool:

More information

Winget–A package manager for Windows

I’ve been using Chocolatey for a long time as an easy way to get my Windows machine configured with all the software I need. With the release of version 1.1 of the Windows Package Manager(WinGet) I thought it was a good time to give it a try.


Chances are high that WinGet is already available on your machine. Open a terminal and type winget. If it is available you should see something like this:

If not, the Windows Package Manager is distributed with the App Installer from the Microsoft Store. You can also download and install the Windows Package Manager from GitHub, or just directly install the latest available released version.

Searching a package

The list of available packages is quite large(more than 2,600 packages in the Windows Package Manager app repository). Just run winget search <SomePackage> to see if the package you are looking for has available there.

For example let’s search for my favorite git client GitKraken:

PS C:\Users\bawu> winget search gitkraken
Naam      Id                Versie Bron
GitKraken Axosoft.GitKraken 8.1.0  winget

For packages inside the Microsoft store you don’t get  a readable id but a hash value instead:

PS C:\Users\bawu> winget search git
Name                                  Id                                         Version                    Source
Learn Pro GIT                         9NHM1C45G44B                               Unknown                    msstore
My Git                                9NLVK2SL2SSP                               Unknown                    msstore
GitCup                                9NBLGGH4XFHP                               Unknown                    msstore
GitVine                               9P3BLC2GW78W                               Unknown                    msstore
GitFiend                              9NMNKLTSZNKC                               Unknown                    msstore
GitIt                                 9NBLGGH40HV7                               Unknown                    msstore
GitHub Zen                            9NBLGGH4RTK3                               Unknown                    msstore
GitLooker                             9PK6TGX9T87P                               Unknown                    msstore
Bhagavad Gita                         9WZDNCRFJCV5                               Unknown                    msstore
Git                                   Git.Git                                    2.33.1                     winget
GitNote                               zhaopengme.gitnote                         3.1.0         Tag: git     winget
Agent Git                             Xidicone.AgentGit                          1.85          Tag: Git     winget
TortoiseSVN                           TortoiseSVN.TortoiseSVN                    1.14.29085    Tag: git     winget
TortoiseGit                           TortoiseGit.TortoiseGit                Tag: git     winget

Installing a package

After you have found the package you want, installing it is as easy as invoking the following command:

winget install --id <SomePackage>

Of course the real fun starts when you create a script that contains all the packages you need for you day-to-day work. Here is the script I’m using:

Tuesday, October 19, 2021

ASP.NET Core–Running Swagger behind a reverse proxy

Today I helped out a colleague who was struggling with the following use case:

We have an ASP.NET Core Web API with OpenAPI(Swagger) integration enabled. This ASP.NET Core Web API was running behind a reverse proxy(Yarp in case you want to know) and isn’t directly accessibel.

To explain the problem he had, let’s start from the following situation:

When browsing to the Swagger endpoint on https://localhost/proxy/swagger, we got the following:

Do you notice the application url in the address bar vs the url in the Servers dropdown?

If we try to invoke a specific endpoint through the Swagger UI, Swagger tries to do the call directly to http://internalname:5000 which results in 404 error as the service is not available directly on this address.

It seems that Swagger doesn’t respect the Forwarded headers as provided through Yarp.

We fixed it by explicitly reading out the X-Forwarded-Host value and using it to fill up the servers dropdown:

Monday, October 18, 2021

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException–The system cannot find the file specified

After deploying an application to production, it failed with the following error message:

The system cannot find the file specified

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore (System.Security.Cryptography.X509Certificates, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile (System.Security.Cryptography.X509Certificates, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor (System.Security.Cryptography.X509Certificates, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System.Security.Cryptography.X509Certificates, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)

Let’s take a look at the code that caused this issue:

Not much I could do wrong with this code. It tries to load a PFX file from disk and open it using the specified password.

I checked if the file was there and that was indeed the case. So we have to search for the root cause somewhere else.

I took a look at the Application Pool settings and noticed that the Load User Profile setting was set to False.

Aha! After changing this back to True the error got away…

Friday, October 15, 2021

DaprCon is coming on October 19th-20th 2021

What is Dapr?

Dapr helps developers build event-driven, resilient distributed applications. Whether on-premises, in the cloud, or on an edge device, Dapr helps you tackle the challenges that come with building microservices and keeps your code platform agnostic.

The Dapr ecosystem keeps growing and now they’ll have their first virtual conference ‘DaprCon’ next week. DaprCon will include a variety of content including a keynote, technical sessions, panel discussions and real-world experiences of adopters building with Dapr

DaprCon is a fully virtual event that will be streamed on YouTube and attendance is free! To watch the live events just follow these two links:

More information:

Thursday, October 14, 2021

MassTransit–Message versioning

MassTransit dedicated a whole documentation page to message versioning but it still wasn’t completely clear to me how it worked.

Let’s use this blog post to see what’s going on…

Publishing messages

Let’s first focus on the sending side.

Publishing a first version of our message contract

We’ll start with a first version of our message contract:

Let’s send this to RabbitMQ using:

Time to open the RabbitMQ Management portal and take a look how the message payload is constructed:

Creating a second version of our message contract

Let’s introduce a v2 version of our message contract:

If we send it to RabbitMQ in the same way:

There isn’t such a big difference when comparing the payloads:

The ‘messagetype’ value is different and of course the message itself. But that’s it.

Send a backwards compatible version

Let’s now construct a message that implements both contracts:

And send that one:

If we now check the payload, we see that 1 message is put on the queue with the following payload:

Take a look at the ‘messagetype’. You can see that it contains both the 2 messagecontracts AND the concrete message type we created:

"messageType": [


Consuming messages

Now we have a good understanding on what is going on at the sending side, let’s move on to the consuming side.

Consuming v1 of our message contract

Let’s create a consumer for that consumes v1 of our message contract:

And subscribe this consumer:

After publishing a ‘SubmitOrder’ message, our consumer is called as expected.

> Old Order consumed

Consuming v2 of our message contract

Let’s create a consumer for that consumes v2 of our message contract:

And subscribe this consumer:

After publishing a ‘SubmitOrderV2’ message, our consumer is called as expected.

> New Order consumed

So far nothing special.

Consuming the backwards compatible version

The question is what happens when we send our ‘SubmitOrderCommand’ that implements both message contracts.

If we have only one consumer subscribed the behavior is completely the same as before and either the old or the new consumer is called.

But if we have both consumers subscribed:

Each one will get a copy of the message and be called:

> Old Order consumed
> New Order consumed

Ok, that is good to now. But what happens if one of the consumers now fail?

Althought the first consumer is called succesfully, the message will still end up on the error queue:

If we then move the message back to the original queue, both consumers will be called again.