Category Archives: professional

.NET 11: unions, MAUI ready for business, but what comes next?

Microsoft has released .NET 11, as part of the online .NET Conf under way today and tomorrow. It is not a long-term support (LTS) release though that detail does not mean all that much; it will be supported for two years, and if like me you upgrade soon after each new release everything is fine.

.NET 11 is now fully released

New features include union types in C# 15, faster asynchronous code, Core CLR on all platforms in place of Mono in MAUI (Multi-platform app UI), and hundreds of other improvements across the runtime and frameworks including ASP.NET Blazor and even the venerable Windows Forms.

Personally I am most interested in the performance improvements, and in the progress of .NET MAUI which after years of troublesome issues now looks to me a strong contender for cross-platform mobile and desktop development.

I like programming in C# and for me it hits a sweet spot of safety, performance and ease of use. Microsoft’s stewardship of the language and of .NET has been good in general, though it fumbled the handover to the .NET Foundation. There is still too much dependence on one company and despite the open source and cross-platform aspect, the technology remains associated with Windows which holds back adoption.

For further background on the inadequacy of the .NET Foundation check out this report from F# Software Foundation Executive Director Reed Copsey which says “I find myself unable to honestly recommend anybody put time or effort into the Foundation, or recommend joining as a member” and that “independence of the Foundation is disingenuous” thanks to bylaws that ensure that “the .NET Foundation is prevented, by design, from being able to self-govern and impact meaningful changes without direct support of Microsoft.”

The future of .NET is in largely in Microsoft’s hands and the question is where it will go now that programming is in the process of disruption by AI, a process which is still under way and the outcome of which is uncertain. If one takes the view that coding will largely be done by AI in future then programming languages and runtimes will change accordingly. We can see a little of how Microsoft is thinking about this with the introduction of WinUI Reactor, a framework for WinUI application using C# that is designed for agents as much as for people.

If we consider though the elements of the sweet spot I mentioned above, safety, ease of use, and performance, we may conclude that ease of use is no longer important (because humans are not using the language), and that for performance we should ask AI to use a system language such as C, C++ or Rust. And of these three, Rust is a winner because safety still matters, and AI is not immune from making memory safety mistakes.

I am therefore uncertain whether we will see the established yearly cycle of major .NET releases every year repeat for much longer. Microsoft may shift more investment towards AI and Rust.

That said, Microsoft has a strong track record of maintaining technology in use by its customers and developers can be confident that .NET and its various frameworks will continue to be maintained for long into the future.

Microsoft’s AI assisted blog posts

Last week I wrote about Microsoft’s Reactor framework, a React-inspired C# framework for WinUI, using an official blog post by principal software developer engineer Alexandre Zollinger Chohfi as one of the sources.

But was the post really by Chohfi? As I read it, I was pretty sure that it was AI-generated. Pangram, an AI detection engine, agrees with me (note this is based only on the first 388 words).

Pangram is confident that the Microsoft post was AI-generated

I see a lot of AI-generated text, for example in my own (light) use of AI coding tools, in code comments and issues on GitHub, in forum posts, and in emails. There are many indicators, though it is hard to pick them out in what is a subjective impression. A phrase like “new controls and patterns get tried here first, and the ones that prove themselves are candidates to land in WinUI itself” just sounds like AI to me. It is not bad writing, but why “to land in WinUI”? Why not, “for WinUI”? It is breezy for the sake of it, and does not come over as something a human would write.

Questions that interest me are first, does it matter, and second, should it be acknowledged, in the same way that Facebook now marks some posts as “AI content” (though I’m not sure how accurate it is).

For me it does matter. In particular, the AI-generated or AI-assisted content removes the personality of the human author who oversaw it, even if the text ends up being better written by some metrics. I would rather have worse English but with a sense of who the author is and what they think and feel about their subject matter.

There is also the possibility of AI-generated mistakes, though if the text is properly reviewed this should not be a concern. With a journalist hat on, I think it is OK to quote such text as if it were written by the author to whom it is attributed. That person is taking responsibility for the text by putting their name to it.

Should it be acknowledged? I would prefer this, but acknowledge that it is difficult. If someone fixed spelling or changed punctuation because of squiggly lines in Microsoft Word, is that AI assistance? Not really. It is hard to determine at what point the line is crossed.

I suspect that part of the reason for using AI assistance is that people lack confidence in their own writing, particularly if it is not in their native language. That is understandable, but from my perspective, I want to hear from the author, not a bland AI-generated post based on the author’s notes, or worse, an author sitting back and letting AI do all the research and the write-up as well.

Deno’s endo – team joins CloudFlare, runtime will be abandoned in one year’s time

Deno (and Node.js) inventor Ryan Dahl has posted that his team is joining Cloudflare and that after one more year of support “we will end our development of the Deno runtime. Deno will remain open source, and we welcome others who want to continue its development.”

Deno 1.0 was released in 2020 as an attempt to fix what Dahl called “design mistakes in Node”. Deno is built in Rust, supports TypeScript natively, takes advantage of V8 sandboxing, but at launch did not support Node modules, limiting compatibility.

Deno’s initial take-up was limited by lack of Node.js compatibility, a problem the project attempted to fix in Deno 2.0, released in October 2024. Retro-fitting Node.js compatibility must have been a big drain on resources, absorbing effort that could have gone into improving the runtime.

In the meantime, Node.js worked on adding native TypeScript support, delivered in early 2025 by Node.js 23.6 in experimental form.

Deno also suffered from the rise of Bun, another JavaScript runtime and bundler, first released in September 2023, with TypeScript support, some Node.js compatibility, and fast performance. Bun evolved rapidly and was acquired by Anthropic in December 2025. Bun continues to improve, with the latest 1.4.3 release adding a TypeScript type checker which is a port of Microsoft’s typescript-go (now just TypeScript 7) to Rust, with a claimed 3x performance improvement.

The Deno project’s business model depended on enterprise support contracts and hosting via Deno Deploy, perhaps not sufficient for the long-term health of the project.

Dahl writes that “we know this is a consequential change for people who have built on Deno,” but offers little comfort to users. Deno Deploy will be discontinued in 6 months. The JSR registry, designed as a superset of the npm registry and as TypeScript-first, will continue.

On Reddit Deno users debate where to go. Might Deno survive as an independent open source project (unlikely)? One says: “we are all back to Node these days” and another, “perhaps now is a good opportunity to consider .NET.”

Shopify migrates from React Native to native Android and iOS development, citing AI as enabler

Cross-platform development fascinates because of its many nuances. Is it more important than an app works the same on each platform, or that it is optimized for the best experience? Is it more important to share code for better maintainability, or to have separate code bases to avoid compromising? And if one does go the for a cross-platform framework, what is the best choice?

Back in 2020, Shopify decided on React Native as its solution; now it is changed its mind. The company has several mobile apps, including one called Shopify aimed at vendors using its service, and another called Shop aimed at consumers. Shop has a five-star rating and is the 7th most popular shopping app in the iOS App Store.

When it adopted React Native after “years of native mobile development”, the company cited three reasons: acquisition of another company with deep React Native skills (Tictail); harmony with its use of React in its web applications; and the improving performance of the React Native framework. Shopify said that an early rewrite of Shop (formerly called Arrive) had less crashes on iOS than the native version, and shared 95% of code with the Android version.

Now, Shopify engineers say that “advances in coding agents changed the tradeoffs behind maintaining a shared mobile codebase.” The native port of Shop, now using Swift on iOS and Kotlin on Android, has a faster start-up (23% improvement on iOS, 50% on Android), improved stability, and on Android, 37% smaller release build size.

React Native has a new architecture with many improvements; however migration to this has challenges and avoiding this work for its Shop app was another factor in Shopify’s decision – though it had already migrated two other apps. This also means that Shopify’s comparisons are with the old React Native architecture; one might speculate that migrating to the new architecture would also have brought benefits. That said, its report on migrating the other apps (Shopify Mobile and Shopify Point of Sale) was mixed; start-up time slightly improved, but the team discovered performance and stability issues which required work. “These were not to blame on the New Architecture itself. It just revealed cracks in some component designs that were previously invisible,” said Shopify at the time.

The key point of interest is not so much the change of mind but the role of AI coding in the decision. The company said that “Native still means building and maintaining software on two platforms, that cost has not disappeared. What changed is that agents can now do enough of the implementation, translation, testing, and review work that it’s no longer the deciding factor it was in 2020.”

What works for Shopify may not work so well elsewhere. Personally I am nervous about AI coding for several reasons, including cost, security and subtle bugs. As an individual developer, the notion of paying continually for software development is unattractive; that does not apply to a larger company which asks only whether the benefits exceed the costs.

First steps with MAUI: some friction

I am evaluating Microsoft’s MAUI (Multi-platform app UI) for use on a cross-platform project. I mainly develop on a Mac with Visual Studio Code.

Setup for MAUI development is well explained here though getting everything in place for Mac Catalyst, iOS and Android is tedious. There is a tricky issue related to Apple’s Xcode, needed for MAUI for the Apple targets. Apple’s recommendation is that you install Xcode from the App Store. As you would expect, it updates quite frequently and always when there is a new version of macOS. The version on my machine is therefore 26.6. After installing MAUI for .NET 10 I got an error when trying to build, stating that I had the wrong version (mine was too new).

The workaround for this is either to install multiple versions of Xcode, which is fiddly, or to set ValidateXcodeVersion to false in the .csproj project file.

As it turns out, there is another fix. The .NET for iOS SDK (used by MAUI) was updated last month to require Xcode 26.6. Note: require, not support. Each version of the SDK requires one and only one version of Xcode, and there is a lag between Apple releasing a new version, and Microsoft updating its SDKs.

My instinct is to set ValidateXcodeVersion false during development and to watch out for strange errors that might be fixed for a production build, using the correct Xcode version.

Microsoft’s MAUI SDK engineering lead said:

Updates can include different things that amount to varying levels of work. Sometimes there’s api changes in the SDKs Xcode ships that we need to account for, sometimes they change Cli tools or break things in other ways. Depending on the changes it can be a little bit of work or a lot. 

Lately minor version updates to Xcode tend to be somewhat compatible with existing MAUI (Mac/ios) workloads and you can technically force trying to use it with the right build settings, but we generally advise not installing Xcode from the App Store so that it isn’t silently updated and you can install updates when you know they’ll be supported by MAUI instead.

This is friction, though it comes with the cross-platform territory. Note that Apple insists on building with the latest Xcode for store submission.

With that out of the say, I started building an experimental app. This is not Windows and conceptually one should think of the app UI as a single page, mobile app style, even if developing for Windows and Mac Catalyst. I decided to use a Tab Bar for navigation, but ran into an issue: when debugging the app for Mac Catalyst, the Tab Bar did not appear.

I thought this was something I was doing wrong, even though it was a simple and basic case. Then after digging a bit I discovered that it was a bug, that I was not the first to hit it, and that it was fixed with a workaround late last year.

The solution is to run: dotnet workload update from the command line to get the latest version.

Both issues are a reminder of how tricksy cross-platform development can be, particularly for frameworks like MAUI which use native widgets rather then drawing them from scratch like Flutter or Avalonia UI.

The solution, it seems to me, is to keep the user interface simple.

JetBrains Resharper for Visual Studio Code adds C# debugging support

One of the oddities of Microsoft’s Visual Studio Code is that it is free to use for almost anything other than the company’s own .NET platform. That is, there is nothing to stop developers from coding in C# with VS Code and using the .net command-line tools without paying Microsoft for a license; but the official C# Dev Kit extension requires a license for teams of 6 developers or more:

For personal, academic, and open-source projects, C# Dev Kit can be used at no cost. For commercial purposes, teams of up to 5 can also use the C# Dev Kit at no cost. For 6+ developers, those users will need a Visual Studio Professional (or higher) subscription.

In addition, there are licensing restrictions on Microsoft’s .NET debugger which impact VS Code forks:

The C# extension for Visual Studio Code includes the Microsoft .NET Core Debugger (vsdbg). Unlike VS Code, and most other parts of the .NET Core ecosystem, vsdbg is not an open source product but rather is a proprietary part of Visual Studio. It is licensed to work only with IDEs from Microsoft — Visual Studio Code, Visual Studio, or Visual Studio for Mac.

JetBrains has now introduced C# debugging support for the ReSharper VS Code extension, which means there is now another high quality option for developers who either prefer not to use the C# Dev Kit, or are using a VS Code fork such as AWS Kiro, Cursor, Windsurf or Google Antigravity, for which the official .NET debugger is not licensed.

ReSharper is free for non-commercial use, or costs £119.00 ($149.00) per year for an individual or £295.00 ($389.00) per year for developers working for an organization. The cheapest standalone Visual Studio Professional plan is currently $540.00 per year, though some developers will get it bundled with other plans.

Leaving aside licensing and cost considerations, how does ReSharper compare to C# DevKit and the Microsoft .NET debugger? I have yet to use ReSharper so do not have a personal opinion; but will note that Microsoft’s recent change which removed the Solution Explorer is unpopular.

Finally, my personal view is that Microsoft has more to gain by making .NET and its tooling fully open, than by playing games with licensing restrictions in an effort to keep developers hooked to Visual Studio or VS Code.

Fixing a .NET P/Invoke issue on Apple Silicon – including a tangle with Xcode

I have a bridge platform (yes the game) written in C# which I am gradually improving. Like many bridge applications it makes use of the open source double dummy solver (DDS) by Bo Haglund and Soren Hein.

My own project started out on Windows and is deployed to Linux (on Azure) but I now develop it mostly on a Mac with Visual Studio Code. The DDS library is cross-platform and I have compiled it for Windows, Linux and Mac – I had some issues with a dependency, described here, which taught me a lot about the Linux app service on Azure, among other things.

Unfortunately though the library has never worked with C# on the Mac – until today that is. I could compile it successfully with Xcode, it worked with its own test application dtest, but not from C#. This weekend I decided to investigate and see if I could fix it.

I have an Xcode project which includes both dtest and the DDS library, which is configured as a dynamic library. What I wanted to do was to debug the C++ code from my .NET application. For this purpose I did not use the ASP.Net bridge platform but a simple command line wrapper for DDS which I wrote some time back as a utility. It uses the same .NET wrapper DLL for DDS as the bridge platform. The problem I had was that when the application called a function from the DDS native library, it printed: Memory::GetPtr 0 vs. 0 and then quit.

The error from my .NET wrapper

I am not all that familiar with Xcode and do not often code in C++ so debugging this was a bit of an adventure. In Xcode, I went to Product – Scheme – Edit Scheme, checked Debug executable under Info, and then selected the .NET application which is called ddscs.

Adding the .NET application as the executable for debugging.

I also had to add an argument under Arguments passed on Launch, so that my application would exercise the library.

Then I could go to Product – Run and success, I could step through the C++ code called by my .NET application. I could see that the marshalling was working fine.

Stepping through the C++ code in Xcode

Now I could see where my error message came from:

The source of my error message.

So how to fix it? The problem was that DDS sets how much memory it allows itself to use and it was set to zero. I looked at the dtest application and noticed this line of code:

SetResources(options.memoryMB, options.numThreads);

This is closely related to another DDS function called SetMaxThreads. I looked at the docs for DDS and found this remark:

The number of threads is automatically configured by DDS on Windows, taking into account the number of processor cores and available memory. The number of threads can be influenced using by calling SetMaxThreads. This function should probably always be called on Linux/Mac, with a zero argument for auto­ configuration.

“Probably” huh! So I added this to my C# wrapper, using something I have not used before, a static constructor. It just called SetMaxThreads(0) via P/Invoke.

Everything started working. Like so many programming issues, simple when one has figured out the problem!

Amazon Linux 2023 on Hyper-V

Amazon Linux 2023 came out in March 2023, somewhat late as it was originally called Amazon Linux 2022. It took even longer to provide images for running it outside AWS, but these did eventually arrive – but only for VMWare and KVM, even though old Amazon Linux 2 does have a Hyper-V image.

Update: Hyper-V is now officially supported making this post obsolete but it may be of interest!

I wanted to try out AL 2023 and it makes sense to do that locally rather than spend money on EC2; but my server runs Windows Hyper-V. Migrating images between hypervisors is nothing new so I gave it a try.

  • I used the KVM image here (or the version that was available at the time).
  • I used the qemu disk image utility to convert the .qcow2 KVM disk image to .vhdx format. I installed qemu-img by installing QUEMU for Windows but not enabling the hypervisor itself.
  • I used the seed.iso technique to initialise the VM with an ssh key and a user with sudo rights. I found it helpful to consult the cloud-init documentation linked from that page for this.
  • In Hyper-V I created a new Generation 1 VM with 4GB RAM and set it to boot from converted drive, plus seed.iso in the virtual DVD drive. Started it up and it worked.
Amazon Linux 2023 running on Hyper-V

I guess I should add the warning that installing on Hyper-V is not supported by AWS; on the other hand, installing locally has official limitations anyway. Even if you install on KVM the notes state that the KVM guest agent is not packaged or supported, VM hibernation is not supports, VM migration is not supported, passthrough of any device is not supported and so on.

What about the Hyper-V integration drivers? Note that “Linux Integration Services has been added to the Linux kernel and is updated for new releases.” Running lsmod shows that the essentials are there:

The Hyper-V modules are in the kernel in Amazon Linux 2023

Networking worked for me without resorting to a legacy network card emulation.

This exercise also taught me about the different philosophy in Amazon Linux 2023 versus Amazon Linux 2. That will be the subject of another post.

The era of tiny PCs: 400g and smaller than a paperback book

My work PC for the last few years has been a 2018 HP Omen gaming PC which has been brilliant; I have replaced the GPU and added storage but everything still works fine. That is, it used to be, until I reviewed a mini PC which has surprised me with its capability – not because it is exceptional, but because everyday technology is at the point where having something bigger is unnecessary for everyday purposes other than gaming.

Mini PC with paperback book and CD to show the size

The new PC is a Trigkey S5 with an AMD Ryzen 5560 CPU, 500GB NVMe SSD and 16GB DDR4 RAM, and currently costs around £320. Its Geekbench CPU score is better than my 5-year old HP with a Core i7.

GPU score is way less than the old HP.

Still, there is support for three displays via HDMI, DisplayPort and USB-C and 4K/60Hz is no problem.

Inside we find branded RAM and it does not look as if the components are shoe-horned in, there is plenty of space.

The power supply is external and rated at 19v and 64.98w.

Expansion is via 4 USB-A ports, one USB-C, and the aforementioned HDMI and DisplayPort sockets. There is also an Ethernet port, and of course Bluetooth and Wi-Fi.

Operating system? Interesting. It is not mentioned in the blurb but Windows 11 happens to be installed, but with one of those volume MAK (Multiple Activation Key) licenses that is not suitable for this kind of distribution (but costs the vendor hardly anything). When first run Windows setup states that “you may not use this software if you have not validly acquired a license for the software from Microsoft or its licensed distributors,” which you likely have not, but Trigkey may presume that most of its customers will not care. I recommend installing your own licensed copy of Windows as I have done, or your preferred Linux distribution.

Windows does run well however and 16GB RAM is enough for Hyper-V and Windows Subsystem for Linux (WSL) 2.0 to run well. Visual Studio 2022, VS Code, Microsoft Office, all run fine.

I am not suggesting that this particular model is the one to get, but I do think that something like this, small, light, and power-sipping, is now the sane choice for most desktop PC users.

Remote Desktop on Mac failes to connect with 0x207 error

I am setting up a new Mac and got this annoying error from the Microsoft Remote Desktop client.

Worse, a number of people have complained about this error but there is a lot of useless advice out there, and also the bad advice to disable NLA (Network Level Authentication) on the Windows PC. Don’t do that, it is bad for security.

One of the few helpful threads on the topic is this one which point to this article on the subject of how to enable integrated authentication on Mac and Linux using Kerberos. I followed the advice here and it worked though I’m not sure if the ALL CAPS is necessary for the domain, but I used it and it worked – as long as I entered user@ALLCAPS in the RDP username as well.