The Modern .NET Show

S06E22 - Navigating the ASP .NET Core Maze: From Middleware to Minimal APIs and Modern C# with Andrew Lock


Support for this episode of The Modern .NET Show comes from the following sponsors. Please take a moment to learn more about their products and services:

Please also see the full sponsor message(s) in the episode transcription for more details of their products and services, and offers exclusive to listeners of The Modern .NET Show.

Thank you to the sponsors for supporting the show.

Embedded Player

S06E22 - Navigating the ASP .NET Core Maze: From Middleware to Minimal APIs and Modern C# with Andrew Lock
The .NET Core Podcast

S06E22 - Navigating the ASP .NET Core Maze: From Middleware to Minimal APIs and Modern C# with Andrew Lock

Supporting The Show

If this episode was interesting or useful to you, please consider supporting the show with one of the above options.

Episode Summary

In this episode of The Modern .NET Show podcast, Andrew Lock shared his expertise in ASP .NET Core. Lock delved into the concept of minimal APIs, a new paradigm for writing APIs in ASP .NET Core that aims to minimize ceremony and simplify the development process. By utilizing filters and metadata, developers can enhance the functionality of their minimal APIs, adding validation, authorization attributes, and OpenAPI descriptions to their endpoints. This approach streamlines the development process and reduces code duplication, making it easier to manage and maintain APIs.

Furthermore, Lock highlighted the evolution of minimal APIs in ASP .NET Core, with improvements made in versions 6, 7, and 8 to enhance developer experience and performance. The transition from ASP .NET Core 5 to 8 has been smooth, with easy upgrade paths and optimizations in the .NET runtime, such as profile-guided optimizations (PGO), making apps faster based on user usage patterns.

The episode also touched on the latest edition of a book on ASP .NET Core, which covers essential concepts such as minimal APIs, Razor Pages, and MVC for building applications. The book incorporates modern C# features like records and required modifiers to introduce readers to new programming concepts and improve their coding skills.

Overall, the discussion provides valuable insights into the middleware pipeline, minimal APIs, and the latest advancements in ASP .NET Core development. By exploring these topics in-depth, developers can enhance their understanding of ASP .NET Core and improve their skills in building efficient and effective APIs.

Episode Transcription

Yeah, exactly.

And it means you can, if you see it in its sort of native place, next time that you’re writing something, maybe you don’t go and change all your IEnumerables to IAsyncEnumerable because that’s not worth doing. But maybe next time you’re writing a new API you’re like, "oh, you know what, I will use that newer API because it will give me better performance. And when I’m writing it, it’s easy to just use the new thing and it’s more applicable to this situation."

- Andrew Lock

Welcome to The Modern .NET Show! Formerly known as The .NET Core Podcast, we are the go-to podcast for all .NET developers worldwide and I am your host Jamie “GaProgMan” Taylor.

In this episode, Andrew Lock joined us to talk about ASP .NET Core’s new Minimal APIs paradigm. Along the We also talked about validation, and the third edition of his book “ASP .NET Core in Action” from Manning Publishing.

So it’s sort of interesting, the philosophy, because obviously validation was one of the things they had some pushback.

In MVC You’ve got validation there by default, and clearly you always want to have validation of your arguments. So why didn’t they include it in minimal APIs? And the answer basically is because there’s more than one validation framework. There’s the data annotation attributes… but then there’s other frameworks like the fluent validation, for example, is a very popular one. And the only way that works in MVC is you have to sort of try and plug it in as an extra part and remove the old validation. And they didn’t want to prioritize any particular style of doing validation.

- Andrew Lock

So let’s sit back, open up a terminal, type in dotnet new podcast and we’ll dive into the core of Modern .NET.

Jamie : So, Andrew, thank you very much for spending some time with us all today, being back on the show after I think about five years. So welcome back to the show.

Andrew : Thank you very much. Thank you for having me on.

Jamie : No worries. No worries.

I’m always interested to speak to anyone who wants to speak .NET, any of the .NET technologies. And, you know, you’re one of these folks who has a book and everything. And I do remember when the first edition of the book came out, I was telling everyone, “you need to go buy this book because the stuff in there that you haven’t done with it, ASP .NET, and it will teach you how to do it.” So, you know, one of those sales might be because of me.

Andrew : I appreciate that. It’s always, always good to know. I’ll give you your commission later.

Jamie : Yeah, the check’s in the mail, right?

Andrew : Yeah, exactly.

Jamie : Excellent. Excellent.

So I guess for the folks who haven’t heard the previous episode of the show from, I think episode 17, I’ll put a link in the show notes if folks want to check that out. For the folks who haven’t heard that one, I was wondering, could you sort of introduce yourself, give a bit of elevator pitch to Andrew, what he’s about, the kind of work he does, that kind of thing?

Andrew : Sure. Yeah. So, yeah, my name’s Andrew Lock. I am a software engineer at Datadog. I work on the .NET client library, which is all to do with distributed tracing and things like that. Generally, I like ASP .NET Core. I’ve been sort of working with it since its inception. And I blog about it a lot. My blog

And yeah, apart from that, I live in the Devon in the UK, like going running on the coast, and that’s about me.

Jamie : Cool, cool.

Okay, so I know that the, one of the main topics of our previous conversation was about the middleware pipeline in ASP .NET core. And I was wondering, just for the folks who perhaps haven’t heard that one or haven’t had a chance to think about that for a while, I wonder, could you give us a really quick sort of brief reintroduction to the middleware pipeline?

Andrew : Sure. Yeah.

So this was, this sort of design of a middleware pipeline is something that, it’s in a lot of different software stacks. I think node is one of the originators. It was also in the old OWIN version, which is almost like the precursor to ASP .NET Core. And it’s basically a series of modules that stack together to process your HTTP request.

So your request comes in, it goes from module to module to module. So each of those is a piece of middleware, and they’re all connected together, and it goes essentially through the pipeline until something sends a request or something writes a response, and then it goes back through the other sort of back out of the middleware pipeline. So it travels through all of those modules in reverse, and it’s a way of doing lots of sort of cross cutting concerns. So the pipeline consists of modules of middleware, which is basically just a class or a function, which executes, runs against the request until something generates a response. Once it’s generated a response, it goes back through that pipeline. And so each module, each middleware gets a chance to inspect the response and all the way back out to Kestrel, which is the actual server, which then sends it back to the client.

Jamie : Right. Okay. So the way that I’m envisioning it. And obviously, feel free to correct me if this isn’t the right metaphor, but then every metaphor is different for everyone else. I’m thinking like a. almost like an assembly line on a factory floor, right? You’ve got a conveyor belt, which is your pipeline, and maybe a request comes in, some. Something is placed on the conveyor belt, and as it passes to each person along the conveyor belt, they can do something to it or read something from it. And then, just, it doesn’t work because the metaphor falls apart, because at some point, someone can place that thing on a different conveyor belt, sending it back the way it came. I don’t think that’s exactly…

Andrew : I mean, that does fit with how it works. That’s certainly perfectly reasonable. The other metaphor is, like, nested dolls, because you have, like, the outer doll is the first middleware, and then it passes it in deeper and sort of give that feeling of getting deeper and deeper inside the application before it then makes its way back out again.

Jamie : Okay. Okay. That makes sense.

And, of course, I mean, this is a leading question, right? Because I’ve done loads of work with ASP .NET Core. But just so that folks who are listening, if they don’t, you know, if they don’t think to ask this, it is the order in which you add those middleware, processors, items, classes—whatever we call them, we’ll come to that in a moment—the order in which you add them is the order in which they are processed, right?

Andrew : Exactly. That’s a very important part of the middleware pipeline is that it is ordered. And one of the designs when you’re actually building your middleware pipeline is like you say when you call the method, AddStaticFiles(), AddAuthentication(), AddMiddleware, the order you make those calls is the order that the pipeline is going to be built as. So you do have to be careful. You can’t just throw the add method somewhere in there like when you’re adding services to dependency injection. In general, it doesn’t really matter which order you add them because it’s all going into the same container. That’s not strictly true, but generally it is. Whereas with middleware it very much has to be specifically ordered.

And the core libraries themselves. So ASP .NET Core itself also adds some middleware automatically to the pipeline at the start and at the end. And part of the reason for that is to try and avoid you adding them in the wrong way. So things like you have to add the authentication middleware before you do the authorization middleware because the application has to know who you are before it can decide what you can do. So there’s various checks now in ASP .NET Core to make sure that you are adding these things in an order that makes sense.

And also, like I say, they automatically add some to try and avoid you adding them in the wrong place by default.

Jamie : Sure, that makes sense.

So just as a trivial example, if my middleware pipeline consists of some kind of authentication and authorization and static files, if I add the authentication authorization first, then static files, unless I am authenticated and I am authorized to see the view [or] access, whatever I’m looking at, I won’t see those static files. Right. Because I need to be authenticated and authorized before I can see those files.

Andrew : Exactly. And there’s some nuance to that, because that assumes that you have an authorization policy that you have applied to the static files, which is relatively unusual, but I don’t think it’s something you couldn’t do. And so yeah, to give your example, that is exactly right. You have to go through those other middleware in order to get to the static files.

Jamie : Sure. Yeah. Well, my example was one of those trivial silly, I couldn’t think of two things that you would have back to back.

How about this then authentication authorization, and then maybe OpenAI/Swagger. If you do it that way, then you will need to be authenticated in order to see the Swagger generated documentation, right?

Andrew : Yes, exactly. Yep, you can, certainly.

Jamie : Whereas if you did it the other way, you could see the Swagger, or the Swagger generated documentation and not have to worry about authenticating until presumably whatever is on the Swagger documentation, whichever controllers and actions, if they have the authorized attribute, I then can’t use those API endpoints until I’ve authenticated.

Andrew : Exactly.

And so another part of that is thinking about, it’s thinking about the order that you want things to happen because there’s certain performance implications as well. So having authentication/authorization, you probably wouldn’t want to apply that before your static files, if your static files never need authentication and authorization. So you don’t want to be doing all that extra work just to download some CSS files.

Jamie : That makes sense.

So I’ve now got in my head building APIs using Factorio. Again, it’s that production line. Right. So you’re placing things—I don’t know if you or any of the listeners have played the video game Factorio, but it is quite literally, you know, if you boil it down to its basics, it’s building a pipeline of actions to be taken with some resource. So I’m thinking, "hey, I can build my API in a Factorio-like way."

Andrew : Exactly. Yeah. I haven’t played with it because I heard it was too addictive, but yeah, that, exactly, that sort of factor, like you said, a pipeline of actions to take is definitely the view you need of it.

Jamie : Cool. Okay, excellent. So yeah, that’s a cool, nice little 10,000 foot view of middleware pipelines. Do, obviously, listeners do go back and listen to episode 17 because we get into it and talk about it a lot, but that’s the basics of it.

So you have, we mentioned earlier on there’s ASP .NET Core in Action, which is a book that you’ve written, but there’s now a third edition. So let’s talk about that first. So what is, what’s, what’s the, I feel like I’ve been asking a really silly question here, but what’s the book about?

Andrew : So fundamentally, it’s about ASP .NET Core and how you use it. And it builds up from the beginnings of you don’t know anything about ASP .NET Core and includes a variety of topics around ASP .NET Core. It doesn’t cover everything just because it’s such a huge topic and there’s so many sort of branching areas, but it’s designed to get you up and running, and goes into quite a lot of detail in some bits. So it’s quite a broad range that it should cover.

Jamie : Right, okay, so you’ve said there it’s useful for people who’ve never touched ASP .NET Core, right? So perhaps if I’ve done aspect ASP .NET "classic," I’m worried about putting the word classic there. But ASP .NET classic, or maybe I’ve built APIs with JavaScript and I’m okay with writing C Sharp. Is that kind of the target audience?

Andrew : Exactly. That’s pretty much bang on. If you’ve been using ASP .NET before, this book will be great for you. It’ll cover the basics of HTTP, which you’ll probably already know, so you can just skip over some bits of those. If you’ve not written any web applications at all. So you’ve just known C Sharp because you’ve been doing, I don’t know, desktop applications or something, then it covers that.

If you’ve, like you say, if you’ve been writing applications in Java so reading C Sharp isn’t too difficult, then it’s designed to cover all those sort of, those sort of bases. So you’re a beginner but not a beginner programmer. I’m not trying to teach C Sharp in here because that’s again a whole new topic. And so I like introduce some modern C Sharp bits in there and just sort of sprinkle them around for people who haven’t seen them before, things like records and required modifiers and things like that.

But in general it’s intended for people who are beginner to intermediate that sort of level.

Jamie : Okay, cool. So then I guess what’s… if someone’s listening in and they’re like, "well, I bought the first edition and what’s different with the third edition?" So Andrew, what’s different with the third edition?

Andrew : So the first edition I started pretty much before ASP .NET Core was fully released. So it was like the 1.0, and then it was released around 2.1. The second edition I updated everything to .NET Core 3.1 because there were some big changes between 2 and 3.1.

And in this one it’s updated to .NET 7, which is no longer the current release of .NET, but they’re close enough that essentially everything in there is still perfectly valid.

In terms of what’s changed, .NET 6 had a big paradigm shift in how the default experience for building ASP .NET Core apps was. So we moved from the traditional program.main and startup class to using a more minimal startup, or not startup, minimum program.main, which is like the GenericHosts, using top level statements, global usings, and the new WebApplicationBuilder.

And on top of that, we started using minimal APIs as a new paradigm for building APIs. So it’s very much focused on introducing minimal APIs using all of new paradigms. And yeah, that’s the biggest change to it. It changes the whole structure of how you teach ASP .NET Core.

Jamie : Right. Yeah, because like I was, I remember when they brought out that—I don’t know the official title for it, but if folks do a dotnet new consoleapp, you get a one-liner, right, instead of the eleven lines of cruft that go around it for the namespace and the using statements and the class main—or class program. Sorry, public static void Main, none of that, that’s not visible. It’s still there in the background because the compiler still throws that in for you for through compiler magic, but it’s no longer required. Right.

And I remember when they brought that out, I was like,. "holy moly. This is a huge paradigm shift for a) people getting started in this, but also b) people like Andrew who are writing books: their program listings in the books now don’t have to be three sets of tabs or three groupings of spaces deep," saves loads of space.

Andrew : Exactly, exactly. It’s so much nicer.

Like having namespaces as statements instead of having the big curly brackets so everything can just shift back in its indents. It’s so nice. Yeah.

And that’s, that niceness was mostly just sort of pretty things up. It wasn’t functionally much different, but it really does help, I think with people who are new to language there’s just so much less to see when you get started. There’s so much you have to try and understand. There’s so much less that you have to, you know, navigate through, you have to look up to figure out what it is. And like you say with teaching, it makes it a lot easier. You can just focus on the actual content, which is what you’re particularly interested in.

Jamie : Absolutely, absolutely. I remember trying to teach someone some C Sharp back in the .NET 3.5 days… the .NET Framework. Sorry, 3.5 days. And we did a "Hello, world!" and I’m like, "right, okay, ignore all of the usings, ignore what a public class is, ignore what a public static void Main(string[] args) is, ignore all of that. We just want to look at this one line."

"Yeah, but why do we need to ignore it?"

"We need to ignore it because none of that is required yet. I’m going to get you to print something to the screen," you know.

Andrew : Exactly. And so you can just, you can just skip all that now, which is, it is very nice.

And there was a lot of people, I was one of the, "who moved my cheese?" initially. And it’s like, "well, how will I know where my program main is if it doesn’t say program main?" But it’s one of those things that conventions help. So program.cs is still the file. You still know to look in program.cs. And that’s one of the biggest things. It’s just getting used to it.

Jamie : Absolutely. And that’s the thing. Whenever a new thing comes along, it is just a case of getting used to it.

I feel like I might be wrong about this, but I feel like up until recently you could still use the old, the older style, the more explicit style of throwing all of that back in there. All of the using statements are namespace, public class, public static void Main. You could still do that at some point during creation time. I’m sure you could. But even so, you could put it back in yourself, right?

Andrew : Yeah, I think the templates still let you use non-top level statements and I think the usings, you can disable the global usings so you can put all those back in if you want to. But I think it’s one of those things where after you’ve tried it for a while, you’re not going to go back. It just doesn’t seem worth it.

Jamie : Yeah, sure, sure. And I feel like with some, how do I put it?

When something is as long lived as all of the .NETs and ASP .NET Core, and things like that, there’s eventually going to be a version where nothing changes on the outer layer. We’re looking at it and it doesn’t look different, it’s just functionally different, but we’re not seeing it. When you get those wonderful blog posts by Stephen Toub, those ones that I read through and get about five sentences in and go, "I’m lost."

Andrew : Exactly, exactly.

And honestly, that’s one of the really nice things from I think .NET 5 to 8 so far have just been really simple to do upgrades for. There’s obviously lots of edge cases you have to hit for, but for ASP .NET Core, if you’re just doing bog standard stuff, you can just update your to the latest version by going changing the TargetFramework in your csproj file and you can go 5/6/7/8 and really it should just be working. Not much has been braking changes.

There’s been lots of additions, like a huge number of additions, like minimal APIs for a start. They weren’t in .NET 5. So there’s lots of extra things you can do, but you don’t have to change, which I think it’s really nice for stability for .NET.

Do you have a WPF application and want to take it to macOS or Linux? Avalonia XPF, a binary-compatible cross-platform fork of WPF, enables WPF apps to run on new platforms with minimal effort and maximum compatibility.

With a few tweaks to your project file, your WPF app and all its dependencies are ready for testing on new platforms.

Start your app transformation journey with a 30-day free trial.

Head over to to get started today.

Jamie : Oh, definitely, definitely.

Because that upgrade path is so easy, you get all of the optimizations for free. You know, I remember I was talking to someone about Ryujinx, which is a Nintendo Switch emulator, partially written in .NET. I believe it’s all written in .NET, I might be wrong. It’s been a while since I talked to the chap. And he was saying, sorry, rather. Yeah, yeah. I checked his gender identity when we were recording. So he was saying, "essentially what you do is you jump into the csproj, you change the, that number, and suddenly your app gets a little bit faster because the stuff underneath your code is running way more efficiently."

Andrew : Exactly, exactly.

And there’s changes to the .NET runtime in .NET 8. So things like they’ve got added PGO—profile guided optimizations. So your app, it’s not even just like the C Sharp gets faster, it’s literally how you’re using the C Sharp in your app. So specifically, the JIT compiler watches how your app is executing and makes it faster, which is just really quite impressive.

Jamie : It’s wizardry, isn’t it? That’s what it is. Or magic. I don’t know.

Yeah, the runtime can make your app faster based on how your users are using it. It’s just, it’s mad.

Andrew : Exactly. Yeah.

Jamie : Brilliant.

Okay, so, so the new things with the third edition is maybe switching over to the new style of writing. C Sharp apps, .NET apps, possibly. I’m just gonna, you know, you mentioned things like records and stuff in the previous, in the versions of .NET that bring us up to now. So I guess, are you using records and things like that?

Andrew : So essentially, I’ve used most of newer APIs. So there’s things like in .NET 6 they introduced a new way of doing configuration with the ConfigurationManager. So the new book uses all of the new ways to do that, using OptionsBuilder to create your IOptions types, things like that.

And then I’ve sprinkled some various newer C Sharp features like records and things around, just because you’ll need to get used to seeing them, even if you’re not like, "I really want to use these new C Sharp features," people will be using them in apps. I mean, that’s one of the, one of the concerns people have about C Sharp moving so quickly. Is like all of the new features and I think just getting used to seeing them is part of the battle, just normalizing that.

So I haven’t really gone hard on them. I’ll introduce them, I’ll explain what they are and they’ll just be around in various places where it makes sense.

Jamie : Yeah, that totally makes sense.

I remember talking to a number of developers when things like IAsyncEnumerable came out and they were like, they sort of threw their hands in there air and said, "oh man, now I have to rewrite everything!"

And I’m like, "no you don’t. It’s another tool in your toolbox. You know, if you want to write something that uses an IEnumerable and needs to be async, you can use that. And then instead of having to wait for everything and all that kind of stuff, you can just, it’s not a problem, don’t worry about it, you don’t have to use it."

But like you said, being sort of I guess exposed to it helps to, and I hate this phrase in this context, but like soften the blow I guess, of the new thing.

Andrew : Yeah, yeah, exactly. And it means you can, if you see it in its sort of native place, next time that you’re writing something, maybe you don’t go and change all your IEnumerables to IAsyncEnumerable because that’s not worth doing. But maybe next time you’re writing a new API you’re like, "oh, you know what, I will use that newer API because it will give me better performance. And when I’m writing it, it’s easy to just use the new thing and it’s more applicable to this situation.". So having that in your tool belt I think is just important, like knowing what you can use.

Jamie : 100%. 100%, because otherwise if you don’t know it’s there, you’re never going to use it. Right?

Andrew : Exactly, exactly.

Jamie : Cool. Okay.

Let’s have a quick chat about things like some of the new or newer ASP .NET core features then. I mean, we brought up a whole bunch already. We talked about middleware at the beginning. Folks do go back and listen to episode 17. There will be a link in the show notes for a full description of middleware. But I thought maybe we could start with something like minimal API’s because I know from my own sort of developer testing and by that I mean I’m talking to other developers. "Hey, have you heard of this? Hey, have you heard of that?" is that the name "minimal APIs" for some people seems to like imply that it’s minimal functionality, but I feel like that’s not quite right.

Andrew : Yeah, exactly.

And so minimal APIs are a new paradigm for how you write APIs, which was, it was introduced in .NET 6 [and in] .NET 7, they really added a huge number of features which actually made them sort of usable in my opinion. [In] .NET 6 they were nice and they could do for very simple apps. You would probably be able to get away with them. But for .NET 7, they really have just way more functionality with filters and things like this, which you can come to later.

But in essence, minimal APIs are designed to be similar to MVC APIs in some way. Like they are just an HTTP endpoint that you can return primarily JSON from. That’s where their sweet spot is designed for JSON. And then they’re designed to be minimal ceremony so they’re easy to write. You don’t need to have a separate class with separate methods and using dependency injection into constructors and all this sort of thing, you can just write a lambda function and that could be it. It could be as simple as that.

You can go a lot more complicated, but you don’t have to. And the sort of the philosophy behind them is that they’re supposed to be basically as fast as possible. They’re doing all of the extra code for extracting root parameters from your roots and converting JSON bodies into objects, just like you get with MVC. But instead of the MVC style of you have a huge number of filters which run all the time and it does all this extra work. The idea with minimal APIs is it’s doing the exact, it’s making the code that you would do if you’re doing it the most performant way, but it’s doing that for you. So it’s a really nice, quite clever way they’ve done it, but to use it, it just makes it very simple.

Jamie : Sure. Yeah. And whenever I’m looking at something that’s built as a minimal API or has a number of minimal APIs. So I have a question about that in a moment. It looks very similar to me to Express.js where you can just do like app.Get() and then write a function that deals with the GET request for that URL. It looks very, very similar.

Andrew : Exactly. It was very very much inspired by that Node and also the Nancy style of the old. So that’s an open source .NET library called Nancy and there’s a newer version called Carter and it’s essentially very much inspired by those. And the node style of doing it.

And it’s something which if you are coming from an MVC style, is quite different, but it’s very easy to understand, like looking at it, you can generally understand what is saying quite simply.

Jamie : Yeah, that was, that was kind of the thing that I never really fully understood when I was building just web APIs. I was like, "what? Hang on. So I have a model, a controller and a view. I don’t need the view. Okay. So do I really need a separate file for all of my, like a controller and whole bunch of APIs that will," that I’ll be poking at and I’m glad that I can use both, but I don’t have to use that controller, I guess. Controller model and controller view. No, hang on, that model and controller pattern. Sorry. Because views don’t make sense in APIs. Right.

Andrew : Depending on how you look at it, yeah. I mean I sort of view the object you return as your, as your view in APIs. If you want to think of it as the MVC, it fits so similar.

But minimal APIs, they give you that flexibility. You can, in all the demos they write app.MapGet() inside the program.cs, whereas in reality if you’re actually building an app, you won’t put all of your minimal APIs into one file. Which is another misconception people have is that you just write everything in the one file, which no one’s going to do in practice.

So basically you can encapsulate that however you want. If you have a whole bunch of APIs about your orders or your products, you can move those all to a separate file and you can register all those in this order, service, app, modifier, whatever you want to call your class, which adds all these APIs. But the point is, it’s up to you. It’s very simple. It’s a very simple API to use. You can control it how you want.

Jamie : Yeah. And I suppose that’s one of the good things about it, being not un-opinionated, I guess, but slightly less opinionated. You know, you’re not having to go, "you will build it this way, and have to build it this way." You know, giving, giving devs a bit of freedom as to how they might implement things is always a boon in my opinion.

Andrew : Yeah. I mean that in itself is somewhat controversial because I think some people like to have the very strong opinions where they’re like, "just tell me how to build my app, tell me what to do so I can go and do it," which I think is almost like why MVC was so popular in some ways. It’s like models go here you create a separate, you have your orders controller, which is where all of your orders methods go.

The trouble is, that’s where you get into dogma, basically. You’re not doing it because it’s better, and you end up with these giant controllers with thousands of lines of code in them and things like this. So it’s giving more flexibility to users with minimal APIs, which I agree is a good thing. But there’s still, you still have to make a decision. It means it’s on you. Like, how do you want to organize your APIs? How do you want to register your APIs? How do you want to share code between them?

Jamie : Yeah, and I think, I think that makes perfect sense because then it’s then, like you said, it becomes a decision for the developer, "where do you want to put these things, how you want to share these things, how do you want to share information between them and things like that. How are you architecting your app?"

Like I said, from my point of view, it’s a great thing. Giving the power of how do I design my app back to the developers can only be a good thing, in my opinion. Yes. I guess it means for perhaps people who are coming new to it, they might fall into that trap of, "just tell me how to build it." But I guess once you’ve gone through a few tutorials or once you’ve built, you know, a maybe a todo app or maybe something slightly more useful, you kind of get into the swing of, "oh, right, yeah, I can, I can understand why perhaps they’ve split this out and why I need to have this thing over here and this thing over there." Right.

Andrew : Exactly, exactly. I think that’s the key. And when you’re getting started, the key thing is you don’t need to think about, "where am I putting APIs?" You can just stick them in, in program.cs. If you’ve only got two little demo APIs, don’t worry about it, just put them there. You don’t have to think about it. Which is one of the, it is one of the really nice things about that.

And then when you’re getting a bit more advanced, you’re building things, things are getting more complicated. You’ve got 100 lines in your program.cs. Then you can think, "oh, maybe I’ll just move these to a separate file." And if you’re using a modern IDE like Rider or Visual Studio, then there’ll be little helpful "extract to separate class" methods and stuff like that.

I very much like the flexibility that comes with it and it means you can build up other frameworks around it as well. So there’s a framework, I’ve been blanking on the name at the moment, but it connects mediator to minimal APIs directly. So it builds essentially a framework on top of minimal APIs. It just gives you all that extra flexibility whichever way you like to build your apps.

Jamie : Yeah. And that all makes sense. And I really like this idea of if you want to use min… so one of the things that I’ve used minimal API for, right, is throwing together MVP’s of like, "I think it needs to look like this, just quickly, just throw it all in the program.cs and let doesn’t matter, it can be, you know, 150 lines long because I’m just testing out is this where I want it to be." Rather than having to go, "right, okay, right-click, create folder, controllers. Right-click, create class, MyController.cs." And then adding all of that ceremony. And then I get to that point, I’m like, "wait, hang on, what was I doing?"

Andrew : Exactly, exactly. It just means you can just focus on just churning out what you need to initially and then refactor later. I mean that makes total sense.

Jamie : Excellent. Okay.

So in the book are you covering things like Blazor and things like that? Because obviously the way I understand it is that Blazor, whilst it is a separate thing, it’s also part of ASP .NET Core; because it’s also part of Razor, which is what MVC is but not isn’t it. Isn’t that any more. But it is. I get confused.

Andrew : Yeah. So yes, absolutely. Blazor is part of Asp .NET Core. I don’t cover Blazor at all in the book. And I’ll put it this way, it’s 1000 pages without Blazor. So if I had Blazor in there as well, it would just be, there would be far too much.

Jamie : That makes tons of sense.

Andrew : So I basically cover minimal APIs is the first part of the book because they give you a great introduction to how ASP .NET Core works. You can look at middleware, you can look at dependency injection configuration and it just gets you sort of ramped up slowly. And then the other main paradigm I talk about is Razor Pages and MVC to an extent.

And part of that is, this certainly was the main way to do server rendered applications. It was main suggested way to do like content apps and things like that was to use Razor Pages. Since .NET Core 2. In .NET 8, it changes a little bit with the way with the new Blazor rendering modes and things, but. So, yeah, I focus on minimal APIs and Razor Pages in MVC, which if you’re coming from ASP .NET "classic" as you termed it before, that’s probably going to cover a lot of what you want to know as well.

The other thing I don’t really cover is gRPC, which again is a whole additional way of building your API apps. I describe it a bit in various points, but it’s not, it’s not one of the main things I cover now.

Jamie : Yeah, sure.

Because like if you. Okay, so you said earlier on it’s a thousand pages without Blazor, but if you’re writing a book, that is, "let’s get you started with this technology, let’s get you up to speed as quickly as possible." You likely don’t want to get lost in the weeds of, "okay, so so far we’ve been using HTTP, but we’re going to switch over to gRPC. So now I have to teach you the differences between the two," or perhaps, "so far we’ve been using razor, which is fantastic and lovely and does a lot of stuff. Now we’re going to switch to Blazor. But hold on, because there’s three different ways to do Blazor, so I’ve got to teach you all three."

Andrew : Yeah, exactly.

Jamie : Before we can decide how we’re going to go from here on.

Andrew : Exactly, exactly. And I mean, JSON APIs are still, HTTP APIs are still the like, de facto way to communicate with apps. gRPC is obviously very interesting and is particularly good for certain things like server to server communication, and it’s getting better for use in the browser and things with ASP. NET Core doing the automatic transcoding between JSON and gRPC.

But I think if you’re getting started, you start with JSON. Later on, you can look at gRPC as an enhancement of, again, an extra stringing your bow, you know, just an extra tool in your tool belt.

And Blazor is an interesting one in .NET 8 with the extra, with the various modes, and it’s sort of setting itself up to replace Razor Pages and MVC. Whether it’ll do that, I don’t know. I mean, I can totally see the advantages of it and I can totally see it’s desirable to have just essentially one paradigm for all of the different ways to build your ASP .NET Core apps.

Maybe in, I mean, my opinion currently is that I probably wouldn’t go and rewrite all my apps into Blazor. And you should almost never rewrite your apps into anything anyway, I don’t think, just based on the technology. But will it become the de facto way to create ASP .NET core apps when it gets to, I don’t know .NET 10? It could be. It could be. But everything up to that is still going to be, it’s all going to be building on top of the knowledge, you know, which is the great thing about ASP .NET Core. Like everything, you still need to understand dependency injection, you still need to understand configuration, you still need to understand APIs and authentication.

So whenever they introduce new paradigms, it’s always good. Gives you more options. But at least it’s always building on that same foundation, which is one of the really nice things about ASP .NET Core. You have that really solid foundation.

Jamie : Yeah, totally.

Just want to really quickly point out that obviously what Andrew has said there about Blazor perhaps becoming the new way to do apps, that’s both of us just speculating that, you know, that is not, neither of us are Microsoft employees, neither of us represent the ASP .NET Core team. Standard disclaimers apply. Right. That’s just us talking out about what we think might be the future. Yeah, no, that’s cool.

I do like. There was something you’d said about focusing on JSON first, because the way that, the way that I, like when I’m, when I’m teaching someone how to use a technology, I always go with, "ight, okay, there’s, here is over here on the right hand side," perhaps if you’re imagining a continuum. "Here’s the really exciting new stuff that’s just come out that you can totally try out if you want. However that’s likely going to break. The documentation isn’t going to be quite there. And you need to change your understanding to be able to make it work. But if we come over here, if we shift left a little bit to the earlier part of the continuum, all the documentation is there. It’s guaranteed to work because it’s been," you know, another phrase I’m not a huge fan of, but it’s been battle tested.

It’s been tested by real developers rather than just, you know, the folks who are building the, building the framework. That’s not to say that they’re not real developers. I tripped up by saying "real developers," so I apologize. But it’s been tested by real-world developers. That’s what I meant to say. People who were building real world apps for real consumers. And there’s documentation, there’s examples, there’s YouTube videos, there’s blog posts about how to use it. So if you get stuck, you can search for, "how do I do this with JSON in ASP .NET Core?"

Whereas if you go right, "I want to leap directly over everything to the latest and greatest." And I’m going to pick on Blazor. I don’t mean to pick on anything, but if I jump straight to Blazor and I say, "I’m doing Blazor and it’s doing mixed rendering modes, and I have this problem and it’s a really esoteric error message and my app doesn’t work. Also, I am learning C

and .NET at the same time, you’re likely not going to fall into the pit of success, success as easily," right?

Andrew : Absolutely. Exactly. I mean, I think that, yeah, that covers it.

I think that’s one of the things that minimal APIs now, when they first came out in .NET 6, they were a nice idea, they were a nice experiment. They demoed really well, but they were missing functionality. If you jumped on it straight away, you’d hit a lot of rough edges. But the biggest thing is not having filters in .NET 6, you get to .NET 7, and now you’ve got all this various filter functionality. You’ve got extra the edges all just sanded down to make them really nice and smooth to use. And then .NET 8, there’s even more enhancements to them. So you can actually just use minimal APIs for forms as well as JSON. And now you’ve got something which is you can just recommend to use. There’s no reason not to use minimal APIs in a lot of way.

So when you think about, "do I choose MVC? Do I choose minimal APIs? Do I choose Blazor?" I think minimal APIs are in that nice sweet spot where they’ve got a good developer experience, they’re very performant and they have been improved sufficiently that there are plenty of real world apps that use them. So I think that’s a yeah.

A Request To You All

If you're enjoying this show, would you mind sharing it with a colleague? Check your podcatcher for a link to show notes, which has an embedded player within it and a transcription and all that stuff, and share that link with them. I'd really appreciate it if you could indeed share the show.

But if you'd like other ways to support it, you could:

I would love it if you would share the show with a friend or colleague or leave a rating or review. The other options are completely up to you, and are not required at all to continue enjoying the show.

Anyway, let's get back to it.

Jamie : Yeah, absolutely, absolutely. You mentioned filters and you’ve mentioned them a few times, so I am definitely, listeners: I am definitely stepping into the world of the unknown here. Can you talk through what filters are? I realize I’m dropping this on you and it’s an audio podcast.

Andrew : No, so that’s fine.

We’ve talked about middleware for your application, and so it’s lots of depending on how you want to look at it? It’s our factory belts. It’s a series of modules which apply cross cutting concerns to every request that comes into your application.

It’s the same thing. You’ve got a… the filter pipeline is essentially a series of middleware-like components that let you do things like apply validation to your application, or you can do any other sort of cross cutting concerns. And the good thing about the filters, as opposed to middleware is filters know what endpoint they’ve been applied to. So you can do things like get the actual arguments which the minimal API endpoint is going to receive. You can access those, you can access their types. So you can decide, is this a valid order type which has been passed from the JSON body? And you can do all that in filters which you can share then between all of your different minimum APIs. You can apply them to only a subset of your minimal APIs, which can just reduce a huge amount of code duplication, and means you can apply these filters across all of your minimal APIs if you wanted to.

Jamie : Right, okay.

So I’m thinking they were a little bit like perhaps attributes, right? So I’ve built validation attributes for some data coming in and I want to make sure that, say I’m asking the user to create a new person object, right? But the person object must be, I don’t know, greater than 18 years old and for some reason less than 100 years old, right? I can validate that on the way in with an attribute that I can then decorate in my particular API… so this is in the previous, in the previous times, right? So I would have a validator attribute, maybe an AgeValidator attribute that I’ll put onto the model. And every time that my request comes in with a new instance of that model, that’s then it’s taken from JSON over into a C Sharp object. It all will automatically apply that validation on that value to make sure that the user is greater than 18 years old, less than 100 years old.

And then I don’t have to manually write out if, you know, if(person.Age > 18 && person.Age < 100) do this path else do that path, it will be automatically done for me. Is that kind of what the filters are doing?

Andrew : Yeah, it’s pretty much.

So there’s some subtleties with the validation because in the MVC web API section of ASP .NET Core validation happens automatically. You can use those attributes that you described, but it automatically does that for every request. In minimal APIs. There’s no built in validation framework or anything like that. The expectation is that you will use filters to do something similar, like they’re very much designed so that they do work with validation. And there’s, I think Damien Edwards did a… wrote package which essentially does exactly what you’ve described. It uses the validation attributes to apply validation to minimal API arguments. But that is a filter which you plug in.

Which goes with their whole philosophy of minimal APIs should be as fast and small as they can get, and they very much lean onto this filters concept to be able to plug in all of the extra functionality.

Jamie : Okay, that makes sense because then you’re adding functionality as and when it’s needed, right? That’s the way I’m understanding it. I may be misunderstanding it, but like I’m adding it as and when needed and, and that way my minimal APIs, because they’re minimal amount of code to provide that functionality, I can then rely on the fact that something perhaps is injecting that filter in, or something is wiring it up so that it is being used whenever that API action is being called. Am I in the right ballpark there?

Andrew : Yeah, exactly.

So it’s sort of interesting, the philosophy, because obviously validation was one of the things they had some pushback. In MVC you’ve got validation there by default, and clearly you always want to have validation of your arguments. So why didn’t they include it in minimal APIs? And the answer basically is because there’s more than one validation framework. There’s the data annotation attributes, which is the sort of built in .NET framework-era style of doing a validation. But then there’s other frameworks like the fluent validation, for example, is a very popular one.

And the only way that works in MVC is you have to sort of try and plug it in as an extra part and remove the old validation. And they didn’t want to prioritize any particular style of doing validation, so they’ve made it that you can "just" write a filter and air quotes around just, but there’s libraries for doing that. And then yeah, you call AddValidation() on your API and this will add a filter to your endpoint or your collection of endpoints—that’s the other thing they added, in .NET 7 was the way to group endpoints together.

And yeah, you get the validation for free. It looks the same to you, but from a performance point of view and yeah, I mean, primarily from performance and the way you use it, point of view, it is very simple and minimal.

Jamie : Right. Okay. That makes more, thank you for that. That makes more sense. Yeah. It’s because I haven’t done a huge amount with filters. That’s why I’ve come across that sort of blind spot I guess, in my, in my knowledge. And I appreciate that. Thank you.

Andrew : No, that’s all good.

The other thing you can do with minimal APIs is add metadata to them. And this is again something that exists in MVC, but it’s very much made visible with minimal API filters. So authorization attributes and things like that, those are all metadata which are associated with the endpoint. So you can do OpenAPI attributes as well to describe, using swagger to describe what your API looks like. That’s all. Adding metadata to the minimum APIs. So you basically do one of two things, minimum APIs. You add filters to them or you add metadata to them and you can get just a huge range of functionality from that.

Jamie : Right. Okay.

And so I guess that metadata idea, it replaces the need… so when I’ve built web API’s with ASP .NET core in the past and I’m using Swagger or OpenAPI or whatever we want to call it, I’ve added, I’ve had to add a number of attributes that are like Produces(“application/JSON”) and you know, response, I think it’s ProducesResponseType() type and then the HTTP status code and then like a model, like a C Sharp model that it might respond with or things like that. I’m probably getting that completely wrong because it’s been a while.

But from what I’m taking from what you’re saying is that I can add that stuff as a metadata to all of my minimal APIs and then magic happens and swagger picks it up?

Andrew : Pretty much, yeah.

And so like you say, those produces attributes, those are all still the same attributes you can use on your minimal API endpoints. So it’s the same kind of mechanism under the hood. There are some additional ways to add the metadata for minimal APIs. There’s often fluent methods you can call so you can do MapGet() to do your endpoint and then you could do add whatever it is metadata you need to add. And minimal APIs are also somewhat clever and they can inspect the… because at runtime minimal APIs [inspect] the code that you provided as the lambda function or whatever it is, look at the arguments that you’re asking and look at what you’re returning as well. And so it can infer the types that you’re using to return as to whether you’re returning not found or whether you’re returning what type of JSON you’re using and things like that. So it can all be quite clever because of this runtime component it has.

Jamie : Right, I see. That’s the crazy thing. Right. I feel like the compiler is getting. The compiler and the runtime are getting way too clever.

Andrew : Well, I mean that’s in .NET a, sorry, in .NET 8 as well. You’ve got the start of native AoT (Ahead of Time compilation) coming for ASP .NET Core. And so there you have a different way of using minimal APIs. We’re actually using source generators and interceptors, which are two, you know, complex topics I don’t really touch on in the book, but they are a whole new way of building all of that extra code and generating, which is all quite interesting.

Jamie : Yeah, yeah.

AoT is one of those things I remember. So I haven’t chatted to him directly, but I remember chatting with Damien Edwards about, I think it was about a year ago when they were first sort of dipping their toe in the ASP .NET Core team. And I know that he’s not, yeah, he’s in loads of different teams, but they were dipping their toe into it. They were like, "yeah, don’t use reflection. And don’t use this, and don’t use that. Otherwise everything, you know, the world will end. But if you don’t use any of those and you just return like a JSON blob with the word words ‘hello world’ in it. Our initial version of it will allow you to do that." And that was like their initial demo version, not like a released version.

And I was, and I thought to myself, this is amazing. It has a couple caveats, but it’s amazing. And I suppose for those people who are in the situation where performance matters, they could turn that on. Most of the stuff that I make, the performance does matter, but not to that extreme, I guess.

Andrew : Yeah.

And I think, I don’t know, I’m sort of surprised in some ways by how much they’re pushing native AoT recently. It’s obviously a huge focus. It’s another big focus for .NET 9. And I can sort of understand it. It’s very cool. And for some workloads I can see that it’s very beneficial where you have latency, startup sensitive applications. So if you’re running in AWS Lambda or Azure Functions with consumption plans, they can make a really big difference because your app can start up very quickly.

But I don’t know, it doesn’t feel to me like that’s the bulk of people. If you just got your app and you’re deploying it and it runs for, if you’re only deploying once a day, say, or you’re deploying every hour, your app has plenty of time to sit there doing the JIT. And a lot of times because of, especially with this PGO runtime, your app will be faster if it’s not native AoT. So it’s sort of of surprising to me that they’re pushing it so much. But it certainly has some interesting applications and I mean, I’ve enjoyed playing with it, but yeah, it’s an interesting one.

Jamie : Yeah. Yeah. Well, so this is the thing, right? I don’t know if this is what they’re doing. This is, again, this is me speculating. Neither Andrew or I work for Microsoft or work on the .NET team or any of the, any of the other teams at Microsoft.

But of course, if you’ve got, again, I’m going to use a continuum, right. If you’ve got a continuum of things that you can optimize and you’ve hit most of the, the, in quotes, "easy ones," right. And you’re running out of things to optimize for, perhaps AoT is the thing that you want, or perhaps maybe you and I are not the target, you know, the target audience. And maybe there’s been a massive outpouring of, "we need AoT for X, Y and Z reasons!" And so obviously the team have then had to pivot and go, "right, okay, we’ll do AoT. We’ll get that out the way, get us started."

Andrew : Yeah.

Jamie : "And then put caveats on it and then maybe that will make those, those people a little bit happier and we, you know, we don’t have to worry about it so much." I don’t know. I wonder why they’re doing it. But like you say, we won’t know. Right. We’re not on the team. We, we aren’t those people making the, those decisions. But it’s an interesting time for sure.

Andrew : Yeah.

And I think you’re right, really on your assessment. I think there’s that as well. There’s probably a significant proportion of people who are using serverless applications, AWS Lambda, Azure Functions, who are lik, ".NET is just slow to start up," which if you compare it to some other libraries, you know, if you’ve, if you’ve written this in Rust or whatever, it’s. Yeah .NET is slow. And when you go to native AoT, it’s not slow. So I can totally understand that purely from being able to say, "yes, we can do this, "point of view. It absolutely makes sense.

And obviously it’s been one of those things that’s been kicked around for a long time and it is quite exciting to see it actually really happening. Like having it in ASP .NET Core was such a huge undertaking that they had to do for .NET 8. So you, it is very impressive and kudos to the team. But when you have things like currently EF Core isn’t supported, for example, which I would wager is a big proportion of people using ASP .NET Core. You feel like the actual reach of this. It’s gonna be 10% of people, tops. I would have guessed picking a number out of my head.

But it’s interesting.

Jamie : It is. But I guess though, it’s another example. It’s another example of we all get the benefit for, of we all get the benefit of whatever it is that they’re doing, right? So if you, even if you’re not doing AoT, but at some point in the future you need to do AoT, guess what? It’s already there, right?

One of the things that I get but don’t get is when people compare the speed of execution across different frameworks and libraries and systems, right? When it comes to like .NET, and Rust, and Python, and things like that. Jay Miller has this wonderful quote that I’m going to misquote because, you know, I’m not intending to misquote, but it’s… hopefully I’m going to hit the core part of what he means. "People say Python slow, but what it is, is it’s a Honda Civic, right? If you want something that will do the work for you and that you can take to any garage and have fixed when something goes wrong because it’s a Honda Civic, you can do that. If you bought a Bugatti, you can only take it to the Bugatti garage, right? So. And only Bugatti people can work on it."

And, and that’s not to say, and again, I’ve misquoted, and I’m sure I have, but that’s not to say that Python is slow. Well, maybe it is for some things, right, but why are you focusing on speed right now? If I do a dotnet new and create a web API, all it’s doing is returning hello world. The speed at which it returns hello world is pointless because a) it’s running on my machine and b) it’s not doing anything useful yet.

Andrew : Yeah, yeah, absolutely.

And I completely agree. Like having all these comparisons is not, it’s generally not very useful. It can be get useful in broad strokes to understand where things, where the best attributes of each language are for which different applications and things like that. Historically .NET maybe wasn’t the best thing to use in AWS Lambda because of the slow startup times. It was costing you money waiting for the runtime to start up. And with native AoT, that is basically solved as a problem. So. Yeah.

Jamie : But then again, you know, we all win, right? We all get that, that boost in startup time if we’re all doing native AoT. I just want to, there’s another part.

Andrew : Of it as well. Sorry.

Jamie : Yeah, I just wanted to really quickly double back and say, obviously I’m not standing here saying Python is slow because it’s not. It’s very, very fast at doing what it does. And what I care about is dev experience. You know, like I watched.

Andrew : Yeah.

Jamie : So Jay Miller did a live stream with Jason from Learn with Jason, and they created a web API using FastAPI in Python in 25 minutes. And I don’t mean they just went, "oh, pip install this." I mean, like they went from no code to a working API with like all four of the CRUD operations—create, read, update and delete—some kind of thing and writing to a real database in 25 minutes. Like, I’m not sure I could do that with .NET, but then I’m not sure whether that that’s a problem that needs to be solved. I don’t know, maybe I’m just talking nonsense.

Andrew : Yeah, I don’t know. I mean, I would have said that I think I could do it in 20 minutes. This sounds like a challenge.

Jamie : Well, I mean, okay, so most of those in .NET land are doing enterprise .NET development, right? So we have to do ceremonies and the, create the cards first and go through meetings and Agile startup, you know, project kick-off meetings and weekly stand ups. So you probably couldn’t do it in 25 minutes because you’re in the enterprise.

Andrew : It’s a good point. Yeah, good point. I forgot to add the Jira tax in. Yeah.

Jamie : Yeah, sorry I interrupted you earlier. Andrew.

Andrew : Oh no, it’s fine. I can’t remember what I was saying.

Jamie : Fair enough.

So I guess we’ve talked about minimal APIs, we’ve talked about filters, we’ve talked about metadata and some wonderful things to do with AoT and how apps are starting up faster and how that affects the people that it affects. I don’t think that anything that I have ever written in .NET would need the AoT speed up, but you know, it’s there as an option if you want it. Again, it’s the tool in your toolbox. Right. We talked about that earlier.

So I guess as we come towards wrapping up then, are there some things in ASP .NET Core that you think maybe don’t get a great deal of, I want to say "air time," that’s probably not the right word. But is there anything in ASP .NET Core that’s come out recently that you’re thinking, "that’s amazing? I wish loads more people knew about that."

Andrew : I mean, there’s so many things.

But honestly, the thing I enjoy most at the moment is source generators, like talking about the native AoT side and things like that. They’re a key thing. But personally I love source generators and they’re not a beginner topic at all. They’re difficult to do correctly. I realized one of my first blog posts about it was just gave some terrible advice, which people have copied, which. So sorry for everyone who did that, but I’ve rewritten it now.

But they’re just so much fun to have this code that is writing your code, and they just take you back to the T4 templates days. The good thing is that they can be used to basically improve the performance of your app. I’ve got one that you use for quasi calling ToString on enums, which is one of those things, which should be easy, but it’s actually really slow. [It’s] built into the framework, but it has to use reflection to go and get all the members and things like that, whereas they did make some improvements to that recently in .NET 8.

But using source generators, it’s sort of trivially easy to just make it super fast, which is one of those things I’ve really been enjoying. So if you haven’t seen those, I&rsquo;ve got a series about it on my blog, which hopefully basically talks you through how to build one of these and how to test it, how to create a NuGet package for it. So yeah, that’s my big things that I find fun at the moment, which, as I say, isn’t in the book, but yeah, I encourage people to have a look at it.

Jamie : Yeah. I have to say, I’ve used a couple of your blog posts in the past to help me write source generators for logging statements. Just to make them fast and memory efficient. They’re brilliant. Rather than doing logger.Log(string) and let the runtime interpolate it, writing the source generator to do that as and when is required is just fantastic. So I want to thank you personally for that because. Because those blog posts are really helpful.

Andrew : Glad to hear it. Glad to hear it. It’s always nice to hear.

Jamie : Cool. Okay, so as we start to wrap up, then I wonder, could you tell folks about the book again so that then they can remember it and go buy it? Hopefully. I’m not saying you have to go buy it, folks, but if you bought it, that would be nice.

Andrew : Again, you just try to earn that commission there, right.

Jamie : For everyone listening. I’m not on any kind of commission. It’s just a little joke.

Andrew : Exactly. Yeah. So it’s ASP .NET Core in Action: Third Edition, and it’s from Manning. So you can bet it from Manning website. You can get it from Amazon at your local Amazon, wherever it is. Or you can go to my blog and I’ve got various links to it around there.

Jamie : Amazing. Amazing. So what about if someone’s listening in and like, "I have a question for Andrew." Can they, like, is there a contact form on the website? Are you on one of the social media places where people can ask questions? Is it a case of they need to yell into their app and I somehow hear it and pass it on to you? Like, how do we, how do we get a message to you if someone’s listening and going, "Andrew, I’ve got a question."

Andrew : So on my blog, I’ve got each of the blog articles have a discussion forum at the bottom which links to GitHub, so you can contact me on there? My email’s on on the blog as well. You can catch me on Twitter. I&rsquo;m on LinkedIn. Those are the main things. And then if you buy the book, there’s a forum associated with the books and so you can ask questions about that and I’ll be on there answering questions as well.

Jamie : Amazing. Amazing. Well, thank you very much, Andrew. I’ve had a wonderful time chatting with you again. Hopefully we can do another one and don’t have to wait another five years.

Andrew : That would be great. It’s been great fun. Thanks, Jamie.

Jamie : Thank you very much, Andrew.

Wrapping Up

Thank you for listening to this episode of The Modern .NET Show with me, Jamie Taylor. I’d like to thank this episode’s guest, Andrew Lock, for graciously sharing his time, expertise, and knowledge.

Be sure to check out the show notes for a bunch of links to some of the stuff that we covered, and full transcription of the interview. The show notes, as always, can be found at the podcast's website, and there will be a link directly to them in your podcatcher.

And don’t forget to spread the word, leave a rating or review on your podcatcher of choice - head over to for ways to do that - reach out via our contact page, or join out discord server at - all of which are linked in the show notes.

But above all, I hope you have a fantastic rest of your day, and I hope that I’ll see you again, next time for more .NET goodness.

I will see you again real soon. See you later folks.

Follow the show

You can find the show on any of these places