We’ve spent a lot of time rearchitecting the React\Client side in UDv3. This brings tons of new controls but we still have tech debt on the backend. I just want to jot this down so people understand where we are headed post-UDv3. This topic covers architectural changes that will happen likely in the v3.1 UD time frame rather than with v3.0.
The Problem(s)
Universal Dashboard is built on ASP.NET Core 2.1 and .NET Core 2.1. It uses the Kestrel web server and is hosted directly in PowerShell. This means that all the assemblies that UD requires are loaded directly into PowerShell.
Assembly Conflicts
From my perspective, this is the most annoying thing.
When you try to load UD in the VS Code extension or try to use the Az module, you may run into problems because both of those use the same .NET assemblies but different versions as UD. This causes UD to fail to load.
Version Lock-In
UD needs to support Windows PowerShell v5.1, which is built on the .NET Framework. New versions of ASP.NET Core no longer support .NET Framework. We can’t upgrade past version 2.1 so we are losing out on so many cool features (Blazor?), security fixes, and bug fixes (WebSocket reconnects!). Later next year, ASP.NET Core v2.1 will no longer be supported by Microsoft.
The Solution
The Universal Dashboard web server will become it’s own executable. It will still be shipped in the module but won’t be loaded directly into PowerShell.
Architecture
Configuration 1
One idea is to have Start-UDDashboard
start the UD.exe process. UD then connects back to PS.exe to execute everything.
PowerShell.exe | UniversalDashboard.exe | Client Browser
Start-UDDashboard -> | Starts Web Server |
Runs PowerShell | <- Processes User Request | < - Requests a page
Return result | Cache request if necessary -> | Renders result
There will be a smaller performance hit so we hope to introduce some request caching and performance improvements to resolve this issue.
This means that you could still use PowerShell v5.1 and we can upgrade UD and avoid assembly loading conflicts.
Configuration 2
This won’t resolve the assembly conflict issue but may be fine for some users.
If you’re using PowerShell v7, we’ll be able to execute the PowerShell completely in the UD process (I think). This means that running PSv7 will be faster since we can host the runtime directly in UDv3.
PowerShell.exe | UniversalDashboard.exe | Client Browser
Start-UDDashboard -> | Starts Web Server |
| Processes User Request | < - Requests a page
| Runs PowerShell Script |
| Cache request if necessary -> | Renders result
Configuration 3
One other configuration that I’m considering is having a per-session PowerShell.exe\Pwsh.exe instance. This means that whenever a user connects to UD, we spin up a new PowerShell.exe\Pwsh.exe instance. All the interaction that is done by the user happens in that process and then when that session is terminated, the process goes away. This cleans up any resources that the user allocated. This also means that sessions don’t conflict with each other at all.
This obviously would use the most resources and be slower because we need to spin up a new PowerShell instance but we might consider it as a feature for users that desire this type of isolation.
It also breaks the caching story because we now have separate processes so using the $Cache
variable would require an external, distributed cache. This is actually sitting in the issue backlog.
Status
I’ve only played with this a little bit. I’ve managed to upgrade UDv3 to .NET Core 3.1 and ASP.NET Core 3.1. It “just works” but getting the separation between PowerShell execution and the webserver is complicated since everything is tightly coupled.
I just wanted to provide a forward-looking tech discussion on this so others understand the problem and the solution that will be required.