Error 500.30: Multiple constructors accepting all given argument types have been found in type ‘HstsMiddleware’.

Upgrading ASP.NET web site to .NET 9

When upgrading a web site to .NET 9, the site stopped working with error 500.30 and this error was logged in event viewer:

System.InvalidOperationException: 'Multiple constructors accepting all given argument types have been found in type 'Microsoft.AspNetCore.HttpsPolicy.HstsMiddleware'. There should only be one applicable constructor.'

I could, unfortunately not, find any mentioning about this error on any of the search engines. There are a lot of information about the 500.30 error, but all of them was older and long before .NET 9. There are also many pages about the “Multiple constructors accepting all given argument types have been found in type xxx “, but none of them was about the HstsMiddleware.

The error “Multiple constructors accepting all given argument types have been found in type xxx” is a planned breaking change that was introduced in .NET 9 RC1 (https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/9.0/middleware-constructors). So, upgrading the site to .NET 8 worked fine. Also, removing the line app.UseHsts() worked, but HSTS sounds like something that is good to have.

After upgrading the site to .NET 9 and then stripping down the site more and more, until almost nothing was left, the error disappeared when removing the line:

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

And that line is for Autofac.
And the Autofac NuGet package was not updated.

Updating Autofac (and Autofac.Extensions.DependencyInjection) solves this issue.

Benchmarking Bitmap Indexes in .NET

For the web site WordMine.info, that is a search engine searching for words in almost any way possible, some optimizations are needed for the searches. Several word lists on the site have almost one million words and only doing a scan of all words and do a Regex or wild card-match one million times is too slow for a reasonable response time.

The most common database index is R-tree. The R-tree index is very good for what it is designed for, but you need to know what columns that is going to be queried to create a good index. Since the searches on WordMine.info is very flexible, there is no way to create an index (or a reasonable amount of indexes) that would work for each every possible search type.

Bitmap Indexes are very specialized indexes and can give a true of false for each record. A R-tree index can index all cities where customers are located and easily find which customers that are located in Gothenburg or customers that are in Copenhagen or all customers that are in either Berlin or London. The bitmap index can only answer one of these questions; “Is a customer in Gothenburg or not?”. To find the customers that are in Copenhagen you need a new index for that. But on the other hand they are somewhat compact (but since you need several indexes for each column, the total is not so compact) and also incredible good at combining several indexes to find the records that are interesting. So finding the customers that are in either Berlin or London, you need two indexes; one for customers in Berlin and one for customers in London. But since bitmap indexes are fast to combine you can easily use the two indexes combined to find all the customers in either Berlin or London.

To combine two indexes is very fast, to combine two indexes the processor instruction bitwise OR or bitwise AND is used, and also the bitwise instruction is normally done on 64 records at the same time.

Bitmap Index implementations in C#

In 2014 i wrote my own implementation of a bitmap index and found that it was extremely fast, it was somewhat specialized to my needs at WordMine.info, but after the initial testing of the first implementation it got abandoned for some reason.

Now, 10 years later, I thought that there is probably several implementations and NuGet packages that can easily beat the performance of my implementation. But there was not so many easy to find implementations as I expected. Actually, Microsoft Copilot found two of the implementations for me, the only time I Copilot has done anything useful so far.

Benchmarked bitmap indexes

csharpewah

https://github.com/lemire/csharpewah
License: Apache License, Version 2.0 (ASL2.0)
Last update: Nov 13, 2021

This is a compressed bitmap index. It’s usage is pretty straight forward, you create a EwahCompressedBitArray (with an initial size, if you like) and you Set(index) all the index positions that are true. There don’t seem to be a way to change a bit after it is set and all the added bits has to be added in order.

After the initialization you can And(), Or() or AndNot() two indexes together. To get the result you use GetPositions() to get a list (List<int>) with all the positive positions, or the enumerator to loop the positions. There is also an optimized Intersects() that returns true if both indexes has at least one true bit in the same position. A special case that I cannot find any use of myself.

CSharp.BitmapIndex

https://github.com/reinaldoarrosi/CSharp-BitmapIndex
License: Unknown
Last update: Aug 5, 2013

After I begun testing this implementation I realized that it was a wrapper for the csharpewah. CSharp.BitmapIndex adds handling of multiple bitmap indexes internally and has its own query language to handle the combining of the different indexes needed to get the result you are querying.

It look like the index initialization tries to help with the mapping of database values to bitmap index. So instead of creating an index for all customers in Gothenburg, you set the position of a key that is group/value (you can even have keys with group/subgroup/value).
bitmapIndex.Set(new BiKey(“City”, “Gothenburg”), position);
I can see the reason why the implementation is made like this, but all the new BiKey() (that is also needed in the querying) makes it a bit annoying to use. The querying is even more “chatty” than the index generation, but the intention is good to encapsulate all the indexes in the implementation.

CRoaring.Net

https://github.com/andersstorhaug/CRoaring.Net
License: MIT
Last update: Feb 21, 2018

CRoaring.Net is a .NET wrapper of the C implementation CRoaring (https://github.com/RoaringBitmap/CRoaring, License: Apache-2.0 and MIT), which is a port of the Java implementation (https://github.com/RoaringBitmap/RoaringBitmap, License: Apache-2.0). There are several other wrappers of the C version and ports of the Java implementation, but I selected this version because it was the repository with most recent (7 years) updates. Because the Java and C versions still gets frequent updates and this wrapper was 7 years old when tested, there might be improvements during these years that are not included in this implementation.

The usage of is pretty straight forward, you combine an index with another with the included methods. There are methods for combining two indexes, And, Or, AndNot, OrNot, Xor and more. Most (or all) has two different version where one of them creates a new index and another version updates the existing index with the combined result. The latter it much more effective when combining several indexes. There is also some static methods that combines a list of indexes, but for some reason combining these indexes with And is not included, but that seems to be a design decision in the CRoaring version.

Since CRoaring.Net is a direct wrap of CRoaring, it is using uint everywhere instead of int. The only time that that would be useful is when the indexed data has more than two billion records, which probably is pretty rare. This results in some of the API needs annoying casts.

Crude.BitmapIndex

https://github.com/aberkromb/Crude.BitmapIndex
License: MIT
Last update: Oct 6, 2019

This bitmap index implementation has the API that I like the most. It uses a Predicate (a Func that returns a bool) to generate the index, you create a builder and run builder.IndexFor(“in-gothenburg”, customer => customer.City == “Gothenburg”). It also includes two query engines, one default and one that uses the hardware acceleration Avx2.

But a great API does not help when the implementation has too many bugs. The first issue was that I tried with 1 million records, which quickly gave an index out of range exception, after some testing it turned out that the index data length cannot be a multiple of 64 without crashing. The hardware accelerated engine worked fine when running the included tests that uses 100,000 records, but with several more records the optimized version just hangs.

Equativ.RoaringBitmaps

https://github.com/equativ/Equativ.RoaringBitmaps
License: Apache-2.0
Last update: Nov 27, 2024

The Equativ.RoaringBitmaps is a pure C# port of the Java implementation RoaringBitmap (http://roaringbitmap.org/).

Creating indexes with Equativ.RoaringBitmaps is done by giving a list with all the set bits to the Create() method. After the index is created it cannot be changed, but it can be Optimized(). This is the only implementation that overloads the bitwise operators to combine the indexes.

ManualBitmapIndex

This is my first test with bitmap indexes from 2014, it is just a List<uint> for all the bits. And to combine two indexes it just loops all the uints in the list and bitwise and them together.

The only performance improvement in is code is that when retrieving the matches it first checks if there is any bit set at all before looking for which bits are set.

BitArrayIndex

This is almost a copy of the ManualBitmapIndex, but instead of storing the bits in a List<uint>, they are stored in a BitArray (https://learn.microsoft.com/en-us/dotnet/api/system.collections.bitarray).

When looking at the code for the BitArray class it is very optimized and hopefully some of the brightest minds at the dotnet team has worked on this code. The methods And(), Or(), Xor() and Not() uses hardware accelerated Vectors to execute the bitwise operations. The computer running the benchmarks supported hardware acceleration of Vector256.

Benchmarking speed of index search

This benchmarking is done on real data where I might have use for a bitmap index.

Total number of records: 1,335,000
Bits set is each index:
Index #1: 805,000 (60%)
Index #2: 226,000 (17%)
Index #3: 453,000 (34%)
Index #4: 384,000 (29%)
Index #5: 926,000 (69%)

About the index search benchmarking

The benchmarking merges two to five indexes with And to get the combined result. After the indexes are combined, the first matching 100 items from a List<> is retrieved. The reason to only get the first 100 items is to not include the retrieval of data in the index search benchmark and also simulate pagination of the result.

About the result of the speed benchmark

  • I was surprised that the ManualBitmapIndex would be faster than most of the other implementations. But maybe this raw implementation lacks some of the overhead that the other implementations have.
  • Also, I expected the hardware accelerated BitArray to be much faster than the ManualBitmapIndex because of the hardware acceleration. But the benchmark shows that in all the benchmarks the BitArray is slower or about the same speed.
  • CrudeBitmapDefault is the worst in all the tests because there is no way to limit the number of data to return. So it will always generate an array with all the objects that matches the combined indexes. All the other benchmarks only returns the first 100.
  • The optimized indexes in CRoaring.Net and Equativ.RoaringBitmaps does not look optimized when it comes to index speed. But that was expected, since I’m pretty sure the optimization refer to memory usage of the index. Also when the indexes has few
  • On their GitHub page, Equativ.RoaringBitmaps show benchmarking that beats CRoaring.Net in on every operation. But the reason for this benchmarking result, is because Equativ.RoaringBitmaps uses optimized indexes in for their own indexes, but unoptimized CRoaring.Net indexes. Changing the benchmark so both uses optimized indexes, makes Equativ.RoaringBitmaps 1.5 to 2.5 times slower.

Benchmarking memory of index search

Benchmarking speed of index generation

About the result of the index generation

  • What stands out here is the CSharp.BitmapIndex, while all other indexes takes a fraction of a second to create the indexes, CSharp.BitmapIndex takes almost a minute for each index. This is because this implementation does not give any way to preallocate the size of the index. This means that in this benchmark the underlying EwahCompressedBitArray (which, by the way, supports preallocation of memory) is probably reallocating the index about 20,000 times.
    But wait, there is more, CSharp.BitmapIndex is reallocating, not one, but two different indexes about 20,000 times, which one of them is negated, with Not(), twice for each set bit.

Benchmarking memory of index generation

Foot notes

  • This post uses indexes as plural of index and not the .NET indices. According to Oxford Learners Dictionary (link), both versions are valid.

Dns.GetHostEntryAsync() now returns “hostname nor servname provided, or not known”

Another regression in .NET MAUI

When all these issues with migrating to .NET MAUI (in the previous post) was fixed and the app was sent out to customers, some of the customers could no longer connect to their local server. The logs showed error “hostname nor servname provided, or not known” and no more useful information at all. But luckily, it is a quite specific error that would be easy to find the issue for. But unluckily, the only pages that the search engines found was not related to Android/MAUI and/or was some kind of configuration error.

The method Dns.GetHostEntryAsync() returns an IP-address from a string with a host name or a IP-address. The network code in my app was not changed at all between Xamarin.Forms and MAUI.

Unfortunately, the error did not occur when testing locally, even trying to connect to several different servers. But after testing several different routers, I finally got the error myself. The issue seemed to be a combination of Android manufacturer and router manufacturer. Samsung worked better than Zebra, some router gave the error on both device manufacturers and some routers only on Zebra. Sometimes, switching between different routers would solve the issue, but it would always come back sooner or later.

The .NET runtime was changed from mono to .NET 8 in MAUI and the working code in mono was calling an Android API to get the IP-address, when the new .NET 8 code is calling NameResolutionPal.TryGetAddrInfo() to get the IP-address. (I’m not sure that I found the correct code in .NET runtime.)

Here is the GitHub issue reported to the runtime team:
https://github.com/dotnet/runtime/issues/106969
It is currently tagged with future, which means that it will maybe be fixed in the future. From my previous experience with reporting issues in .NET, it will soon be closed with “closed because of inactivity”, because no one fixed the issue and users gets tired of waiting and starts using workarounds.

Migrating to MAUI from Xamarin.Forms

This is what I had to do to get my app converted to MAUI

TLDR; It was a less than optimal experience.

0. All old projects where updated

For this the Visual Studio Upgrade Assistant was used. It helped a lot with the upgrade, but missed a few referenced NuGet packages for Xamarin.Forms and did not sort the usings in any of the files (the added usings are not even sorted).

1. First try was to keep the current structure with separate project

But after fixing a few of the issues below and it did still not work satisfactory, I started over with a new project. Since the MAUI project template in Visual Studio uses one project for all platforms, that will probably be more used and have higher priority for Microsoft.

2. A referenced .NET Standard project had a space in the <PackageId>

That was a misstake from my side, but that space had been there for seven years, when the project was first created in 2017. At that time it was using .NET Standard 1.4 and none of the project upgrades since then has had any problem with that space.

And the error in Visual Studio for this issue was:

Error CS0006 Metadata file ‘D:[path to .NET Standard project]\obj\Debug\net8.0-android\ref\[project-name].dll’ could not be found

When comparing with other MAUI projects that did compile with proper PackageId (or no PackageId), that net8.0-android folder does not exist in the referenced project. Also when trouble shooting by removing and re-adding the invalid PackageId is somewhat inconsistent since the project has to be cleaned before the changes had any effect.

3. Upgraded old NuGet packages

Some NuGet packages in the project was targeting Xamarin.Froms and had to be updated or removed.

4. Created a new MAUI project

Since the new MAUI template is a single project and the old Xamarin project is four separate projects I started from scratch with a new project and copied the code manually to the new project.

5. Fixed compiler errors

Because of the new folder structure in the new MAUI project there was a few namespace collisions, which had to be fixed manually.

6. The app shows first page on Android

To check that the app starts properly on Android I changed the startup to only show the About page and that worked. After the previous issues this was a big relief.

7. The Windows app does not start

Now the app starts fine on Android, but on Windows it just starts and then crashes with a strange hex-code error.

The program ‘[4780] app.exe’ has exited with code 3762504530 (0xe0434352).

This was because the .gitignore was not updated for several years and the “launchSettings.json” was still ignored, so during the trouble shooting for the issue with the PackageId that file was removed. But I could not find any information on the web about this error. I found the error code, but none of the issues had anything to do with MAUI.

8. Switch the menu from MasterDetailPage to FlyoutPage

Yes, this should have been done a long time ago, but from what I can remember there was some issues when trying to switch earlier. And I think well tested code (that has been in production for a long time) is better than new code.

9. NavigationPage Title does not update

Now when a new page is loaded from FlyoutPage, the Title is not updated in the NavigationPage when a new page is pushed. The first page title that is shown when the app starts, stays there.

10. Switching to AppShell

So to get the page titles to work I switched to AppShell. AppShell is what Microsoft recommends and therefore will it probably higher prioritized in functionality and bug fixes. Switching to AppShell was easier than expected and a new version with new navigation made.

11. AppShell does not support TabbedPage

Now when the app is started every thing looks fine. But the most important pages in the app are tabbed pages and they do not load as expected. Not until i debug the app in Windows I get a proper exception that says that TabbedPage is not supported in an AppShell app.

That important information can will not appear until the runtime exception is hit.

To use AppShell, the TabbedPages must be rewritten. That means new untested code that could cause problems with the current stable app.

12. Switching back to NavigationPage

Re-writing the tabbed page or a bad title bar? Bad title bar seems like a more stable way to go. Tried several workarounds without any success. Then I found that the ToolbarItems are not updated either when a new page is pushed. So the filtering in the app will not work either.

Then at last I found that it was a bug that was fixed. The Visual Studio template for MAUI Apps references the NuGet package Microsoft.Maui.Controls with version “$(MauiVersion)”. It took a long time before I found the blog post that explained what $(MauiVersion) is and how it is supposed to work.

For some reason the Microsoft.Maui.Controls should not be updated like other NuGet packages, it is updated by changing the “<MauiVersion>8.0.6</MauiVersion>” in the project file. And of course, that property is not in the MAUI App template in Visual Studio.

13. Acr.UserDialogs does not work with WinUI

This is not a big issue, the project Acr.UserDialogs is no longer maintained. And the CommunityToolkit.Maui seems to have good replacements for this, but then it is new untested code again.

But it is yet another bump in the road towards the new MAUI App.

14. FlyoutPage crashes in WinUI

When using FlyoutPage (and MasterDetailPage) the code examples show that IsPresented should be set to false when the page has been shown.

But in WinUI the FlyoutPage is always visible and “IsPresented = false” throws a runtime exception. It looks like there is no way to detect if the FlyoutPage is always visible or not, because that property is always set to “Default”.

15. App initialization changed from Xamarin.Forms

In Xamarin.Forms the app had all the Android specific initialization in MainActivity.OnCreate(), but switching to MAUI that initialization is done after the MAUI App constructor is called and some things was not set up when the generic code was initialized.

16. Layout is inconsistent with Xamarin.Forms

When all these issues where fixed the migrated app is still unusable because of the xaml changes that was made between Xamarin.Forms and MAUI. There are changes in the grid layout and stack layout. For some reason that I haven’t found yet, most of the colors are wrong. Lots of text in the layouts are missing or cut off. Other text is stacked ontop of each others. Also, the padding has been intentionally changed in some of the controls, making buttons and text to shrink and be unusable.

17. CollectionView loads all items from ItemSource

All CollectionViews in the app was placed in StackLayouts. This was mostly because before the CollectionView, that was an easy way to add a header and a footer to a ListView.

In MAUI those CollectionViews stopped working (didn’t really stop, but it took minutes to load and used 1 GB extra of memory). After some debugging it turned out that the collection view in MAUI loaded all 600 items in ItemSource into memory, when Xamarin.Forms only loaded the first 30.

After some more digging it shows that it was another design change and CollectionView shall not be placed in StackLayouts anymore. Changing the StackLayouts to Grid fixed this problem.

Remote reset VMware ESXi when vSphere Client cannot connect

I’ve had several issues when I could not connect to vmWare ESXi. The vSphere Client only reported connection failure. The server was running as it should and none of the virtual mashines was affected by this, only the login.

Since the server is hosted in a remote location there has been no other way of fixing it  than to do a hardware reboot. Not the nicest way of solving it.

But since it happen regulary, I’ve turned the SSH as default. So I had one way in to the server when this happen. And there was no problem to log in with a SSH client.

I’ve tried to find a way to reset the service that vSphere Client connected to, but could not find anything. Some posts at the VMware site suggested that some processes should be restarted, but that was no luck. One suggestion was even that there was a problem with the local network, didn’t even try that.

After a while I gave up and decided to reboot the whole vmWare host with shutdown -r now. But in the vmWare host I could not find the shutdown command. Instead there was a shutdown.sh in the bin  (sbin) folder.

Maybe there was some clues in the shutdown.sh script.? It sure was! One of the lines in shutdown.sh was /sbin/services.sh stop. I just had to try and do a restart instead of a stop on that script. My backup plan was that if anything went terribly wrong, I would have to call the off site and have them do a physical power down on the server.

And it turned out a success! After the script had finished there was no problem at all to log in with the vSphere Client. None of the virtual mashines was affected and none of the web site neither.

/sbin/services.sh restart

Connecting to Server with Hyper-V Manager without Domain

After installing Windows Server 2016 Hyper-V on a small office network without domain or AD, I had big troubles with managing the server from Hyper-V Manager.

Found a guide from Microsoft that looked that it would solve the problem. But after trying “all” the steps there was still no luck with connecting to the server.

https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/user_guide/remote_host_management

These were the steps that most useful to me:

On the Hyper-V host to be managed, run the following as an administrator:

  1. Enable-PSRemoting
    • Enable-PSRemoting will create the necessary firewall rules for private network zones. To allow this access on public zones you will need to enable the rules for CredSSP and WinRM.
  2. Enable-WSManCredSSP -Role server

On the managing PC, run the following as an administrator:

  1. Set-Item WSMan:\localhost\Client\TrustedHosts -Value “fqdn-of-hyper-v-host”

  2. Enable-WSManCredSSP -Role client -DelegateComputer “fqdn-of-hyper-v-host”

  3. Additionally you may need to configure the following group policy: ** Computer Configuration | Administrative Templates | System | Credentials Delegation | Allow delegating fresh credentials with NTLM-only server authentication **

    • Click Enable and add wsman/fqdn-of-hyper-v-host

I did not do the last and optional step because I didn’t know how to do it. Of course that was the missing part!

To get to the Computer Configuration you have to start the “Local Group Policy Editor“. You can search for it in Windows or run the command “gpedit.msc“.

Also for those who don’t know, FQDN is “Fully Qualified Domain Name”.