Scott Hanselman

Upgrading a 20 year old University Project to .NET 6 with dotnet-upgrade-assistant

November 18, 2021 Comment on this post [7] Posted in DotNetCore | Open Source
Sponsored By

I wrote a Tiny Virtual Operating System for a 300-level OS class in C# for college back in 2001 (?) and later moved it to VB.NET in 2002. This is all pre-.NET Core, and on early .NET 1.1 or 2.0 on Windows. I moved it to GitHub 5 years ago and ported it to .NET Core 2.0 at the time. At this point it was 15 years old, so it was cool to see this project running on Windows, Linux, in Docker, and on a Raspberry Pi...a machine that didn't exist when the project was originally written.

NOTE: If the timeline is confusing, I had already been working in industry for years at this point but was still plugging away at my 4 year degree at night. It eventually took 11 years to complete my BS in Software Engineering.

This evening, as the children slept, I wanted to see if I could run the .NET Upgrade Assistant on this now 20 year old app and get it running on .NET 6.

Let's start:

$ upgrade-assistant upgrade .\TinyOS.sln
-----------------------------------------------------------------------------------------------------------------
Microsoft .NET Upgrade Assistant v0.3.256001+3c4e05c787f588e940fe73bfa78d7eedfe0190bd

We are interested in your feedback! Please use the following link to open a survey: https://aka.ms/DotNetUASurvey
-----------------------------------------------------------------------------------------------------------------

[22:58:01 INF] Loaded 5 extensions
[22:58:02 INF] Using MSBuild from C:\Program Files\dotnet\sdk\6.0.100\
[22:58:02 INF] Using Visual Studio install from C:\Program Files\Microsoft Visual Studio\2022\Preview [v17]
[22:58:06 INF] Initializing upgrade step Select an entrypoint
[22:58:07 INF] Setting entrypoint to only project in solution: C:\Users\scott\TinyOS\src\TinyOSCore\TinyOSCore.csproj
[22:58:07 INF] Recommending executable TFM net6.0 because the project builds to an executable
[22:58:07 INF] Initializing upgrade step Select project to upgrade
[22:58:07 INF] Recommending executable TFM net6.0 because the project builds to an executable
[22:58:07 INF] Recommending executable TFM net6.0 because the project builds to an executable
[22:58:07 INF] Initializing upgrade step Back up project

See how the process is interactive at the command line, with color prompts and a series of dynamic multiple-choice questions?

Updating .NET project with the upgrade assistant

Interestingly, it builds on the first try, no errors.

When I manually look at the .csproj I can see some weird version numbers, likely from some not-quite-baked version of .NET Core 2 I used many years ago. My spidey sense says this is wrong, and I'm assuming the upgrade assistant didn't understand it.

    <!-- <PackageReference Include="ILLink.Tasks" Version="0.1.4-preview-906439" /> -->
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0-preview2-final" />

I also note a commented-out reference to ILLink.Tasks which was a preview feature in Mono's Linker to reduce the final size of apps and tree-trim them. Some of that functionality is built into .NET 6 now so I'll use that during the build and packaging process later. The reference is not needed today.

I'm gonna blindly upgrade them to .NET 6 and see what happens. I could do this by just changing the numbers and seeing if it restores and builds, but I can also try dotnet outdated which remains a lovely tool in the upgrader's toolkit.

image

This "outdated" tool is nice as it talks to NuGet and confirms that there are newer versions of certain packages.

In my tests - which were just batch files at this early time - I was calling my dotnet app like this:

dotnet netcoreapp2.0/TinyOSCore.dll 512 scott13.txt  

This will change to the modern form with just TinyOSCore.exe 512 scott13.txt with an exe and args and no ceremony.

Publishing and trimming my TinyOS turns into just a 15 meg EXE. Nice considering that the .NET I need is in there with no separate install. I could turn this little synthetic OS into a microservice if I wanted to be totally extra.

dotnet publish -r win-x64 --self-contained -p:PublishSingleFile=true -p:SuppressTrimAnalysisWarnings=true

If I add

-p:EnableCompressionInSingleFile=true

Then it's even smaller. No code changes. Run all my tests, looks good. My project from university from .NET 1.1 is now .NET 6.0, cross platform, self-contained in 11 megs in a single EXE. Sweet.


Sponsor: At Rocket Mortgage® the work you do around here will be 100% impactful but won’t take all your free time, giving you the perfect work-life balance. Or as we call it, tech/life balance! Learn more.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service

.NET 6 Hot Reload and "Refused to connect to ws: because it violates the Content Security Policy directive" because Web Sockets

November 16, 2021 Comment on this post [7] Posted in DotNetCore
Sponsored By

If you're excited about Hot Reload like me AND you also want an "A" grade from SecurityHeaders.com (really, go try this now) then you will learn very quickly about Content-Security-Policy headers. You need to spend some time reading and you may end up with a somewhat sophisticated list of allowed things, scripts, stylesheets, etc.

In DasBlog Core (the cross platform blog engine that runs this blog) Mark Downie makes these configurable and uses the NWebSpec ASP.NET Middleware library to add the needed headers.

if (SecurityStyleSources != null && SecurityScriptSources != null && DefaultSources != null)
{
app.UseCsp(options => options
.DefaultSources(s => s.Self()
.CustomSources(DefaultSources)
)
.StyleSources(s => s.Self()
.CustomSources(SecurityStyleSources)
.UnsafeInline()
)
.ScriptSources(s => s.Self()
.CustomSources(SecurityScriptSources)
.UnsafeInline()
.UnsafeEval()
)
);
}

Each of those variables comes out of a config file. Yes, it would be more security if they came out of a vault or were even hard coded.

DasBlog is a pretty large and cool app and we noticed immediately upon Mark upgrading it to .NET 6 that we were unable to use Hot Reload (via dotnet watch or from VS 2022). We can complain about it, or we can learn about how it works and why it's not working for us!

Remember: Nothing in your computer is hidden from you.

Starting with a simple "View Source" we can see a JavaScript include at the very bottom that is definitely not mine!

<script src="/_framework/aspnetcore-browser-refresh.js"></script>

Ok, this makes sense as we know not only does HotReload support C# (code behinds) but also Markup via Razor Pages and changing CSS! It would definitely need to communicate "back home" to the runner which is either "dotnet watch" or VS2022.

If I change the ASPNETCORE_ENVIRONMENT to "Production" (either via launch.json, launchsettings, or an environment variable like this, I can see that extra HotReload helper script isn't there:

C:\github\wshotreloadtest>dotnet run --environment="Production"
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7216
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5216

Remember: You never want to use dotnet run in production! It's an SDK building command! You'll want to use dotnet exec your.dll, dotnet your.dll, or best of all, in .NET 6 just call the EXE directly! .\bin\Debug\net6.0\wshotreloadtest.exe in my example. Why? dotnet run will always assume it's in Development (you literally tell it to restore, build, and exec in one run command) if you run it. You'll note that running the actual EXE is always WAY faster as well! Don't ship your .NET SDK to your webserver and don't recompile the whole thing on startup in production!

We can see that that aspnnetcore-browser-refresh.js is the client side of Development-time HotReload. Looking at our browser console we see :

Refused to Connect because it violates a CSP Directive

Refused to connect to 'wss://localhost:62486/' 
because it violates the following Content Security Policy
directive: "default-src 'self'".
Note that 'connect-src' was not explicitly set,
so 'default-src' is used as a fallback.

That's a lot to think about. I started out my ASP.NET Web App's middle ware saying it was OK to talk "back to myself" but nowhere else.

app.UseCsp(options => options.DefaultSources(s => s.Self())); 

Hm, self seems reasonable, why can't the browser connect BACK to the dotnet run'ed Kestrel Web Server? It's all localhost, right? Well, specifically it's http://localhost not ws://localhost, or even wss://localhost (that extra s is for secure) so I need to explicitly allow ws: or wss: or both, but only in Development.

Maybe like this (again, I'm using NWebSpec, but these are just HTTP Headers so you can literally just add them if you want, hardcoded.)

app.UseCsp(options => options.DefaultSources(s => s.Self())
.ConnectSources(s => s.CustomSources("wss://localhost:62895")));

But port numbers change, right? Let's do just wss:, only in Development. Now, if I'm using both CSPs and WebSockets (ws:, wss:) in Production, I'll need to be intentional about this.

What's the moral?

If you start using CSP Headers to tighten things up, be conscious and aware of the headers you need for conveniences like Hot Reload in Development versus whatever things you may need in Production.

Hope this helps save you some time!


Sponsor: At Rocket Mortgage® the work you do around here will be 100% impactful but won’t take all your free time, giving you the perfect work-life balance. Or as we call it, tech/life balance! Learn more.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service

DotNetConf 2021 - .NET Everywhere - Windows, Linux, and Beyond

November 11, 2021 Comment on this post [5] Posted in DotNetCore | Open Source
Sponsored By

.NET 6 is released and it's a LTS release which means it'll be fully and actively supported for the next 3 years. If you've been paused waiting for the right time to upgrade to .NET 6, it's a good time to make the move!

The .NET Upgrade Assistant can take Windows Forms, WPF, ASP.NET MVC, Console Apps, and Libraries and help you - interactively - upgrade them to .NET 6.

Why bother?

  • Massive and ongoing performance improvements
  • No need to count on .NET being on the user's machine. You can ship you own version of .NET and embed it inside your EXE! Check out Single File Deployment.
  • Tons of new C# 10 features, but they are optional, so your existing code works great but you can also "refactor via subtraction" and check out things like implicit usings.
  • Optional Profile-guided optimization (PGO) is where the JIT compiler generates optimized code in terms of the types and code paths that are most frequently used. This can mean even MORE free performance!
  • Crossgen2 can dramatically improve your startup time
  • Support for macOS Arm64 (or "Apple M1 Silicon") and Windows Arm64 operating systems, for both native Arm64 execution and x64 emulation. In addition, the x64 and Arm64 .NET installers now install side by side. For more info, see .NET Support for macOS 11 and Windows 11 for Arm64 and x64.
  • Hot Reload - just make changes and your app changes...even if you're coding in Notepad!
  • And tons more!

Check out my .NET Conf 2022 video where I see how many places I can run .NET! Windows, Linux, Docker, Mac, Raspberry Pi, even a Remarkable 2 eInk tablet. Enjoy!

 

Be sure to watch and enjoy ALL the great .NET Conf 2022 videos up on YouTube today.


Sponsor: Lob’s developer-friendly APIs make it easy to send a letter, check, or postcard, as easily as email. Design dynamic HTML templates to personalize mail for maximum impact. Start Exploring with Postman!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service

Let's upgrade my main site and podcast to .NET 6 LTS

November 09, 2021 Comment on this post [4] Posted in Blogging | DotNetCore
Sponsored By

.NET 6 is released and it's a LTS release which means it'll be fully and actively supported for the next 3 years. If you've been paused waiting for the right time to upgrade to .NET 6, it's a good time to make the move!

Right now, Hanselman.com and Hanselminutes.com (my podcast) are running on some version of .NET 5. You can se by visiting them and scrolling to the very bottom in the footer as I've added a git commit hash and Azure DevOps Build Number and Build ID to an ASP.NET website and I'm using RuntimeInformation.FrameworkDescription to output the plain text version of .NET I'm using. This blog is on .NET Core 3.0 which is an LTS release but I'll be working with Mark Downie this week to move it to .NET 6 LTS as he's already got his instance of dasBlog running on 6!

© Copyright 2021, Scott Hanselman. Design by @jzy, Powered by .NET 5.0.10 and deployed from commit e5058e via build 20210920.3

OK, let's see what's involved. Let's start with my podcast site. I've got the code on GitHub and running locally with "dotnet run" on the command line in both Linux and Windows. I can run the "dotnet upgrade assistant" which is great, but I also like to drive stick shift sometimes for smaller projects.

I'll update my TargetFramework in my csproj project file from net5.0 to net6.0 and update the major PackageReferences from 5.0.0 to 6.0.0. It compiles.

Optionally, I'll also run "dotnet outdated" which is one of my favorite tools. You'll want to make sure you have a solid test suite and not just do this without testing.

dotnet outdated tells me which packages need updating

I see that some of these are major changes so I can do a diff of these packages with a number of tools, but my favorite is FuGet.org (Thanks Frank!) so I can do a diff between the alpha version of Selenium I'm using and the released see that the RemoteLogs type is now called Logs.

I will also update my Dockerfile and change versions like this

FROM mcr.microsoft.com/dotnet/sdk:6.0 as build

and

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS runtime

I'll confirm that these images build and test. I also run my tests optionally inside a container so that's nice.

Some of my sites use Azure DevOps and others use GitHub Actions. Both use YAML (yay) to manage their config, so I'll update my UseDotNet task in Azure DevOps YAML to version: "6.0.x"

I'll commit and start building in the cloud!

Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: Dockerfile
modified: azure-pipelines.yml
modified: hanselminutes.core.tests/SeleniumTests.cs
modified: hanselminutes.core.tests/hanselminutes.core.tests.csproj
modified: hanselminutes.core/Startup.cs
modified: hanselminutes.core/hanselminutes-core.csproj

$ git commit -m "upgrade to .net 6"

I will also confirm that my Azure App Service is set to .NET 6, but this is only needed if I'm NOT running in a Docker Container or if I'm NOT using a self-contained executable.

Now I repeat this for my podcast and main site and I'm now on .NET 6! The blog (a larger upgrade) is next.


Sponsor: Lob’s developer-friendly APIs make it easy to send a letter, check, or postcard, as easily as email. Design dynamic HTML templates to personalize mail for maximum impact. Start Exploring with Postman!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service

PowerShell 7.2.0 - Could not load type System.Management.Automation.Subsystem.PredictionResult

November 04, 2021 Comment on this post [9] Posted in PowerShell
Sponsored By

My PowerShell upgraded to the new PowerShell 7.2.0 and it happened automatically since I get PowerShell from the Windows Store. However, my fancy prompt use PSReadLine with Predictive Autocomplete stopped working suddenly.

However, suddenly I started getting this error on every prompt.

Could not load type 'System.Management.Automation.Subsystem.PredictionResult' from assembly 'Microsoft.PowerShell.PSReadLine.Polyfiller, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
at Microsoft.PowerShell.PSConsoleReadLine.PredictionViewBase.Reset()
at Microsoft.PowerShell.PSConsoleReadLine.PredictionInlineView.Reset()
at Microsoft.PowerShell.PSConsoleReadLine.Prediction.Reset()
at Microsoft.PowerShell.PSConsoleReadLine.Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics)
at Microsoft.PowerShell.PSConsoleReadLine.ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics, CancellationToken cancellationToken)

Well, you can see I'm using a Beta of PSReadLine 2.2:

### Environment
PSReadLine: 2.2.0-beta2
PowerShell: 7.2.0

But I have failed to keep it up to date, and when I got into this state, I realized just because my prompt wasn't pretty (momentarily) I could update it with one line while still staying on the Beta Train.

Install-Module PSReadLine -AllowPrerelease -Force

Now I'm on 2.2.0-beta4 and all is well and I have my cool prediction history back!


Sponsor: Couchbase Capella DBaaS is flexible, full-featured and fully managed  with built-in access via K/V, SQL and full text search. It’s blazing fast, yet surprisingly affordable. Try Capella today for free.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.