A roundup of .NET 9 release videos
Published by marco on
In November of 2024, Microsoft released a lot of videos about .NET to accompany the release of .NET 9. I watched/listened to a lot of these, with varying levels of attention paid. When something caught my attention, I took notes. These videos are roughly in the other than I watched them, although I reserved the right to shuffle them about a bit to improve grouping.
- AI
- Aspire
- ASP.NET
- Bulletproof ASP.NET Core APIs: The OWASP API Security Top Ten
- What’s New for ASP.NET Core & Blazor in .NET 9
- Exploring the New Fluent UI Blazor Library: Next-Gen Web Components and Architectural Innovations
- I Confronted Microsoft About Blazor’s Future” width=“560px
- Introducing HybridCache in ASP.NET Core
- Easily Improve Web Application Performance using .NET 9 Caching and Redis
- Clean Architecture with ASP.NET Core 9
- New tools in Visual Studio for Web API developers
- Desktop
- General
AI
AI Building Blocks − A new, unified AI layer by Steve Sanderson (YouTube)
The API looks very approachable and straightforward to use. I wish that they would stop papering over the inaccurate responses, though.
At about 17;45, he writes that the additional pair of socks has been added to the cart and that it’s “gone up in the way that it should.” Except that’s not what the response showed. The response showed the total number of pairs of socks in the cart, yes, but it showed the price only for the additional pair of socks that was added in the last step. It noted that this was the case but it was quite confusing to show the total number of items in the cart and then write “the total price for that pair is”, which would confuse a reader into thinking that it was the total for the cart, unless they read carefully. Using language like “total” for a single item is confusing, if not misleading.
This is the kind of stuff that would ordinarily be cleaned up in a final product but it’s doubtful that this kind of stuff will be cleaned up in AI-generated prototypes that are scaled up to production, especially since people that will know how to fix it might become rarer. It will be deemed “good enough” and the inexorable erosion of software quality will continue.
Also, Sanderson had GitHub Copilot running during the entire demo and he pretty much completely ignored all of its suggestions, choosing instead to copy/paste pre-written snippets. This is fine, of course! It’s just that, … why didn’t he just turn off the annoying prompts that constantly plastered completely irrelevant information into his video? It was quite distracting.
Discover the Latest GitHub Copilot Features for .NET Developers in Visual Studio (YouTube)
I suppose this is future of programming? In this video, you can watch a young person ask an AI to add usings
because you have no idea what they are and don’t know that the IDE could just add them for you automatically. She described everything as “awesome” and thought that the interaction loop was super-intuitive and easy to use, as she typed out natural-language command after natural-language command to try to get the machine to do what a programmer could have done in seconds with analysis-based tools.
I suppose if you want to program without knowing anything about the technologies, then this is probably going to get you a little bit further. Maybe. It was pretty painful to watch, though, like someone claiming that they were building a house by throwing wood at bags of cement and hoping for the best.
Building and scaling cloud-native, intelligent applications on Azure and .NET by dotnet | Scott Hunter & Paul Yuknewicz (YouTube)
This is a longer presentation—almost an hour—that goes in-depth on converting an ASP.Net Web application first to an Azure Function, and then adding a .NET Aspire Host project to not only coordinate communication between the front-end client and the Function project, but also to facilitate deployment directly to a Cloud Container.
Hunter explains the different between WithReference()
, which indicates that a service depends on another service being started and WaitFor()
, which extends the reference to indicate that a service should wait until a health-check of its dependency indicates success before declaring itself available. If you think about it, almost all references are important in his way, but .NET Aspire still makes the distinction to give your app flexibility in starting up. If you have two service that depend on each other, they can’t each wait for each other, or you might be a deadlock (unless the health-check can return success before the service itself is ready).
On top of that, there is a method called WithExternalHttpEndpoints()
, which they describe as “doing the right thing” and setting up a virtual private network in the cloud container so that only the web client has access to the Azure Function endpoint. “It’s network-isolated by default, which is one of the features of container apps, which is the default way of publishing in an Aspire application.” This is very cool and seems a lot easier than writing a bunch of custom Bicep code.
The web client can now access the Azure Function at the alias that it assigned in the .NET Aspire host project’s configuration. That configuration is all written in C#, with a nice fluent API. I’m a little disappointed that they don’t use a shared C# constant to reference the unique strings, but nobody in any of the .NET Aspire demos seems to do that, preferring to ride the ragged edge of disaster with copy/pasted identifiers.
Getting back to the demo: He shows how it’s published to Azure, using Managed Identity. The .NET Aspire dashboard shows the remote resources with full logging available, also available and published to Azure. It’s the same dashboard as you would use locally.
Everything they demonstrated is available in several solutions, all listed in Samples for Building and Deploying Cloud Native Intelligent Apps by Paul Yuknewicz (GitHub Gist).
They say, “All you do is clone the repo, and then you do azd init
and azd up
and they’re super-easy to get in the cloud and try yourself.” It will deploy the resources into your subscription and region of choice. There are detailed instructions for each example, e.g., azure-functions-openai-aisearch-dotnet (RAG example).
Paul goes into this example in more detail, examining the Bicep scripts (which I’m not sure whether they’re hand-written or generated by .NET Aspire). They cover how to build an embedding for RAG and how much support there is in .NET now for making this kind of thing easy. They use a standard HTTP body as input but discuss many other potential input streams (queues, etc.), all of which are just as easily supported by default.
I learned that “agenting” is just the cool new term for allowing an LLM to use “tools”. It’s also called “skilling” (adding “skills”). The most approachable epithet is the least-cool-sounding one: “function-calling”, which at least explains what it does. So “agenting” is empowering an LLM to execute tools in order to enhance results.
Like many of the other videos, they use the .http Files feature to store recipes of calls to make against an HTTP server.
When their demo doesn’t initially work, you see how Microsoft also has a locked-down network that they have to work around. They very smoothly transitioned to Scott discussing security initiatives that Microsoft has taken and is taking to lock things down by default for new applications, including those generated by customers. Secure by default. They then smoothly transition back to the demo, for which Paul has reset his network to a working state. Nice job.
The funny thing about some of these demos, though, is that they used an LLM to find out what time it is in New York City…and everyone held their breath to see if it would get it right. It took about 10 seconds to figure it out. That’s laughable on its face, but the point is that it’s now quite easy to set up a powerful tool to round-trip to an LLM running securely in Azure, built with access to custom functions (agenting) and custom data (RAG). Subsequent demos are more impressive.
At 40:00, Paul addresses why it’s interesting to solve problems in this way: you can scale up quickly to much higher data volumes without changing the architecture or implementation at all. This is great but you want to remember the aphorisms, “you’re not Google” and “you don’t have big data.” In this case, though, an argument can be made that these technologies are the right way to build it when its small and when its large. The support and abstractions are good enough that you don’t have to choose a a non-scalable solution early in the process to save money.
On the subject of ignoring warnings in code, though, Paul had a typo in the word “cacluated” that Visual Studio showed him and he still hadn’t bothered to quick-fix it, even though the entire world would be seeing it.
The final example is showing how to use a “blog trigger”, which is a function that reacts when new data is added to an Azure blob container. When you drop a PDF into it, it uses standard, available recognition tools to analyze the document and then funnel that content to the LLM (which is not great at “cracking” PDFs provided as context on its own). These dependent tasks are captured as “activities”, which are composed as part of a “durable function”, which is essentially a high-level abstraction on top of potentially distributed calls.
This is the part that Paul called “orchestration” at the beginning of this section. It’s not orchestration like Kubernetes (although possibly related, way down at the low level), it’s orchestration of high-level activities and representing them as a single function call that takes an indeterminate amount of time. Paul demonstrates how much tooling and web-based observability there is available for debugging and monitoring solutions.
“Again, this is Functions, so you can do this at scale. You can send million of documents.”
It just costs money, but you’re not otherwise limited by the architecture if you build it with these concepts, this architecture, and these building blocks.
Aspire
What's new in .NET Aspire by Damian Edwards and Maddy Montaquila (YouTube)
This addition to the .NET ecosystem continues to impress me. While this video demonstrates only .NET Aspire, the previous video (Building and scaling cloud-native, intelligent applications on Azure and .NET) also made heavy use of Aspire. Many of the videos would include Aspire, actually.
ASP.NET
Bulletproof ASP.NET Core APIs: The OWASP API Security Top Ten by dotnet / Christian Wenz (YouTube)
This is a very useful introduction to common security issues and how to address them. He talks about how to program by default so that the issues never come up.
At around 19:00, he even discusses how to build a threat model. He kind of backs into describing it by talking about the types of risks for which you might need processual mitigations. That is, the threat model talks about something like “the system allows a single user to book multiple seats for themselves on a plane” and then talks about (A) whether you even want to mitigate this and (B) which kinds of mitigations would work against it.
What's New for ASP.NET Core & Blazor in .NET 9 by dotnet / Daniel Roth (YouTube)
This was pretty informative, overall. I wish he’d spent a bit more time on HybridCache
, which seems like a big win.
Oh, hey, look at that: there’s a video for it, called Introducing HybridCache in ASP.NET Core.
Exploring the New Fluent UI Blazor Library: Next-Gen Web Components and Architectural Innovations by dotnet / Vincent Baaij & Denis Voituron (YouTube)
This library is quite nice and seems to offer a good basis on which to start projects. It’s interesting, though, how people just say things that they’ve heard. Denis said at one point that Playwright will be integrated soon in order to improve “code quality”, which is absolutely not what tests do. Tests do the second thing he mentioned: “avoid regression.” If you have tests, your code can be any old quality. The tests don’t care, as long as they’re green.
I Confronted Microsoft About Blazor's Future by Nick Chapsas & Daniel Roth (YouTube)
I mean, honestly, can you just write “interviewed” instead of “confronted”? Do we really have to write everything as if it were a title in a Fleet Street broadsheet? It’s a friendly interview.
- They discussed the difference between .NET LTS and non-LTS versions. There is no difference in quality.
- Why wasn’t there so much Blazor news this year? The .NET 8 release was so huge that they spent a lot of time in the first half of the year after the release simply stabilizing that release, and then focused on quality improvements in .NET 9. There is a big feature that consolidates the different ways of using Blazor into a more uniform concept.
- Who’s using Blazor? How big is it? Year-over-year growth is high but the overall usage numbers are still kind of low, relative to other frameworks, like the by-now ancient WebForms, ASP.Net MVC, ASP.Net Core, etc.
- Is Blazor going to go the way of Silverlight? No, it’s the recommended way to develop web sites on .NET. Nick gave a good intro here, talking about how good WebForms actually was—taking aside
ViewState
—but that frameworks like Next.JS are still re-inventing what WebForms had already offered and pawning it off as a revelation. It’s kind of how most of the server-side frameworks now just look like PHP. - .NET Aspire has a super-short support cycle; it goes obsolete with the first point release. You have to upgrade it rather aggressively to stay in-support. It’s not part of the .NET release. It’s out-of-band. It’s super-useful but it’s a bunch of tools and wiring without much of its own API. It makes sense to keep support cycles short because, while it’s been released for others because it’s so damned useful, it’s also acknowledged that the surface will potentially change quite a bit as more and more real-world use cases appear.
Why do we even need Blazor? Microsoft isn’t using it anywhere, is it? The problem that Blazor solves is trying to build a web site with a team that doesn’t know any of the languages, tooling, or paradigms of front-end development. For the vast majority of web sites, you really don’t need full-fledged React or Angular or Svelte. While there are developers who can legitimately live in both worlds, Blazor is for those for whom a good web site is good enough.
You can make anything in Blazor, of course, but it really helps you get to a standard, good-enough view (especially with Blazor Fluent UI) that covers so much of the software being built. Roth describes how the client-side world is such a different beast and that spinning developers up to be productive and happy in that world takes a lot of time, money, and resources.
It’s a fair point. Many people just can’t wrap their heads around that style of development. It’s too alien to them. I would venture to say that most web developers aren’t very good at software-development, don’t really understand the environment or their tools, and are just cargo-culting their way to freedom and happiness.
It’s why we’ve had so many RAD dev environments, it’s why we have so many frameworks. Even after a good 20 years of development churn, things are still churning. There is almost no consensus on how to address the plethora of non-functional requirements in clients: accessibility, compatibility, graceful degradation, progressive enhancement, etc. The best philosophy seems to be PWA and probably an MPA not an SPA for apps, which is not most web sites. Most web sites are mostly static. So the common web frameworks are ill-suited to those kinds of pages. Etc. Etc. “Blazor lets me get more with less. I can’t afford to hire a full-time front-end developer.”
- Why is .NET trying to do everything? Isn’t that a recipe for being mediocre in most things? “I think it’s fair to say that there are parts of the .NET stack that have … more strengths than other parts.” I think that there’s a real need at Microsoft for doing a lot of things in all areas. MS needs to develop web sites, needs to develop mobile apps, needs to develop cloud-based apps, etc. They’re going to develop at this scale anyway. We can be happy that this workman’s version of these tools are available, and cross-platform. Apple makes some amazing technology that only works on their hardware and on their systems and they don’t have a cloud. .NET runs on AWS, GCP, Azure, etc. .NET runs on ARM, x86, Linux, Windows, MacOS, etc. The base library is incredibly well-designed.
- How big is the Blazor team? There are six full-time devs. It sits atop other parts, like SignalR, which has two full-time devs. The actual framework is six engineers. He mentions that the community does some heavy-lifting here as well.
- Who’s using Blazor? Roth mentions some customers, and then talks about how it’s used in a lot of places internally at Microsoft. They don’t use Blazor for Teams, Office365, large customer-facing products. Those use React. A lot of that is historical, because Blazor has only been around for 5 years. They used to use Script#, which was a transpiler for C# to JavaScript, but then they moved to React. A ton of the recent, internal LOB-style products use Blazor. That’s what it’s for. Smaller teams use Blazor and there are thousands of devs who use Blazor at Microsoft.
Is there anything public-facing that uses Blazor? Very little. The Aspire Dashboard is one of the only things. Part of that reason is “technology fit”. Blazor is very good for internal LOB that runs on a known set of devices and capabilities. Think Office, though: they need to be able to run on anything. That’s a completely different proposition because it constrains you more. You need more control of the stack. A high-level solution like Blazor doesn’t save you time there; it costs you time. For products that need to be optimized in terms of download-size and speed, etc., then you probably should use JavaScript directly.
They recommend Blazor if it fits your scenarios. Otherwise, use ASP.Net Core with a JS front-end. He made the comparison to using Node on the server. It’s not the optimal thing for performance, but it might match your team best. But you can scale the server-side with money. You can’t scale the client-side.
Roth agrees: if you have millisecond-initial-download constraints, then Blazor isn’t for you. He does say that you’d be surprised how many apps aren’t like that.
I’m not surprised. He says that even the heavyweight Blazor server model, which is basically PHP-style, if we’re honest, then you can support dozens of thousands of concurrent users on a single, modestly sized VM. Most apps have expectations of hundreds of concurrent users, at most. Being server-based will restrict your interactivity if you rely on it too much with server-based stuff. For forms and LOB, though? It’s fine. You’re not Facebook. Relax.
- How many people use the web-assembly stuff instead? Quite a few, actually. The server-side Blazor is slightly more popular, though. They’re both growing at about the same speed. .NET 10 plans to invest more in the server-side version. They need to solve some problems about server-side state: hydration strategies for longer-lived processes and workflows.
- What if you had to make an app for millions of users? If it’s B2B or LOB, then consider Blazor. Start with Server-side, then move to interactive server-rendering on the client, move to WASM-based to push individual islands to the client where necessary. If it’s customer-facing, then it’s going to be .NET on the backend and a JavaScript front-end (he doesn’t say “React”, notably). I think MS engineers are also seeing the value in writing to the web platform, using JavaScript. He doesn’t even say TypeScript, because they’re so close these days. It would be amazing if browsers allowed the syntax directly so we didn’t have to transpile anymore. There’s a proposal for this.
- Yeah, but which platform would you use if you couldn’t use Blazor? TypeScript because static typing is awesome. He mentioned that the Angular 18 release was “pretty compelling”. I personally looked into it based on this and couldn’t figure out what he was talking about; it looked like an incremental upgrade to me.
Daniel asked what about server-side rendering? Would you look at Next.JS? SSR? Server-side components? Nick says Next.JS but I don’t agree. I think their solutions, just like Remix, about which I’ve also read quite a bit. Their solutions get … complicated at scale, with their attempts to paper over the difference between client and server parts without being forced to know where anything is running tending to be quite leaky abstractions. I’ve read quite a bit about Remix and Next.JS and, in both of those, I’ve seen where cracks show that people deeply familiar with the technology think “aren’t so bad” but that’s only because they know that it used to be so much worse.
Daniel says “Look around at what is going to be around for a while. Everybody has to plan for the longevity of their career.” This is so sad, though. We don’t get anything great from people “planning for the longevity of their career.” We get cool things from people who just can’t help but try to make something better, to make something cool, to make something to help themselves, that interests them.
Dude, React is a hype. Most people are using it poorly. You get to leaky abstractions in the first two days of teaching, where you have to tell people how to avoid horrible performance with
useMemo()
anduseCallback()
. They’re working on a compiled version of React, which is just where Svelte has always been.What’s next for Blazor? Roth talks about SSR a lot. Interaction between SSR and client-side, etc. Performance and caching. I think Blazor will be a better, more well-thought-out and much less ad-hoc approach to SSR than Next.JS and Remix have gotten.
Why? Because the people that Microsoft has and the culture that they have tend to produce really good APIs. That’s just a fact. Multi-threading feature is on the radar again. They’re going to try again, but it’s not committed yet. Security is the #1 push right now, though. So if Blazor has work to do there, then that takes priority. This will result in a more secure stack for users of Blazor as well.
- If you had to work with a different back-end language, what would you use? Daniel responded “Python”. Nick said “Kotlin”, which he says is how JetBrains fixed Java by making it C#. I would take another look at Swift, which I haven’t used for anything real since version 5. Or maybe finally do something in Rust, just to see where the tooling is at.
Introducing HybridCache in ASP.NET Core by dotnet / Marc Gravell (YouTube)
This video covers Redis, HybridCache, and stampede-protection.
Easily Improve Web Application Performance using .NET 9 Caching and Redis by dotnet / Catherine Wang & Matt Soucoup (YouTube)
Moar caching. Pretty good.
Clean Architecture with ASP.NET Core 9 by dotnet / Steve Smith (ardalis) (YouTube)
I follow this guy’s blog and find many of his articles to be a bit basic. It feels like he’s writing just enough articles to keep his Microsoft MVP badge. In this video, though, he is en fuego, absolutely ripping through a whirlwind introduction to clean architecture, with some demos and some code. You can find the sample projects in NimblePros / eShopOnWeb (GitHub) and ardalis / CleanArchitecture (GitHub).
He also very quickly demonstrates how to use the new API window to submit requests to the running server; this replaces external tools like Postman, keeping you within Visual Studio (or Rider, which has supported this for even longer).
In his full-tilt presentation, he also mentions using Papercut-SMTP, which is “a 2-in-1 quick email viewer AND built-in SMTP server (designed to receive messages only).” This is ideal for local devs to test emailing code and can be easily integrated and started with .NET Aspire.
After having generated a solution using his clean-architecture template, he says that “this is the slowest part … opening the new solution in Visual Studio,” but this is really unfair because the solution is restoring and doing everything in the background, while he’s clicking around in the solution explorer. Previous versions of Visual Studio would never have allowed this. He even launches the product and is browsing around in the Aspire Dashboard and the web server’s OpenAPI front-end within seconds. It’s an impressive demo.
New tools in Visual Studio for Web API developers by dotnet / Sayed Ibrahim Hashimi (YouTube)
Sayed starts off with a good overview of the basics of .http files, which showed up with .NET 8 and allow you to keep sets of API calls for testing, much in the way that people have been using Postman or Insomnia. The new feature is that .http files can now store values in variables for transferring results from one call to others. He uses Visual Studio but, as I’ve noted elsewhere, Rider has supported them for even longer than Visual Studio.
He also shows a not-quite-ready-for-primetime-but-coming-soon feature of Visual Studio called the Endpoints Explorer, which is a sort of Swagger/OpenAPI browser available as a Visual Studio panel.
Desktop
Modern WinForms Development with .NET 9 by dotnet / Merrie McGaw & Klaus Loffelmann (YouTube)
This was quite an interesting video, in that it really drives home that WinForms is here to stay. The community pushed hard to make a lot of the code base expose and use nullability. Microsoft has also improved performance in System.Drawing
and replaced all interop with code generated by CSWin32. There is also improved support on base UI objects for asynchronous calls like Form.ShowAsync
and so on.
I like that his demo to show text in a color-mode-aware manner failed because he was creating the brush with the right color but he wasn’t assigning it anywhere. How do I know he wasn’t using it anywhere? Because Visual Studio had grayed out the instance variable to which he had initialized his brush. He’d assigned the brush but hadn’t actually assigned it to be used by any control. This is why you configure and then pay attention to the warnings and suggestions in your IDE, folks. It really does help you solve otherwise pretty hairy problems. In this case, I was able to diagnose his problem just from a brief flash of less than a second of him scrolling through his file.
It hurts me so much to watch people click toolbar buttons to comment/uncomment code. Seriously, you’re fired.
So, cool video but this guy really shows how outdated some WinForms developers are. 😹
MVVM Building Blocks for WinUI and WPF Development by dotnet / Sergio Pedri & XAML Llama (YouTube)
I learned that the latest preview version of the MVVM Community toolkit is already using partial properties—which are new to C# 12 in .NET 9—to help you write even less code for your view models. Also, you can use x:Bind
instead of x:Binding
to have a compile-time, reflection-free binding, which has much better support for code-completion, inspections, etc.
How Fidelity uses .NET MAUI for Cross-platform desktop by dotnet / David Ortinau, Matthew Faust, & Kevin Bieri (YouTube)
This is a pretty impressive demo of what is now possible with Maui. They’re using Telerik controls. The neat thing about this Maui app is that it runs on MacOS as well. They talk about WebViews a lot—and painting to the canvas—so it also runs in a browser. He does discuss how using SkiaSharp is a valuable place to seek performance but that you are almost certainly going to make usability or accessibility concessions. Use source generators, not reflection. Interestingly, they mention how you can speed things up with Windows Defender by signing assemblies with “HSM methodology”, which is something to look into, I think.
I just can’t help but think that it isn’t any faster or better-looking than the trading app that I was lucky enough to be able to build for Peak6 back in 2010–2013. That one was a multi-threaded Winforms app that connected to a data hose that shoveled tons of data toward the app—dozens to hundreds of thousands of refreshed data rows per second—in dozens of open windows and portals. Each of the grids showed data in grouped, tiered, aggregated, and heat-mapped views. When it really got going, you had 40+ open windows on eight screens, all updating in real-time. Close the app and re-open it and it came right back where it was. it was very, very colorful.
Cross-Platform Magic: Transforming WPF Apps with Avalonia XPF by dotnet / Mike James (YouTube)
This is a great look at Avalonia, which is a very interesting migration path from the Windows-only WPF to a multi-platform approach that doesn’t involve rewriting everything in Maui or Blazor.
With Avalonia, you can either port from WPF, primarily changing the styles to use the more CSS-style styling of Avalonia. Because of this feature, though, an Avalonia app can relatively easily be deployed to a web application. He discusses a community project Avalonia Visual Basic 6 by BAndysc (GitHub), which you can browse in a demo.
It runs in a browser, it runs on all desktop platforms—including Linux, which Maui doesn’t support.
On top of that, it also supports something called Avalonia XPS, which is a complete replacement for the WPF rendering engine, so you can “port” an app just by changing the SDK uses in the project files. That’s it. He demonstrates it live and it works extremely quickly and seamlessly. Of course, if you have P/Invokes or a lot of custom rendering—or external components that aren’t compatible—then you’ll have to do more work. But it’s a huge step forward to getting WPF apps running on other platforms.
For charts, he mentions that SciChart is the “best” charting library for WPF and that it is compatible with Avalonia. They use the XPS layer to provide support for Linux platforms.
His final demo shows a WPF app (the calculator) running with XPS but targeting a web browser. This is wild. I had completely underestimated Avalonia.
General
Advanced Pattern Matching in C# by dotnet / Oli Sturm (YouTube)
At about 8:30, he shows a nice usage of switch expressions with range expressions to make a recursive summing function.
static int Sum(Span<int> l) => l switch {
[] => 0,
[var x, .. var xs] => × + Sum(xs)
};
Nice!
There were a lot of interesting examples in this video. The final one for refactoring a red-black tree was really cool. It’s funny how bad these people are at demos, though. He showed us that he had 513 tests running and passing in 0.5s. Then he says that the passing tests is the only thing that’s important. Um, no, it’s also important that rebalancing is done in a reasonable amount of time, so we should also keep an eye on the time the tests take with any refactored implementation.
To demonstrate that the tests actually test the code he’s going to refactor, he wiped out the enter implementation and re-ran the tests. But they didn’t run because he was no longer returning a value from his method, so it didn’t even compile. He blew right by that and said “see, the tests don’t run.” Um, no, the program no longer compiles and you haven’t proven anything about the connection between the implementation you’re going to refactor and the tests.
All that aside, though, it’s quite an elegant solution that looks just like the original Haskell code. It’s not legible at a glance but is a very succinct representation that uses the standard style for these kinds of things.
Testing.Platform, the new way to run .NET tests by dotnet / Jakub Jares (YouTube)
The Testing.Platform is very nice. It promotes test suites to first-class citizens, built as executable files without any reflection-based assembly-scanning at runtime. Instead, the source generator scans and generates code for running the tests. It also supports a “watch” mode (called “hot reload”, of course), which lets you keep the tests running as a separate app. It’s much faster and more reliable, it’s AOT-friendly, etc. etc.
When it was initially introduced in January of 2024, the only drawback was that you could only use it with MSUnit. That’s changed! At 23:00, he shows how to enable and run NUnit-based and XUnit-based tests with Testing.Platform. I really, really like how MS-based projects like this embrace open and non-Microsoft standards: the testing platform is to replace VSTest, which only ran on Windows. Testing.Platform is platform-agnostic and testing-framework-agnostic, bringing its Reflection-free, AOT-capable, runtime-stable approach for everyone.
He demonstrates running a solution with NUnit, XUnit, and MSUnit tests running as a standalone, collectively with dotnet run
, and in Visual Studio. Rider / VSTest writes “JetBrains Rider can run tests from any custom test framework that uses VSTest or Microsoft.Testing.Platform.” ReSharper / VSTest writes “ReSharper can run tests from any custom test framework that uses VSTest or Microsoft.Testing.Platform.”
Good news all around. This thing is ready to be used!
Modernising Legacy .NET Codebases with NDepend by dotnet / Goh Chun Lin (YouTube)
I really like the tool NDepend and I was quite interested to see how Lin used it to upgrade a codebase from .NET Standard 2.1 to target .NET 8, and then .NET 9. He’s from Singapore so he was not easy for me to understand—but he definitely knows what he’s doing.
This video reminded me of a time about 9-10 years ago when I was really heavily using the tool to modernize the Quino code-base, which had grown quite organically and was proving difficult to use for only web servers, especially those running on Linux. We made our own journey from .NET Framework 4.7.2 to .NET Standard 1.0 (didn’t work at all), then to .NET Standard 2.0 (success!). I continued to use the tool for the next five years.
Here is a list of related articles, which I argue go into more depth on how to use NDepend than the video does. NDepend hasn’t changed a significant amount in 10 years—it was an incredibly powerful tool then, and it still is. I haven’t used it much at my new job at Uster but time will tell.
- 2014: The Road to Quino 2.0: Maintaining architecture with NDepend (part I)
- 2014: The Road to Quino 2.0: Maintaining architecture with NDepend (part II)
- 2015: Splitting up assemblies in Quino using NDepend (Part I)
- 2015: Iterating with NDepend to remove cyclic dependencies (Part II)
- 2018: The Road to Quino 2.0: Maintaining architecture with NDepend (part I)
- 2019: Finding deep assembly dependencies
F# − Nullable Reference Types by dotnet | Petr & Tomáš Grošup (YouTube)
This is by far the nerdiest video in the entire series. It’s chock-full of interesting information about F#, with a focus on the new support for null
, which it has in order to better interoperate with .NET modules built in other languages that do support null
. F# is a functional language and uses options. However, Tomáš demonstrates how this is not sufficient when working with data coming in from outside of the F# system. The feature piggybacks on the |
-operator to allow | null
in any type definition.
Most of the rest of the presentation shows how the new feature integrates with options, pattern-matching, generic types, etc. There are analyzers in the compiler that help your code shed “nullness” as soon as possible, leaving most of your F# code without nulls, as God intended.
Tomáš calls “shadowing” a feature, which is being a bit generous. It’s a nice trick to declare a “new” version of the incoming argument that has a type narrowed by a null-check function call. Languages like TypeScript and C# actually have a “feature” in which the type is narrowed without variable-shadowing. It amounts to the same thing, though. I suppose F#’s version is less gimmicky and implicit, but shadowing is frowned upon in so many other places, because it’s super-confusing when done inadvertently. Using shadowing to narrow a type is a clear use case but it will also prevent analysis from being able to preclude accidental shadowing.
This video is mostly just an F# tutorial, though. At the end, a guy named Kinfey pops in to tell Tomáš that he better wrap things up. It’s quite unprofessional but also quite funny.
Embedding Python libraries in .NET services and applications by dotnet | Anthony Shaw & Aaron Powell (YouTube)
This isn’t the most organized demo, and they don’t really show how to set things up but it does show how integration of Python into .NET is much simplified by source generators that generate bindings for marshaling data to and from Python.
Not only that but .NET Aspire is indispensable for configuring a system like this, not only for tying together the moving parts—PostgreSql, Python API, web front-end—but also for monitoring not only the startup but also API executions, which you can track in a nice process-graph for each request (shown below).
.NET Aspire for CSnakes / Python
It even shows how the chart is rendered in Python, returned as bytes to C# and then rendered into the body of the response directly (basically sending back an image rendered in Python without conversion).
Unlike previous attempts like IronPython, this approach uses .NET Aspire to simplify integration of Python projects and code without changing it. It just integrates it, like taking care of setting up the PostgreSql database and then passing the connection string to the Python code.
Anthony discusses at the end how the common data types used in Python ML processing (tensors, etc.) are all supported in an efficient manner, allowing you to pass buffers back and forth from Python to .NET and offloading code like web servers and GUIs to .NET development while benefitting from existing Python libraries.
I imagine that this is just an interim solution until the .NET ecosystem catches up more with Python—which it is definitely going to do, if it hasn’t largely done so already.