Category Archives: .net

Creating a secure ASP.Net Core web application with Entra ID (formerly Azure AD) auth by group membership – harder than it should be

Several years ago I created a web application using ASP.NET and Azure AD authentication. The requirement was that only members of certain security groups could access the application, and the level of access varied according to the group membership. Pretty standard one would think.

The application has been running well but stopped working – because it used ADAL (Azure Active Directory Authentication Library) and the Microsoft Graph API with the old graph.windows.net URL both of which are deprecated.

No problem, I thought, I’ll quickly run up a new application using the latest libraries and port the code across. Easier than trying to re-plumb the existing app because this identity stuff is so fiddly.

Latest Visual Studio 2022 17.13.6. Create new application and choose ASP.NET Core Web App (Razor Pages) which is perhaps the primary .NET app framework.

Next the wizard tells me I need to install the dotnet msidentity tool – a dedicated tool for configuring ASP.NET projects to use the Microsoft identity platform. OK.

I have to sign in to my Azure tenancy (expected) and register the app. Here I can see existing registrations or create a new one. I create a new one:

I continue in the wizard but it errors:

This does not appear to be an easy fix. I click Back and ask the wizard just to update the project code. I will add packages and do other configuration manually. Though as it turned out the failed step had actually added packages and the app does already work. However Visual Studio is warning me that the version of Microsoft.Identity.Web installed has a critical security vulnerability. I edit Nuget packages and update to version 3.8.3.

The app works and I can sign in but it is necessary to take a close look at the app registration. By default my app allows anyone with any Entra ID or personal Microsoft account to sign in. I feel this is unlikely to be what many devs intend and that the default should be more restricted. What you have to do (if this is not what you want) is to head to the Azure portal, Entra ID, App registrations, find your app, and edit the manifest. I edited the signInAudience from AzureADandPersonalMicrosoftAccount to be AzureADMyOrg:

noting that Microsoft has not been able to eliminate AzureAD from its code despite the probably misguided rename to Entra ID.

However my application has no concept of restriction by security group. I’ve added a group called AccessITWritingApp and made myself a member, but getting the app to read this turns out to be awkward. There are a couple of things to be done.

First, while we are in the App Registration, find the bit that says Token Configuration and click Edit Groups Claim. This will instruct Azure to send group membership with the access token so our app can read it. Here we have a difficult decision.

If we choose all security groups, this will send all groups with the token including users who are in a group within a group – but only up to a limit of somewhere between 6 and 200. If we choose Groups assigned to the application we can limit this to just AccessITWritingApp but this will only work for direct members. By the way, you will have to assign the group to the app in Enterprise applications in the Azure portal but the app might not appear there. You can do this though via the Overview in the App registration and clicking the link for Managed application in local directory. Why two sections for app registrations? Why is the app both in and not in Enterprise applications? I am sure it makes sense to someone.

In the enterprise application you can click Assign users and groups and add the AccessITWritingWebApp group – though only if you have a premium “Active Directory plan level” meaning a premium Entra ID directory plan level. There is some confusion about this.

Another option is App Roles. You can assign App Roles to a user of the application with a standard (P1) Entra ID subscription. Information on using App Roles rather than groups, or alongside them, is here. Though note:

“Currently, if you add a service principal to a group, and then assign an app role to that group, Microsoft Entra ID doesn’t add the roles claim to tokens it issues.”

Note that assigning a group or a user here will not by default either allow or prevent access for other users. It does link the user or group with the application and makes it visible to them. If you want to restrict access for a user you can do it by checking the Assignment required option in the enterprise application properties. That is not super clear either. Read up on the details here and note once again that nested group memberships are not supported “at this time” which is a bit rubbish.

OK, so we are going down the groups route. What I want to do is to use ASP.NET Core role-based authorization. I create a new Razor page called SecurePage and at the top of the code-behind class I stick this attribute:

[Authorize(Roles = "AccessITWritingApp,[yourGroupID")]
public class SecurePageModel : PageModel

Notice I am using the GroupID alongside the group name as that seems to be what arrives in the token.

Now I run the app, I can sign in, but when I try to access SecurePage I get Access Denied.

We have to make some changes for this to work. First, add a Groups section to appsettings.json like this:

"Groups": {
"AccessItWritingApp": "[yourGroupIDhere]"
},

Next, in Program.cs, find the bit that says:

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

and change it to:

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{ 
// Ensure default token validation is carried out
builder.Configuration.Bind("AzureAd", options);
// The following lines code instruct the asp.net core middleware to use the data in the "roles" claim in the [Authorize] attribute, policy.RequireRole() and User.IsInRole()
// See https://docs.microsoft.com/aspnet/core/security/authorization/roles for more info.
options.TokenValidationParameters.RoleClaimType = "groups";
options.Events.OnTokenValidated = async context =>
{
if (context != null)
{
List requiredGroupsIds = builder.Configuration.GetSection("Groups")
.AsEnumerable().Select(x => x.Value).Where(x => x != null).ToList();
// Calls method to process groups overage claim (before policy checks kick-in)
//await GraphHelper.ProcessAnyGroupsOverage(context, requiredGroupsIds, cacheSettings);
    }
    await Task.CompletedTask;
};
}
);

Run the app, and now I can access SecurePage:

There are a few things to add though. Note I have commented a call to GraphHelper; you might want to uncomment this but there are further steps if you do. GraphHelper is custom code in this sample https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/ and specifically the one in 5-WebApp-AuthZ/g-2-Groups. I do not think I could have got this working without this sample.

The sample does something clever though. If the token does not supply all the groups of which the user is a member, it calls a method called ProcessAnyGroupsOverage which eventually calls graphClient.Me.GetMemberGroups to get all the groups of which the user is a member. As far as I can tell this does retrieve membership via nested groups though note there is a limit of 11,000 results.

Note that in the above I have not described how to install the GraphClient as there are a few complications, mainly regarding permissions.

It is all rather gnarly and I was surprised that years after I coded the first version of this application there is still no simple method such as graphClient.isMemberOf() that discovers if a user is a member of a specific group; or a simple way of doing this that supports nested groups which are often easier to manage than direct membership.

Further it is disappointing to get errors with Visual Studio templates that one would have thought are commonly used.

And another time perhaps I will describe the issues I had deploying the application to Azure App Service – yes, more errors despite a very simple application and using the latest Visual Studio wizard.

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!

Odd behaviour from Azure App Service: production version sometimes serves app from staging slot

I am developing an application which is deployed to Azure App Service. It runs on .NET 5.0 on Linux. I have set up a simple DevOps process so that committing changes to GitHub runs an Azure DevOps pipeline that deploys the application to a staging slot on Azure App Service for Linux. Then I can use Swap in the Azure portal to update the production slot. Swap simply exchanges the content of the staging slot with that in the production slot, so there is a route back in the event of disaster. Swap also restarts the application and forces users to log back in.

Yesterday I fixed a bug, deployed the change to the staging slot, and performed a swap. Logged back into the application, but the bug was still there, though intermittent. That was the bit I could not figure out: what was causing the code to behave differently on different requests? I became suspicious that it was sometimes serving the old version. I proved this by refreshing a page that demonstrated the bug. My page has an application version in the footer, and I could see that when the bug appeared, the version was older.

image

image

Well this is odd. In the App Service Deployment slot settings I have traffic set to 100% for the production slot:

image

In general I tend to assume a bug in my code or an error in my configuration settings is more likely than an issue with the Azure App Service. This does look odd though: why, if traffic is going 100% to the production slot, does the application sometimes serve the old version?

The pragmatic fix was easy. A second deployment to the staging slot means both now have code that works. The bug no longer appears; but I have kept the version number different and can see that the issue is actually still occurring.

I will update this post when I have more information, just in case anyone else hits this issue.

A UI lesson: do not ask users to choose between Register and Login

I am developing a web site for playing bridge, a project which kicked off in March when lockdown caused bridge clubs everywhere to close. There are lots of sites where you can play bridge online, but not many options (particularly back in March) for clubs that wanted to run their own online sessions.

It’s going OK with a number of clubs now using it every week, though it is still in development. I have learned a painful lesson though. In order to proceed as quickly as possible, I started my project with the Visual Studio template for an ASP.Net Core application with ASP.NET Core Identity – the latter an easy decision since it handles all the complications of registration, password reset and so on. (I did end up having to re-plumb it to use int rather than GUID for the primary key but that is another story).

The default home page the template generates looks like this, with options in the menu to Register or Login.

image

Registration and login are fundamental concepts that have been part of the web forever. It’s simple for a developer to understand: you register to create an account, you login if you already have an account.

The painful discovery is that this is not obvious to everyone, particularly to an older demographic that did not grow up with computers. Another factor is that cookies, browser-saved passwords and single sign-on with Google/Facebook etc means that this whole area is a bit of a mess and there are people who just kinda expect web sites to know who they are (which in one way horrifies me but I do see the massive convenience).

The consequence is that a surprising (to me) number of people had difficulty knowing whether Registration or Login was what they needed. They would Register, then return to the site and hit Register again. Why is this site asking for my details again? Maybe a security thing? Oh no, why does it now say username not available?

This is because asking the user to make this choice is not good design. Registration is rare, login is common. Further, Register is a confusing word. We sometimes use the word register when accounts already exist. Create Account is better. And a better UI is just Login. I need to access this website. Then, underneath the username/password request, an option that says “I need to create an account”. The two options should not be equally prominent; and if you look at how many prominent sites design this, that is what they do:

image image

Lesson learned; but I wish this had occurred to me sooner!

Developing software for playing bridge

I am a duplicate bridge player in my spare time and enjoyed playing in my local club once or twice a week. That was before COVID-19 and then, in March this year, lockdown. Bridge clubs were no longer able to meet. There are more important things in the world; but bridge is both a lot of fun and a welcome distraction from weightier matters, and my thoughts soon turned to what we could do to continue playing in these new circumstances.

The answer was to play online; but while there are plenty of ways to play bridge online, the existing systems were not designed with the idea of being a way for bridge clubs to meet in a new context. If anything, the reverse is true: online bridge site were designed for people who could not easily get to a club or wanted to play at any time with whoever else happened to be available. Clubs like my own, by contrast, wanted to replicate their face-to-face meetings with an online equivalent. A further complication back in March was that the biggest online bridge site, called Bridgebase, was immediately overloaded and declared that it was unwilling to allow new people to qualify as directors, people allowed to run online bridge sessions.

My immediate instinct was to build a new site for playing bridge. I was not quite starting from scratch. Back in the early days of Windows 8, I started work on a bridge game for Microsoft’s new and as it turned out ill-fated platform. I had got some way with it; I had created a bridge engine that understood about cards and hands and tricks and shuffling and scoring and all the various elements that go into playing bridge. It was written in C# and what is now UWP XAML. It is designed of course for a solo player. Here is the bidding screen:

image

and the play screen:

image

This is how it looks on Windows 10; it looked a bit better on Windows 8 though it would not win any prizes for design. My software could play bridge though; the reason I never finished it was that I never cracked getting the AI working. But for human to human play that did not matter. A weekend or two coding, I thought, and I could have a website up and running so our club could play bridge online. I made an immediate start, registering the domain name YourBridgeClubOnline.co.uk.

Well, three months later and here we are.

image

image

It is, I have to say, still under development. But it works and we have been able to play bridge again, as a club.

What took you so long? Ha! Much of my old bridge engine code remains untouched and has proved useful; it all runs fine on .NET Core. Even the (useless) AI has been handy, as I can test the mechanics of play without involving others. But I had, of course, wildly underestimated the problem of converting a game for solo play on Windows, to a multi-player web application. There is much to think about:

The UI. I am not a designer (I am sure you can tell) but spent ages puzzling over how to get a workable user interface in the browser for everything from tablets to desktops. Not smartphones yet but it is coming. I decided early on to take a view on compatibility. No Internet Explorer. JavaScript fetch API is required. When time is against you, it is easier to say, just use another browser, than to waste too much time supporting old browsers.

Messaging – both the API kind, and the chat kind. I am using C#, ASP.NET Core and SignalR. In general it works well. SignalR uses WebSockets as first preference, but falls back to Server Sent Events or long polling where necessary. In my first experiments I did my own polling and switching to SignalR was a great relief.

Registration and login. I am using the stuff that comes in the box, ASP.NET Core Identity. It has saved me a ton of work. It’s a bit annoying and not too well documented. I don’t really like using GUIDs for the primary key, for example, and I believe there is way to avoid it, but it isn’t top priority when you are going for Minimum Viable Product.

JavaScript. I’ve written tons of it and I don’t even like the language. I have a new respect for it though. The thing is, it is very fast and there is nothing you cannot do. The worst thing is the friction of doing some debugging in the browser, and some in Visual Studio. I am thinking of switching to VS Code for development since it works nicely with ASP.NET Core and is better for JavaScript than Visual Studio.

Scoring. My Windows software could score a hand of bridge. But duplicate is different; you have to compare the scores with others who played the same hands and work out the percentages, then export the results to standard formats for display on club websites and submission to the English Bridge Union. It was more work than I had expected and I am not done yet; the system only understands Pairs at the moment, not Teams (a different way of scoring).

Directing. Someone has to manage an online bridge session, settle any arguments, and fix errors like cards played by accident. It all needs coding and there was nothing like it in the Windows version.

Movements. Imagine you have 28 people playing bridge (or 14 pairs). They need to all play the same hands, but never play the same hand twice, and it has to be so arranged that each pair plays against other pairs in a defined sequence so it is balanced and fair. We call this the movement. Online, you have a bit more flexibility because you don’t need to share physical cards: everyone can play the same hand at the same time if you like. It is still quite fiddly though, and I did not do any of this in the old Windows version. I saved some time by writing an import function to enable re-use of movements made for EBUScore, a widely used scoring and bridge session management application. There is more to do though.

Claims. This is where, half way through the hand, a player says, “There’s no point in playing on, I’m obviously going to win all the remaining tricks.” A trick is a sequence of four cards played one from each hand, which is won by one of the pairs. This statement is called a claim, and has to be agreed by the other players. Getting this working was more difficult than I had expected – because built into my bridge engine was the idea that you could score by counting the tricks each side had won. But claimed tricks are never played. With hindsight, I should have allowed for this from the beginning.

Database. Every detail of play has to be stored on the server. I am using Dapper and SQL Server currently, though it is possible that PostgreSQL would work just as well. I started with Entity Framework Core, still there as it is used by ASP.NET Core Identity, but I am happier with Dapper.

Things that worked well

Three months is longer than I had thought it would take to get to a playable system, but I suppose as a spare time project it is not too bad. It would not be possible without the likes of ASP.NET Core and Dapper and SignalR doing so much for you. C# is a delight for coding. I am also using an Azure App Service for all this test and development and that has worked well. I am deploying to a Linux container of course; but the nice thing about App Service is that it will scale to a considerable extent without the hassle of Kubernetes. If the project succeeds and needs to scale up, there is an Azure SignalR service ready and waiting. I was nevertheless interested to see that AWS now offers .NET Core on Elastic Beanstalk, complete with some nice Visual Studio integration. Trying it there would be an interesting experiment, though I’m not sure AWS is so savvy about SignalR.

Open Source?

Could this have been done quicker by making it open source and seeking collaborators early on? Will it become open source? I need help for sure, though I also feel the code needs some cleaning up before it is fit to share more widely. You will recall though that I had started out thinking that it would be a small matter to convert my solo bridge game to an online multiplayer web application. I figured it would be better to get something working and then ask for help. But I am open to offers! Note: this is not a commercial project.

Rewarding

Most of the software projects I have been involved in have been business applications. Bridge is a lot more fun. I do see software development as a creative act. I recall starting work on the bridge game back in 2011 (I think); starting a new blank project in Visual Studio and thinking, hmm, I had better write a class to represent a pack of cards. From that beginning I ended up with an application that could play bridge, after a fashion, and now one that multiple people can play concurrently. It is rewarding and I will not regret the time spent on it, irrespective of how much actual use it gets.

Microsoft’s Pipelines for Azure Kubernetes Service: fixing COPY failed

I like to try new technology when I can so following the Build conference I decided to deploy a Hello World app to Azure Kubernetes Service (AKS). I made a one-node AKS cluster in no time. I built a .NET Core app in Visual Studio deployed to a Linux Docker container, no problem. I pushed the container into ACR (Azure Container Registry) though it turns out I did not really need to do that. The tricky bit is getting the container deployed to the AKS cluster. There is a thing called Dev Spaces but it does not work in UK South:

image

I was contemplating the necessity of building a Helm chart when I tried a thing called Deployment Center (Preview) in the Azure portal.

Click Add Project and it builds a pipeline in Azure DevOps for you.

image

It worked but the pipeline failed when building the container.

COPY failed: stat /var/lib/docker/tmp/docker-builder088029891/AKS-Example/AKS-Example.csproj: no such file or directory

I spent some time puzzling over this error. You can view the exact logs of the build failure and I worked out that it is executing the Dockerfile steps:

COPY [“AKS-Example/AKS-Example.csproj”, “AKS-Example/”]

RUN dotnet restore “AKS-Example/AKS-Example.csproj”
COPY . .

This is failing because there the code in my repository is not nested like that. I eventually fixed it by amending the lines to:

COPY [“AKS-Example.csproj”, “AKS-Example/”]
RUN dotnet restore “AKS-Example/AKS-Example.csproj”

COPY . AKS-Example/

Now the pipeline completed and the container was deployed. I had to look at the Load Balancer Azure had generated for me to find the public IP number, but it worked.

image

Now the Dockerfile has a different path for local development than when deployed which is annoying. I found I could fix this by changing a step in the Deployment Center wizard:

image

Where it says /AKS-Example in Docker build context I replaced it with /. Now the build worked with the original Dockerfile.

I also noticed that the Deployment Center (Preview) used a sample YAML template which is linked directly from GitHub and referred confusingly to deploying sampleapp. It worked but felt a bit of a crude solution.

At this point I realised that I was not really using the latest and greatest, which is the pipeline wizard in Azure Devops. So I deleted everything and tried that.

image

This was great but I could not see an equivalent step to the Docker build context. And indeed, the new build failed with the same COPY failed error I got originally. Luckily I knew the workaround and was up and running in no time.

This different approach also has a slightly different shape than the Deployment Center pipeline, using Environments in Azure DevOps.

Currently therefore I have two questions:

  • Why does Azure offer both the Deployment Center (Preview) and the multi-stage pipeline which seem to have overlapping functionality?
  • What is the correct way to modify the generated YAML to fix the path issue?

I suppose it would also be good if the path problem were picked up by the wizard in the first place.

The future of WPF for developers who need to support Windows 7

If you talk to Microsoft about what is new for Windows Presentation Foundation (WPF), a framework for Windows desktop applications, the answer tends to revolve around the Windows UI Library (WinUI), user interface controls for the Universal Windows Platform and therefore Windows 10, which you can use with WPF. That is no use if you need to compile applications that work on Windows 7. Is WPF on Windows 7 in effect frozen?

Not quite. First, note that WPF (and Windows Forms) was updated for .NET Framework 4.8, with High DPI enhancements and bug fixes. The complete list of fixes is here. So there have been recent updates.

Microsoft says though that .NET Framework 4.8 is the “last major version” of .NET Framework. This suggests that WPF on .NET Framework will not change much in future. WPF is open source; but the open source project targets .NET Core, the cross-platform version of .NET. In addition, there are a few features in WPF for .NET Framework that will never be ported, including XBAPs (XAML Browser Applications) – probably not something you care about.

The good news though is that .NET Core does run on Windows 7 (currently SP1 is required). You can see the progress of WPF on .NET Core here. It is not yet done and there are a few things that will never be supported. But when this is production-ready, it is likely that the open source WPF will run on Windows 7 and thus benefit from any updates and fixes made to the code.

From what I have learned here at Build, Microsoft’s developer conference, it is that .NET Core work that is currently top of mind for the WPF team. This means that WPF on Windows 7 does have a future – provided that .NET Core continues to support Windows 7. This proviso is important, since it is the decision of a different team. At some point there will be a version of .NET Core that does not support Windows 7, and that will be the moment when WPF cannot really progress on that operating system.

There may also be a special case. Presuming Edge Chromium runs on Windows 7, WPF may get a new Edge-based WebView control that runs on Windows 7.

Summary: WPF (and Windows Forms) on .NET Framework is not going to change much in future. If you can transition to using these frameworks on .NET Core though, there is more hope of improvements, though there is no magic that will make Windows 10 features available on Windows 7.

Which application platform for desktop Windows apps? Microsoft has stated its official line, but UWP is still not compelling

One year ago I wrote a post on Which .NET framework for Windows: UWP, WPF or Windows Forms? which is still the most popular post on this site, indicating perhaps that this is a tricky issue for many developers. That this is a live question is a symptom of Microsoft’s many changes of strategic direction over the last decade, making it hard for even the most loyal developers to read the signals.

I was intrigued therefore to note that Microsoft has an official Choose your platform post on this subject. There is something curious about this post. It covers three frameworks: Universal Windows Platform (UWP), Windows Presentation Foundation (WPF) and Windows Forms (WinForms). Microsoft states:

UWP is our newest, leading-edge application platform.

implying that if you have an unconstrained choice, this is the way to go. Yet if you look at the table of “Scenarios that have limited support”, UWP has the longest list. It is not only Windows 7 support that you will miss, but also something called Dense UI, along with other rather significant features like multiple windows and “full platform support”.

What is Dense UI? I presume this is a reference to the chunkiness of a typical UWP UI, caused by the fact that it was originally optimised for touch control. This matters if, for example, you are writing a business application and want to have a lot of information to hand in a single window. It may not be ideal for cosmetics, but it can be good for productivity.

With respect to all three of these limitations, Microsoft does note that “We have publicly announced features that will address this scenario in a future release of Windows 10.” I am not sure that they are in fact fully addressed; but it is clear that improvements are coming. In fact, the promise of further active development is perhaps the key reason why you might choose UWP for a new project, that is, if you do not learn from the past and believe that UWP will still be core to Microsoft’s strategy in say five years time.

Take a look at the strengths column for UWP though. Anything really compelling there? To my mind, just one. “Secure execution via application containers.” Yet the security of UWP was undermined by Microsoft’s decision to abandon its original goal of restricting the Windows Runtime API (used for UWP) to a safe subset of the full Windows API. You can also now wrap WPF and WinForm applications using Desktop Bridge, getting Store delivery and a certain amount of isolation.

At the time of writing, Microsoft is still displaying this diagram in its guide to UWP.

image

This is now somewhat misleading though. Windows Mobile is on death row:

Windows 10 Mobile, version 1709 (released October 2017) is the last release of Windows 10 Mobile and Microsoft will end support on December 10, 2019. The end of support date applies to all Windows 10 Mobile products, including Windows 10 Mobile and Windows 10 Mobile Enterprise.

Windows 10 Mobile users will no longer be eligible to receive new security updates, non-security hotfixes, free assisted support options or online technical content updates from Microsoft for free.

As a developer then, would you rather have PC, Xbox and HoloLens support? Or PC, Mac, iOS and Android support? If the latter, you would be better off investigating Microsoft’s Xamarin Forms framework than UWP as such.

The truth is, many developers who target Windows desktop applications do so because they want to run well on Windows and are not concerned about cross-platform. While that may seem odd from a consumer perspective, it is not so odd for corporate development with deskbound users performing specific business operations.

I was at one time enthusiastic about Windows Runtime/UWP because I liked the idea of “one Windows platform” as illustrated above, and I liked the idea of making Windows a platform for secure applications. Both these concepts have been thoroughly undermined, and I would suggest that the average developer is probably better off with WPF or WinForms (or other approaches to Win32 applications such as Delphi etc), than with UWP. Or with Xamarin for a cross-platform solution. That is unfortunate because it implies that the application platform Microsoft is investing in most is at odds with what developers need.

If UWP becomes a better platform than WPF or WinForms in all important respects, that advice will change; but right now it is not all that compelling.

The best apps for a Windows 10 PC? Disappointing list shows key Windows weakness

I happened across Tom Warren’s list of 9 best apps for your new Windows PC and it gave me pause for thought. You may love some of those apps – Tweeten, Wox, ShareX, for example – but as it happens I don’t use any of them and it strikes me as a weak list.

There are reasons for this and it is not Warren’s fault (though of course you can argue with his selection, that’s really the point of this kind of post).

The most essential app for Windows is Microsoft Office. In business environments a new Windows 10 installation may only need Office, or Office and perhaps a few custom business applications, and it is ready to go.

You might add Chrome or Firefox if you want to avoid Edge (I use Edge and find it pretty good), and you probably want Adobe Reader or equivalent as Edge is not that good for PDFs.

There are other fantastic commercial applications of course, not least Adobe’s amazing Creative Cloud, and of course stalwarts like AutoCAD.

These expensive business applications are not the kind of thing you want to list in a consumer-oriented post though. So you end up desperately searching the Windows Store for apps that deserve to be on a “best apps” list. It is not easy.

The core problem is that Microsoft expended considerable energy telling developers not to bother with classic Windows desktop applications but to target the Windows Runtime, later reworked as UWP (Universal Windows Platform). Then with Windows 10 (and the abandonment of Windows 10 mobile) UWP became rather pointless. You can debate this back and forth, but the net result is that much of the life was sucked out of the Windows developer ecosystem, even though Windows remains popular.

I don’t see this changing and it will not help Microsoft sustain Windows market share versus Google Chrome OS and Apple iPad Pro. From a consumer perspective, an iPad now has vastly better apps than Windows.

Incidentally, my favourite free Windows apps are Visual Studio Code, Filezilla, Putty, Notepad++, Paint.NET, Audacity, Foobar2000 and Open Live Writer. And stuff I have installed in Windows Subsystem for Linux (Ubuntu) though I am not sure if that counts.

A glimpse into Microsoft history which goes some way to explaining the decline of Windows

Why is Windows in decline today? Short answer: because Microsoft lost out and/or gave up on Windows Phone / Mobile.

But how did it get to that point? A significant part of the story is the failure of Longhorn (when two to three years of Windows development was wasted in a big reset), and the failure of Windows 8.

In fact these two things are related. Here’s a post from Justin Chase; it is from back in May but only caught my attention when Jose Fajardo put it on Twitter. Chase was a software engineer at Microsoft between 2008 and 2014.

Chase notes that Internet Explorer (IE) stagnated because many of the developers working on it switched over to work on Windows Presentation Foundation, one of the “three pillars” of Longhorn. I can corroborate this to the extent that I recall a conversation with a senior Microsoft executive at Tech Ed Europe, in pre-Longhorn days, when I asked why not much was happening with IE. He said that the future lay in rich internet-connected applications rather than browser applications. Insightful perhaps, if you look at mobile apps today, but no doubt Microsoft also had in mind locking people into Windows.

WPF, based on .NET and DirectX, was intended to be used for the entire Windows shell in Longhorn. It was too slow, memory hungry, and buggy, eventually leading to the Longhorn reset.

“Ever since Longhorn the Windows team has had an extremely bitter attitude towards .NET. I don’t think its completely fair as they essentially went all in on a brand new technology and .NET has done a lot of evolving since then but nonetheless that sentiment remains among some of the now top players in Microsoft. So effectively there is a sentiment that some of the largest disasters in Microsoft history (IE’s fall from grace and multiple “bad” versions of Windows) are, essentially, totally the fault of gambling on .NET and losing (from their perspective). “

writes Chase.

This went on to impact Windows 8. You will recall that Windows Phone development was once based on Silverlight. Windows 8 however did not use Silverlight but instead had its own flavour of XAML. At the time I was bemused that Microsoft, with an empty Windows 8 app store, had not enabled compatibility with Windows Phone applications which would have given Windows 8 a considerable boost as well as helping developers port their code. Chase explains:

“So when Microsoft went to make their new metro apps for windows 8/10, they almost didn’t even support XAML apps but only C++ and JavaScript. It was only the passion of the developer community that pushed it over the edge and let it in.”

That was a shame because Silverlight was a great bit of technology, lightweight, powerful, graphically rich, and even cross-platform to some extent. If Microsoft had given developers a consistent and largely compatible path from Silverlight to Windows Phone to Windows 8 to Windows 10, rather than the endless changes of direction that happened instead, its modern Windows development platform would be stronger. Perhaps, even, Windows Phone / Mobile would not have been abandoned; and we would not have to choose today between the Apple island and the ad-driven Android.