← Back
JetBrains TV October 15, 2026 40m

C# Interceptors: Native AOT & Performance for Free | Stefan Pölz | .NET Day 2026

Not yet indexed — Search & Ask will be available once this episode finishes processing.

Read full transcript 33 segments
  1. Stefan Herz is with us. And Stefan Herz is with us. And what will he talk about today what will he talk about today what will he talk about today ? ? C# interceptors, Native C# interceptors, Native AOT, and performance AOT, and performance AOT, and performance for free. Congratulations. for free. Congratulations. for free. Congratulations. Hello, Stefan. Hello, Stefan. Hello, Stefan. Hello virtual Hello virtual Hello virtual heaven and earth. It's very heaven and earth. It's very heaven and earth. It's very nice to see you nice to see you nice to see you again. Thank you for again. Thank you for again. Thank you for inviting me again. inviting me again. inviting me again. Always happy. I think it's Always happy. I think it's Always happy. I think it's still early enough still early enough still early enough for you to completely for you to completely for you to completely confuse us with confuse us with confuse us with some tricky C some tricky C #. I think we'll get #. I think we'll get #. I think we'll get Excuse me. Excuse me. Excuse me. Continue. Yes, there Continue. Yes, there Continue. Yes, there may be some may be some may be some confusion confusion confusion . Yes. . Yes. . Yes. In my opinion, this is the In my opinion, this is the In my opinion, this is the best type of conversation best type of conversation best type of conversation about C#. Perfectly. I think about C#. Perfectly. I think about C#. Perfectly. I think we'll let you we'll let you we'll let you get straight to the get straight to the get straight to the point. So let's point. So let's point. So let's bring up the screen. We can bring up the screen. We can bring up the screen. We can see your see your see your screen perfectly and will let you get screen perfectly and will let you get screen perfectly and will let you get started. So, Stefan, started. So, Stefan, started. So, Stefan, you have the floor. you have the floor. you have the floor. Yes. Thank you very much. Yes. Thank you very much. Yes. Thank you very much. Greetings. Checkpoints.net is Greetings. Checkpoints.net is Greetings. Checkpoints.net is live. Thank you very much for live. Thank you very much for live. Thank you very much for joining us live joining us live joining us live or watching the recording or watching the recording or watching the recording later. So, we're later. So, we're later. So, we're going to talk about going to talk about going to talk about C# interceptors, which C# interceptors, which C# interceptors, which were a pre- were a pre- were a pre- feature in .NET 8 and feature in .NET 8 and feature in .NET 8 and became became became publicly available with publicly available with publicly available with .NET 9. This is not exactly a .NET 9. This is not exactly a .NET 9. This is not exactly a C# language feature, but C# language feature, but C# language feature, but rather a rather a rather a compiler feature that you compiler feature that you compiler feature that you can plug into can plug into can plug into your system using your system using code generators.

  2. So, what are we So, what are we going to talk about now? First, going to talk about now? First, going to talk about now? First, we'll start with a we'll start with a we'll start with a little introduction. little introduction. Then we'll Then we'll split our session up a bit. split our session up a bit. First, we'll talk First, we'll talk about what about what about what interceptors are. This is a interceptors are. This is a interceptors are. This is a C#-only C#-only or or or C# compiler-only feature. What do C# compiler-only feature. What do C# compiler-only feature. What do they represent in they represent in they represent in general? Then we general? Then we general? Then we will look at Native AOT and will look at Native AOT and will look at Native AOT and what it is in general. what it is in general. Meanwhile, we Meanwhile, we will also talk about will also talk about will also talk about code generators. Which code generators. Which code generators. Which is also a Roslyn feature. is also a Roslyn feature. And finally, we'll And finally, we'll put all these put all these put all these components together to components together to components together to show how a show how a show how a code generator can code generator can code generator can create an create an create an interceptor, which in interceptor, which in interceptor, which in some scenarios some scenarios some scenarios enables Native AOT enables Native AOT enables Native AOT compilation. So, compilation. So, compilation. So, before we start, before we start, before we start, hello, I'm Stefan. You hello, I'm Stefan. You hello, I'm Stefan. You can find can find can find my profile with all my profile with all my profile with all my social media in the chat my social media in the chat my social media in the chat if you have any if you have any if you have any questions that I questions that I questions that I can't answer can't answer can't answer live, after the live, after the live, after the session, or if you session, or if you session, or if you are watching the recording. Why are watching the recording. Why are watching the recording. Why I'm so excited to be at I'm so excited to be at I'm so excited to be at this event—I'm a member of the this event—I'm a member of the this event—I'm a member of the JetBrains community, so it's JetBrains community, so it's JetBrains community, so it's always cool always cool always cool to get involved in to get involved in to get involved in JetBrains events. I am also a JetBrains events. I am also a JetBrains events. I am also a Microsoft MVP and Microsoft MVP and Microsoft MVP and organizer of .NET organizer of .NET organizer of .NET meetups in Vienna. So, meetups in Vienna. So, meetups in Vienna. So, when you're in Vienna, when you're in Vienna, when you're in Vienna, please write to please write to please write to me on any of my me on any of my me on any of my social media. And I also social media. And I also social media. And I also do

  3. do do small live broadcasts from time to time. small live broadcasts from time to time. small live broadcasts from time to time. Um, as you can see, Um, as you can see, Um, as you can see, the word was "lean", um, the word was "lean", um, the word was "lean", um, is there a lot of it. So I is there a lot of it. So I is there a lot of it. So I often, yes, look at often, yes, look at often, yes, look at how the compiler works how the compiler works how the compiler works "under the hood" and how you "under the hood" and how you "under the hood" and how you can can can use that use that use that for certain, uh, for certain, uh, for certain, uh, scenarios, and also, scenarios, and also, scenarios, and also, incredibly, how the incredibly, how the incredibly, how the .NET team .NET team .NET team implements certain implements certain implements certain features to features to features to give you the give you the give you the best best best performance. This performance. This performance. This session is a follow-up to a session is a follow-up to a session is a follow-up to a session four years session four years session four years ago at JetBrains .NET ago at JetBrains .NET ago at JetBrains .NET Developer Days where I Developer Days where I Developer Days where I talked about talked about talked about incremental incremental incremental code generators, code generators, code generators, because because because interceptors interceptors interceptors should actually should actually should actually be created by an be created by an be created by an incremental incremental incremental generator, not generator, not generator, not by hand in C#. But by hand in C#. But by hand in C#. But we'll find out what that means we'll find out what that means we'll find out what that means in the next in the next in the next 30 minutes. Good. 30 minutes. Good. 30 minutes. Good. Let's see Let's see Let's see what what interceptors are. The current GA version of version of version of the interceptors, like the interceptors, like the interceptors, like version one, um, they're version one, um, they're version one, um, they're a little hard a little hard a little hard to demonstrate. to demonstrate. So I'll show the preview that was preview that was preview that was introduced in .NET 8.

  4. introduced in .NET 8. introduced in .NET 8. We'll get a few We'll get a few We'll get a few warnings warnings warnings because this because this preview is already outdated preview is already outdated preview is already outdated and could be removed by the and could be removed by the and could be removed by the compiler at compiler at any time. I'm actually not any time. I'm actually not any time. I'm actually not sure. I didn't sure. I didn't sure. I didn't check this. It may check this. It may not be there in dotnet 11. not be there in dotnet 11. not be there in dotnet 11. It still works in a It still works in a It still works in a more old-fashioned more old-fashioned more old-fashioned way and emphasizes way and emphasizes way and emphasizes what the interceptor actually does what the interceptor actually does what the interceptor actually does . That's why I'm . That's why I'm . That's why I'm turning to this turning to this turning to this older version. Oh, older version. Oh, older version. Oh, not benchmarks. not benchmarks. not benchmarks. I'm giving a little teaser I'm giving a little teaser that, of course, there will be that, of course, there will be that, of course, there will be benchmarks, as in all benchmarks, as in all benchmarks, as in all my sessions. So, my sessions. So, my sessions. So, I just have an I just have an I just have an empty console empty console empty console application and two application and two application and two methods here. I am methods here. I am methods here. I am calling a static calling a static calling a static method and an method and an method and an instance method. If we instance method. If we instance method. If we look at the look at the look at the implementation, these two implementation, these two implementation, these two methods are just methods are just methods are just one static method one static method one static method and an instance method and an instance method and an instance method that outputs a " that outputs a " regular method" regular method" regular method" because that's what because that's what because that's what they are. These are so-called they are. These are so-called they are. These are so-called regular methods, like regular methods, like property getters or setters, or property getters or setters, or constructors, or, um, constructors, or, um, constructors, or, um, delegates, local delegates, local delegates, local functions—that's a different type of functions—that's a different type of functions—that's a different type of method. They are not method. They are not method. They are not ordinary. And these are ordinary. And these are ordinary. And these are normal from the normal from the normal from the Roslyn perspective, from the Roslyn perspective, from the Roslyn perspective, from the compiler perspective. And then compiler perspective. And then compiler perspective. And then we'll pass Hello World to the we'll pass Hello World to the we'll pass Hello World to the static method and dotnet static method and dotnet static method and dotnet days online to the days online to the days online to the instance method. When we instance method. When we instance method. When we launch this, there launch this, there launch this, there shouldn't be any shouldn't be any shouldn't be any surprises. We should surprises. We should surprises. We should get the "normal get the "normal get the "normal Hello World method" and the " Hello World method" and the " normal dotnet normal dotnet normal dotnet days online method". Now, what I'm going to days online method". Now, what I'm going to days online method". Now, what I'm going to do now manually, do now manually, do now manually, which you shouldn't which you shouldn't which you shouldn't do manually. The

  5. do manually. The do manually. The code generator should code generator should code generator should generate this, but generate this, but generate this, but to highlight this to highlight this to highlight this feature, I'll now feature, I'll now feature, I'll now manually enter an manually enter an manually enter an interceptor. This is interceptor. This is interceptor. This is essentially adding a essentially adding a essentially adding a method that has a method that has a method that has a compatible signature. What compatible signature. What compatible signature. What does a compatible does a compatible does a compatible signature mean? This signature mean? This signature mean? This should also be a common should also be a common should also be a common method. It can't be a method. It can't be a method. It can't be a local function or local function or local function or anything like that. It anything like that. It anything like that. It must have the same must have the same must have the same return type. return type. It must have the It must have the same number and types of same number and types of same number and types of parameters, but the name does parameters, but the name does parameters, but the name does not necessarily have to not necessarily have to not necessarily have to match, but it match, but it match, but it must be compatible in must be compatible in must be compatible in terms of terms of terms of parameters and parameters and parameters and return type. If we are return type. If we are return type. If we are aiming for a aiming for a aiming for a static method, then that is how it static method, then that is how it static method, then that is how it is. If we is. If we is. If we target an target an target an instance method using instance method using an interceptor, we an interceptor, we also pass, like in a also pass, like in a also pass, like in a classic C#3, I think, classic C#3, I think, classic C#3, I think, extension method, the extension method, the extension method, the type of the receiver where type of the receiver where type of the receiver where that instance exists. that instance exists. And now we will generate And now we will generate this attribute, it is not this attribute, it is not this attribute, it is not part of the part of the part of the base class library.

  6. base class library. base class library. There is also a similar attribute in the GA version There is also a similar attribute in the GA version There is also a similar attribute in the GA version , not exactly the , not exactly the , not exactly the same, which same, which same, which is also not part of the BCL is also not part of the BCL . But since the . But since the . But since the code generator should code generator should code generator should generate it, you generate it, you generate it, you can simply add can simply add can simply add this attribute to your this attribute to your this attribute to your generator. And here we generator. And here we generator. And here we have three aspects. We have the have three aspects. We have the have three aspects. We have the file path, file path, file path, line number, and character. So, in line number, and character. So, in line number, and character. So, in other words, it's other words, it's other words, it's actually actually actually a location in the a location in the a location in the source code that source code that source code that gives the compiler a hint gives the compiler a hint not to "go to" but to do something not to "go to" but to do something opposite to "go to". opposite to "go to". It's like "come from." So It's like "come from." So it intercepts it intercepts it intercepts the call that would have the call that would have the call that would have happened if we had happened if we had happened if we had just made a just made a just made a static call with static call with static call with static static static binding to this binding to this binding to this method, the regular method, the regular method, the regular method that we're method that we're method that we're calling now; we calling now; we calling now; we say, "Please say, "Please say, "Please intercept this intercept this intercept this request," and proceed request," and proceed request," and proceed to the method above. And this is the to the method above. And this is the to the method above. And this is the program file. This is program file. This is program file. This is a call that we are a call that we are a call that we are intercepting, so intercepting, so intercepting, so we need to have an we need to have an we need to have an accurate path here. Another accurate path here. Another accurate path here. Another clue as to why this should clue as to why this should clue as to why this should be a code generator be a code generator be a code generator and not something manual. We and not something manual. We and not something manual. We pass in the pass in the pass in the line number, line number line number, line number line number, line number seven, and the character, 36.

  7. seven, and the character, 36. seven, and the character, 36. Character 36 is right Character 36 is right Character 36 is right here. here. After the period. So we After the period. So we intercept this intercept this intercept this static call and static call and static call and no longer go to the no longer go to the no longer go to the previous method previous method previous method that was called the that was called the that was called the regular method, but regular method, but regular method, but now we say, "Hey, now we say, "Hey, now we say, "Hey, instead of calling instead of calling instead of calling this method, this method, this method, actually call this actually call this actually call this interceptor method." interceptor method." interceptor method." Which now says " Which now says " intercepted" and " intercepted" and " static". So, without static". So, without static". So, without changing anything in the changing anything in the changing anything in the code below, in my code below, in my code below, in my own code that I own code that I own code that I wrote, and running it wrote, and running it wrote, and running it again, we again, we again, we no longer get the no longer get the no longer get the normal strings, but normal strings, but normal strings, but intercepted ones. And this is intercepted ones. And this is intercepted ones. And this is how the how the how the interceptor works. interceptor works. interceptor works. The difference in the GA version is that The difference in the GA version is that The difference in the GA version is that this attribute looks this attribute looks this attribute looks different. Hmm, other than that different. Hmm, other than that , everything is pretty much the same. , everything is pretty much the same. , everything is pretty much the same. It's still not It's still not It's still not designed to be designed to be designed to be manually launched, but manually launched, but manually launched, but that's the gist of how that's the gist of how interceptors work. Okay, the interceptors work. Okay, the first part first part first part is complete. Now I is complete. Now I is complete. Now I promised to talk promised to talk promised to talk about native AOT. So, about native AOT. So, about native AOT. So, let's talk a little bit let's talk a little bit let's talk a little bit about how about how about how your C# code is compiled your C# code is compiled . With normal JIT . With normal JIT (just-in-time) compilation, (just-in-time) compilation, (just-in-time) compilation, you have C# files in your you have C# files in your you have C# files in your project. There may be project. There may be project. There may be one or more of them.

  8. one or more of them. Since this is an Since this is an executable, there executable, there executable, there is always some kind of is always some kind of is always some kind of entry point, perhaps a entry point, perhaps a entry point, perhaps a top- top- top- level statement or an explicit level statement or an explicit level statement or an explicit Main method. And when we Main method. And when we Main method. And when we click dotnet build, click dotnet build, click dotnet build, the code is compiled by the C# the code is compiled by the C# compiler, that is, compiler, that is, compiler, that is, Roslyn, into IL code, Roslyn, into IL code, Roslyn, into IL code, intermediate language code. Yes, in intermediate language code. Yes, in ...Oh, I'm wrong, ...Oh, I'm wrong, ...Oh, I'm wrong, but that's how you but that's how you but that's how you know it's a know it's a know it's a real video. Not real video. Not real video. Not a record. Um, now the a record. Um, now the a record. Um, now the intermediate language code is not intermediate language code is not intermediate language code is not executable. This is, as executable. This is, as executable. This is, as the name suggests, a the name suggests, a the name suggests, a kind of intermediate kind of intermediate kind of intermediate representation of how representation of how representation of how .NET can execute .NET can execute .NET can execute code. Because we code. Because we code. Because we can also have, can also have, can also have, for example, Visual Basic code for example, Visual Basic code , and VB files that , and VB files that , and VB files that are compiled by the are compiled by the are compiled by the Roslyn compiler into IL Roslyn compiler into IL code. We can also code. We can also code. We can also have F# code. F# code does not have F# code. F# code does not have F# code. F# code does not compile with Roslyn. F# compile with Roslyn. F# has its own has its own compiler toolset for compiler toolset for generating IL code.

  9. generating IL code. generating IL code. So, when we have this So, when we have this So, when we have this IL code, it can be an IL code, it can be an IL code, it can be an executable file, executable file, executable file, maybe for Windows. It maybe for Windows. It maybe for Windows. It cannot start. cannot start. cannot start. I'm currently on my I'm currently on my I'm currently on my Windows x64 computer. Windows x64 computer. Windows x64 computer. This is not bytecode for a This is not bytecode for a This is not bytecode for a Windows x64 machine. So Windows x64 machine. So Windows x64 machine. So when we run when we run when we run the program, if we the program, if we the program, if we execute dotnet run, the execute dotnet run, the execute dotnet run, the JIT JIT compiler compiler compiler codenamed RyuJIT comes into play. I codenamed RyuJIT comes into play. I codenamed RyuJIT comes into play. I always always always pronounce it wrong. Um, it pronounce it wrong. Um, it pronounce it wrong. Um, it now converts this now converts this now converts this IL code into machine- IL code into machine- specific code and specific code and specific code and runs it. The cool thing is runs it. The cool thing is runs it. The cool thing is that this IL code is that this IL code is that this IL code is machine-independent. machine-independent. We just need a We just need a JIT compiler for the JIT compiler for the JIT compiler for the appropriate machine appropriate machine appropriate machine we are running on, we are running on, we are running on, so the so the so the .NET runtime takes care of that .NET runtime takes care of that .NET runtime takes care of that . If I were on a . If I were on a . If I were on a Mac, he would have created a Mac, he would have created a Mac, he would have created a version compatible with macOS. version compatible with macOS. If I were on a Linux x64 If I were on a Linux x64 or ARM machine, it would or ARM machine, it would or ARM machine, it would generate machine generate machine generate machine code for that code for that code for that specific specific specific architecture in architecture in architecture in real time. So, real time. So, real time. So, we have a single code we have a single code we have a single code base that can base that can base that can run anywhere run anywhere run anywhere as long as the as long as the as long as the right right right runtime is installed. That's what's runtime is installed. That's what's runtime is installed. That's what's cool. The disadvantage is cool. The disadvantage is cool. The disadvantage is that JIT compilation that JIT compilation that JIT compilation takes time. So, takes time. So, takes time. So, when we first when we first when we first run some run some run some code, we need, code, we need, code, we need, after the .NET run command, to after the .NET run command, to after the .NET run command, to first first first compile that IL compile that IL code into executable code code into executable code . This takes some time . This takes some time . Now, the JIT compiler

  10. . Now, the JIT compiler . Now, the JIT compiler has many has many has many optimizations. optimizations. optimizations. At first it creates At first it creates At first it creates code quickly, and when it code quickly, and when it code quickly, and when it later realizes that later realizes that later realizes that this code is executed this code is executed this code is executed frequently, it creates " frequently, it creates " under the hood", behind under the hood", behind under the hood", behind the scenes, fast the scenes, fast the scenes, fast code that takes a little code that takes a little code that takes a little longer, but you longer, but you longer, but you won't notice it; and won't notice it; and won't notice it; and then swaps these two then swaps these two then swaps these two execution paths, and execution paths, and execution paths, and suddenly your code suddenly your code suddenly your code starts running starts running starts running faster. So for faster. So for longer-running applications like longer-running applications like ASP.NET Core web apps ASP.NET Core web apps , this is just perfect , this is just perfect , this is just perfect because you can because you can because you can launch your launch your launch your application pretty application pretty application pretty quickly, and it quickly, and it quickly, and it will get somewhat will get somewhat will get somewhat faster over time the more faster over time the more faster over time the more often it often it often it is called. So it's a kind of is called. So it's a kind of self-optimization mechanism. This is self-optimization mechanism. This is really cool really cool really cool technology. But for technology. But for technology. But for very short-lived very short-lived very short-lived applications, say a applications, say a applications, say a console application console application console application that lives only a few that lives only a few that lives only a few milliseconds, this may milliseconds, this may milliseconds, this may be a price we don't be a price we don't be a price we don't want to pay. Or, want to pay. Or, want to pay. Or, if you have if you have if you have a web application in a a web application in a a web application in a hyperscale hyperscale hyperscale scenario that needs scenario that needs scenario that needs to be available to be available to be available as soon as possible, perhaps as soon as possible, perhaps as soon as possible, perhaps this JIT compilation this JIT compilation this JIT compilation won't work for us. That's won't work for us. That's won't work for us. That's why the .NET team why the .NET team why the .NET team introduced AOT— introduced AOT— ahead-of-time compilation. The difference ahead-of-time compilation. The difference with JIT compilation with JIT compilation with JIT compilation is that we is that we is that we still have our still have our still have our C#, Visual Basic, or F# files, C#, Visual Basic, or F# files, C#, Visual Basic, or F# files, they are still they are still they are still being converted to IL being converted to IL code, but we code, but we code, but we are still in the are still in the are still in the build phase.

  11. build phase. Machine- specific code is generated directly during compilation using an AOT compiler. specific code is generated directly during compilation using an AOT compiler. For example, Win x64 or For example, Win x64 or Linux. Linux x64, depending on the Linux. Linux x64, depending on the Linux. Linux x64, depending on the target platform target platform target platform I want to I want to I want to build for. build for. build for. Now this is machine- Now this is machine- dependent code. This is dependent code. This is dependent code. This is no longer the case with IL code, which no longer the case with IL code, which no longer the case with IL code, which is is is machine independent. These machine independent. These machine independent. These executables are now machine- executables are now machine- dependent. So my dependent. So my dependent. So my Win x64 will only run Win x64 will only run Win x64 will only run on 64-bit on 64-bit on 64-bit Windows machines, just like my Windows machines, just like my Windows machines, just like my Linux only runs on Linux, Linux only runs on Linux, Linux only runs on Linux, Mac OS, and so on. This is the Mac OS, and so on. This is the Mac OS, and so on. This is the disadvantage. We disadvantage. We disadvantage. We need a separate need a separate need a separate executable file for executable file for executable file for each target. The advantage each target. The advantage each target. The advantage is that is that there is no JIT compilation. there is no JIT compilation. there is no JIT compilation. In fact, there is no JIT In fact, there is no JIT compiler at all compiler at all compiler at all . It is . It is . It is unavailable, so the code unavailable, so the code unavailable, so the code just runs. just runs. just runs. In some scenarios, we In some scenarios, we In some scenarios, we can't even can't even can't even use the JIT use the JIT compiler. Mac OS compiler. Mac OS compiler. Mac OS has strict has strict has strict security rules that prevent security rules that prevent security rules that prevent you from generating new code in the you from generating new code in the you from generating new code in the same same same app app and then executing and then executing it, as you could it, as you could it, as you could execute code that the execute code that the App Store team cannot verify. So this is a safety directive. So, there is no JIT compiler here compiler here compiler here at all. You can't at all. You can't use it. So in use it. So in some scenarios you some scenarios you some scenarios you might even might even might even need need need AOT support. And that's AOT support. And that's AOT support. And that's essentially what AOT does.

  12. essentially what AOT does. essentially what AOT does. The advantage of AOT is that The advantage of AOT is that The advantage of AOT is that it runs it runs it runs very quickly because it very quickly because it very quickly because it has ready-made machine has ready-made machine has ready-made machine code. The disadvantage is code. The disadvantage is code. The disadvantage is that the JIT compiler is that the JIT compiler is that the JIT compiler is not available to us. And some not available to us. And some not available to us. And some functions rely functions rely functions rely on the JIT compiler. on the JIT compiler. on the JIT compiler. For example, regular For example, regular For example, regular expressions. So, it's expressions. So, it's expressions. So, it's time to move on to time to move on to time to move on to benchmarks. I benchmarks. I benchmarks. I have prepared have prepared have prepared a benchmark for you with a simple a benchmark for you with a simple a benchmark for you with a simple template. Essentially, I'm template. Essentially, I'm template. Essentially, I'm looking for text looking for text looking for text ending in .cs ending in .cs ending in .cs or .vb. That is, I am looking for or .vb. That is, I am looking for or .vb. That is, I am looking for C# or Visual Basic files. C# or Visual Basic files. C# or Visual Basic files. So, I'm looking for files So, I'm looking for files So, I'm looking for files that the that the Roslyn compiler can compile. A small note: a A small note: a cool feature of Rider cool feature of Rider cool feature of Rider is that is that is that if you if you if you use the use the use the string syntax attribute and string syntax attribute and string syntax attribute and pass a pass a pass a regular expression string there, regular expression string there, regular expression string there, Rider displays it Rider displays it Rider displays it as a regex, understands as a regex, understands as a regex, understands characters, and also characters, and also characters, and also recognizes parentheses, etc. recognizes parentheses, etc. recognizes parentheses, etc. Very useful feature. Very useful feature. So, I have So, I have four benchmarks here. In four benchmarks here. In four benchmarks here. In one, I create the regex one, I create the regex one, I create the regex directly and directly and directly and call it immediately. I do call it immediately. I do call it immediately. I do n't cache it. I don't n't cache it. I don't n't cache it. I don't overuse it. And overuse it. And overuse it. And this is also an this is also an this is also an interpreted interpreted interpreted regular expression.

  13. regular expression. regular expression. So, I don't have So, I don't have So, I don't have any any any compilation flags here. This compilation flags here. This compilation flags here. This means that means that an interpreter is used. The regular expression interpreter spends approximately the spends approximately the same amount of time on the same amount of time on the same amount of time on the same input data each time it runs. same input data each time it runs. We could also We could also use a use a use a compiled compiled compiled regular expression regular expression regular expression that, on first that, on first that, on first run, calls the JIT run, calls the JIT compiler to compiler to compiler to generate new IL generate new IL code. No, it doesn't. code. No, it doesn't. code. No, it doesn't. No, wait. It does not No, wait. It does not No, wait. It does not call the JIT call the JIT compiler. We compiler. We compiler. We use use use Reflection.Emit to Reflection.Emit to Reflection.Emit to generate new IL generate new IL code, which is then code, which is then code, which is then optimized optimized optimized using JIT using JIT compilation. So it compilation. So it compilation. So it will generate very will generate very will generate very specific code for specific code for specific code for this template. This this template. This this template. This means that the first means that the first means that the first launch will be launch will be launch will be slower, but all slower, but all slower, but all subsequent launches will be significantly subsequent launches will be significantly subsequent launches will be significantly faster. In this faster. In this faster. In this benchmark, I benchmark, I benchmark, I create a new object each time. create a new object each time. create a new object each time. This is very bad, but it This is very bad, but it This is very bad, but it will help will help will help demonstrate the demonstrate the demonstrate the initial cost of a initial cost of a initial cost of a compiled compiled compiled regular expression. Unlike regular expression. Unlike when we when we use the use the use the same regular same regular same regular expression but already expression but already expression but already cache it. So we cache it. So we cache it. So we pay the price for JIT pay the price for JIT compilation only compilation only compilation only once, and then once, and then once, and then use the use the use the faster JIT-generated faster JIT-generated faster JIT-generated loop. But, as I loop. But, as I loop. But, as I mentioned, in native AOT mentioned, in native AOT mentioned, in native AOT we don't have a JIT we don't have a JIT compiler. So in a compiler. So in a compiler. So in a native AOT script we will native AOT script we will native AOT script we will always have the always have the always have the interpreted interpreted interpreted version, regardless of the version, regardless of the version, regardless of the flag. Which does flag. Which does flag. Which does n't run as fast as the n't run as fast as the n't run as fast as the compiled version compiled version . And that's why the . And that's why the . And that's why the .NET team introduced a .NET team introduced a .NET team introduced a code generator for code generator for code generator for regular expressions.

  14. regular expressions. regular expressions. So, here we have a So, here we have a So, here we have a partial type, where partial type, where partial type, where the presence of the the presence of the the presence of the partial keyword indicates that partial keyword indicates that partial keyword indicates that another part of another part of another part of the implementation the implementation the implementation is generated is generated is generated automatically, in this automatically, in this automatically, in this case by a case by a case by a code generator. Where I pass in code generator. Where I pass in code generator. Where I pass in my parameters and the my parameters and the my parameters and the template that I want to template that I want to template that I want to compile, and in Rider compile, and in Rider compile, and in Rider I can—well, depending I can—well, depending I can—well, depending on your on your on your hotkeys—press F12 hotkeys—press F12 hotkeys—press F12 to go to the to go to the to go to the source code, and source code, and source code, and see that this is the see that this is the see that this is the generated code. g.cs. generated code. g.cs. generated code. g.cs. You'll see that Rider You'll see that Rider You'll see that Rider highlights this a little with a highlights this a little with a highlights this a little with a gray background. Um, this is gray background. Um, this is gray background. Um, this is generated code. You generated code. You generated code. You should not should not should not edit it. Uh, also edit it. Uh, also edit it. Uh, also note that we are note that we are note that we are in reading mode. And this is in reading mode. And this is in reading mode. And this is now a regular now a regular now a regular expression generated expression generated expression generated at the compile stage. at the compile stage. at the compile stage. That is, this That is, this That is, this happens during happens during happens during assembly. Not at assembly. Not at assembly. Not at runtime through the IL runtime through the IL compiler. So, we compiler. So, we compiler. So, we have an optimized have an optimized have an optimized regular expression regular expression regular expression that also works in AOT that also works in AOT scripts, well, not scripts, well, not scripts, well, not just works, but just works, but just works, but provides the best provides the best provides the best performance in native performance in native performance in native AOT scripts. Let's take AOT scripts. Let's take AOT scripts. Let's take a look at the a look at the performance test results. So, performance test results. So, if we always if we always if we always use the use the use the interpreted interpreted interpreted version and version and version and allocate a new one each time, it allocate a new one each time, it allocate a new one each time, it doesn't take too doesn't take too doesn't take too much time. It doesn't much time. It doesn't much time. It doesn't allocate too much allocate too much allocate too much memory. He is quite memory. He is quite memory. He is quite fast. If we fast. If we fast. If we do it poorly and don't do it poorly and don't do it poorly and don't reuse reuse reuse , but , but , but create a create a create a compiled compiled compiled version every time, we see version every time, we see version every time, we see the cost of a compiled the cost of a compiled the cost of a compiled regular expression.

  15. regular expression. regular expression. It takes a little time It takes a little time It takes a little time to compile this to compile this to compile this regular expression at regular expression at regular expression at runtime. This is the JIT- runtime. This is the JIT- compiled version compiled version . And it allocates . And it allocates . And it allocates a lot of memory. But a lot of memory. But a lot of memory. But when we when we when we reuse it reuse it reuse it , we pay , we pay , we pay this price only once, this price only once, this price only once, and then each and then each and then each subsequent call is subsequent call is subsequent call is significantly faster significantly faster significantly faster compared to the compared to the compared to the interpreted one. And interpreted one. And interpreted one. And it becomes one that does not it becomes one that does not it becomes one that does not require require require memory allocation. Very cool. memory allocation. Very cool. memory allocation. Very cool. But we still But we still But we still pay this price pay this price pay this price during the first during the first during the first execution, when the IL code execution, when the IL code execution, when the IL code is generated and the is generated and the is generated and the JIT JIT compiler is run. So with the compiler is run. So with the compiler is run. So with the generated generated generated option, where we option, where we option, where we move move move the complexity from the complexity from the complexity from runtime to runtime to runtime to build time, upfront, we build time, upfront, we build time, upfront, we don't pay that don't pay that don't pay that upfront price. Now upfront price. Now upfront price. Now we are compatible with native AOT and we are compatible with native AOT and we are compatible with native AOT and have a version that is even a have a version that is even a have a version that is even a little faster than the little faster than the little faster than the compiled one. Now, compiled one. Now, compiled one. Now, um, in some um, in some um, in some scenarios this scenarios this scenarios this highlights that in a native highlights that in a native highlights that in a native AOT scenario we would always AOT scenario we would always AOT scenario we would always have the have the have the interpreted interpreted interpreted version because the JIT version because the JIT compiler doesn't work compiler doesn't work compiler doesn't work unless we unless we unless we use the use the use the generated version.

  16. generated version. generated version. So, we can So, we can So, we can change our code from change our code from change our code from regular Regex, or regular Regex, or regular Regex, or maybe maybe maybe use a use a use a static call where static call where static call where we say IsMatch and we say IsMatch and we say IsMatch and pass in the pattern and pass in the pattern and pass in the pattern and text, depending on text, depending on text, depending on your scenario. If your scenario. If your scenario. If we can rewrite we can rewrite we can rewrite our code to go our code to go our code to go to the version to the version to the version generated at the generated at the generated at the build stage, we build stage, we build stage, we will get a version will get a version will get a version compatible with native AOT. But compatible with native AOT. But compatible with native AOT. But you need to change the you need to change the you need to change the code. Well, the .NET team code. Well, the .NET team code. Well, the .NET team has provided has provided has provided a fix for a fix for a fix for this as well. Actually, I this as well. Actually, I this as well. Actually, I turned it off here, but turned it off here, but turned it off here, but if I hadn't turned off the if I hadn't turned off the if I hadn't turned off the fixer, you could have fixer, you could have fixer, you could have pressed Alt + Enter or pressed Alt + Enter or pressed Alt + Enter or Control + Period, depending Control + Period, depending Control + Period, depending on your on your on your hotkeys, and let hotkeys, and let hotkeys, and let Roslyn with the code Roslyn with the code Roslyn with the code fixer create fixer create fixer create this generated this generated this generated regular expression for regular expression for regular expression for you. And you can you. And you can you. And you can apply this in Rider apply this in Rider apply this in Rider to the entire solution. to the entire solution. to the entire solution. So it's Alt + Enter and So it's Alt + Enter and So it's Alt + Enter and down arrow, down arrow, down arrow, press Enter again, press Enter again, press Enter again, and you apply that and you apply that and you apply that to your entire to your entire to your entire solution. I'm quite solution. I'm quite solution. I'm quite sure your sure your sure your agent could do it too agent could do it too agent could do it too , with the , with the , with the capabilities we capabilities we capabilities we saw in the presentation, saw in the presentation, saw in the presentation, to get a new to get a new to get a new version. But we still version. But we still version. But we still need to need to need to change our code. Wouldn't it be change our code. Wouldn't it be change our code. Wouldn't it be cool cool cool if we didn't have to if we didn't have to if we didn't have to change our change our change our code? And if code? And if code? And if the interceptor could the interceptor could the interceptor could make such a substitution, make such a substitution, make such a substitution, as if behind the scenes. This is exactly what as if behind the scenes. This is exactly what we will now we will now consider using the consider using the consider using the example of a native AOT example of a native AOT example of a native AOT web API. I'll also highlight, and web API. I'll also highlight, and web API. I'll also highlight, and you'll find it in the chat, a you'll find it in the chat, a you'll find it in the chat, a spec from the spec from the spec from the Roslyn repository about

  17. Roslyn repository about Roslyn repository about how the how the how the GA interceptors currently work, GA interceptors currently work, GA interceptors currently work, available since .NET 9, although it available since .NET 9, although it available since .NET 9, although it says here that they says here that they says here that they were were were experimental in experimental in experimental in .NET 8 and released .NET 8 and released .NET 8 and released starting with the .NET 9.0.2 SDK. starting with the .NET 9.0.2 SDK. starting with the .NET 9.0.2 SDK. They work very They work very They work very similarly. The difference is similarly. The difference is similarly. The difference is that this attribute that this attribute that this attribute looks a little looks a little looks a little different. We have a different. We have a different. We have a version and a data string here version and a data string here . And this line of data . And this line of data . And this line of data now encodes those three now encodes those three now encodes those three components that we components that we components that we saw earlier. saw earlier. File location, File location, line number, line number, line number, character number, and a character number, and a character number, and a specific specific specific checksum. So this string of checksum. So this string of checksum. So this string of data is not very data is not very data is not very human-readable, human-readable, human-readable, but, again, it's but, again, it's but, again, it's intended to be intended to be intended to be generated by a machine, a generated by a machine, a source code generator. This is a source code generator. This is a practically pure practically pure practically pure ASP.NET Core example with ASP.NET Core example with ASP.NET Core example with native AOT. So what I native AOT. So what I native AOT. So what I did before going did before going did before going live—I executed dotnet live—I executed dotnet live—I executed dotnet new web API AOT. Which new web API AOT. Which new web API AOT. Which creates a native ASP.NET creates a native ASP.NET creates a native ASP.NET Core minimal API that is also Core minimal API that is also Core minimal API that is also native AOT. When we native AOT. When we native AOT. When we look at this CS look at this CS project, we see publish project, we see publish project, we see publish AOT. So if I AOT. So if I AOT. So if I hit dotnet publish it hit dotnet publish it hit dotnet publish it would create, since would create, since would create, since I'm on a Win x64 machine, a Windows I'm on a Win x64 machine, a Windows I'm on a Win x64 machine, a Windows 64 AOT-compiled 64 AOT-compiled 64 AOT-compiled executable. You executable. You executable. You can also can also can also pass RID, I forgot pass RID, I forgot pass RID, I forgot what that means— what that means—

  18. resource identifier, runtime identifier . So I could . So I could . So I could pass pass pass an identifier to, an identifier to, an identifier to, say, -r Linux, but that say, -r Linux, but that say, -r Linux, but that might not work might not work might not work because I need to because I need to because I need to have have have Linux tools available. Linux tools available. So usually if So usually if you're in a CI scenario, you you're in a CI scenario, you you're in a CI scenario, you use a specific use a specific use a specific machine that you have in CI machine that you have in CI , and compile for , and compile for , and compile for that target that you're that target that you're that target that you're also going to also going to also going to run on. And now In run on. And now In run on. And now In this example of a this example of a this example of a minimal API with Native minimal API with Native minimal API with Native AOT, there are two culprits AOT, there are two culprits AOT, there are two culprits that prevent that prevent that prevent Native AOT from working. Specifically, these are the Native AOT from working. Specifically, these are the Native AOT from working. Specifically, these are the map get methods, which are map get methods, which are map get methods, which are part of this part of this part of this example. I didn't example. I didn't example. I didn't change anything. If we change anything. If we change anything. If we look at look at look at the implementation of map get, it the implementation of map get, it the implementation of map get, it has two attributes. It has two attributes. It has two attributes. It says requires unreferenced code. " says requires unreferenced code. " Unreferenced code" is a good Unreferenced code" is a good Unreferenced code" is a good word for reflection.

  19. word for reflection. So when you So when you use get type use get type use get type and get the method or and get the method or and get the method or members of the type just by the members of the type just by the members of the type just by the string name. string name. string name. Without a static Without a static Without a static reference, something to reference, something to navigate to, and navigate to, and something the compiler can something the compiler can something the compiler can check to see what check to see what check to see what it actually it actually it actually binds to. If binds to. If binds to. If you use you use you use reflection, get member, get reflection, get member, get reflection, get member, get field with a specific name, field with a specific name, field with a specific name, it's not statically it's not statically it's not statically bound, well, yeah. bound, well, yeah. Binding Binding happens at happens at happens at runtime, so you can't runtime, so you can't runtime, so you can't figure it out figure it out figure it out at compile time. at compile time. Because what Because what Native AOT does is Native AOT does is trimming. Pruning trimming. Pruning trimming. Pruning means it means it means it looks at all your looks at all your looks at all your code, essentially hitting code, essentially hitting code, essentially hitting F12 or going into the F12 or going into the F12 or going into the implementation of all implementation of all implementation of all your code and seeing your code and seeing your code and seeing what is being used. what is being used. what is being used. And what is not And what is not And what is not used, used, used, it shakes out like a it shakes out like a it shakes out like a tree and removes from the tree and removes from the tree and removes from the final final final executable file. executable file. Because machine code is Because machine code is larger than IL code. The IL larger than IL code. The IL code is super- code is super- optimized, so we optimized, so we optimized, so we would get much would get much would get much larger larger larger executables. Hence the executables. Hence the executables. Hence the aggressive pruning aggressive pruning aggressive pruning to reduce these to reduce these to reduce these costs again for costs again for costs again for Native AOT applications. You Native AOT applications. You Native AOT applications. You can also enable can also enable can also enable pruning for pruning for pruning for non-AOT applications. For JIT- non-AOT applications. For JIT- compiled compiled compiled applications, you applications, you applications, you can also enable can also enable can also enable pruning. But when you pruning. But when you pruning. But when you enable Native AOT, you will enable Native AOT, you will enable Native AOT, you will always have clipping always have clipping . What if this type of . What if this type of . What if this type of reflection, which is not reflection, which is not reflection, which is not statically bound, statically bound, statically bound, can now be can now be can now be removed by pruning, and removed by pruning, and removed by pruning, and then we suddenly

  20. then we suddenly then we suddenly encounter a encounter a encounter a member not found or type not found exception member not found or type not found exception member not found or type not found exception at runtime. at runtime. That's why when you have That's why when you have a trim, requires unreferenced a trim, requires unreferenced a trim, requires unreferenced code throws a code throws a code throws a warning and says, " warning and says, " Hey, this might not Hey, this might not Hey, this might not work at work at work at runtime." And there is a second runtime." And there is a second runtime." And there is a second attribute: requires dynamic code. attribute: requires dynamic code. attribute: requires dynamic code. This applies to This applies to This applies to dynamically dynamically dynamically generated code, generated code, generated code, we can generate we can generate we can generate new IL code. Which is new IL code. Which is new IL code. Which is then compiled by a JIT then compiled by a JIT compiler, just like compiler, just like compiler, just like with the regular with the regular with the regular expressions I expressions I expressions I showed earlier. showed earlier. So, minimal APIs So, minimal APIs use both use both use both reflection and reflection and reflection and generate new IL code generate new IL code generate new IL code for your specific for your specific for your specific endpoints. This does not endpoints. This does not endpoints. This does not work in a Native work in a Native work in a Native AOT scenario. I should get a AOT scenario. I should get a AOT scenario. I should get a warning because I have warning because I have Publish AOT enabled in my CS code file. But Publish AOT enabled in my CS code file. But I don't see any I don't see any I don't see any warning. Because the warning. Because the warning. Because the interceptor is interceptor is interceptor is already fixing it behind already fixing it behind already fixing it behind the scenes. If we... the scenes. If we... There was one There was one There was one property that I property that I property that I just forgot. Maybe just forgot. Maybe just forgot. Maybe we can find her together.

  21. we can find her together. So, I'm looking to, um, So, I'm looking to, um, enable enable enable native AOT parsers. Eh, is native AOT parsers. Eh, is native AOT parsers. Eh, is native AOT compatible, native AOT compatible, native AOT compatible, enable, enable enable, enable enable, enable AOT parsers. So AOT parsers. So AOT parsers. So what we can do what we can do what we can do is disable native AOT is disable native AOT is disable native AOT but still but still enable analyzers that analyzers that check for check for unquoted code or unquoted code or dynamic code. And dynamic code. And dynamic code. And now we should now we should now we should get two get two get two warnings. Eh, but warnings. Eh, but warnings. Eh, but we don't get them. Oh, we don't get them. Oh, we don't get them. Oh, enable enable enable AOT parsers. Do AOT parsers. Do AOT parsers. Do I have some type of unknown? I have some type of unknown? I have some type of unknown? Looks good. I'm afraid Looks good. I'm afraid I don't know why I'm not I don't know why I'm not I don't know why I'm not getting errors, but getting errors, but getting errors, but I should now, um, I should now, um, I should now, um, get two get two get two errors here that say, " errors here that say, " Hey, we're Hey, we're Hey, we're using a method using a method that's not AOT-compatible that's not AOT-compatible because it might because it might because it might be deprecated, and be deprecated, and be deprecated, and also it requires also it requires also it requires dynamic code dynamic code dynamic code that's not available in AOT that's not available in AOT ." And yes, we should ." And yes, we should ." And yes, we should get these get these get these warnings now. I warnings now. I warnings now. I don't know what I did don't know what I did don't know what I did wrong in my wrong in my wrong in my settings. But settings. But settings. But if we go back if we go back if we go back to what was to what was to what was before, we don't before, we don't before, we don't get these get these get these warnings because warnings because warnings because these methods, which have these methods, which have these methods, which have unquoted code and unquoted code and unquoted code and have dynamic code, are have dynamic code, are have dynamic code, are not actually not actually not actually being called.

  22. being called. The interceptor The interceptor intercepts these two, um, intercepts these two, um, intercepts these two, um, calls and transfers calls and transfers calls and transfers the complexity of creating the complexity of creating the complexity of creating IL, creating this IL, creating this IL, creating this code at code at code at runtime, to the runtime, to the runtime, to the compilation stage, and compilation stage, and compilation stage, and then also at then also at then also at compile time it performs a compile time it performs a compile time it performs a trick to call trick to call trick to call another method. So, we another method. So, we another method. So, we don't need to don't need to don't need to change any of change any of change any of our minimal API our minimal API code. We just code. We just code. We just say publish AOT true, and we say publish AOT true, and we say publish AOT true, and we become become become native AOT compatible because the native AOT compatible because the native AOT compatible because the .NET team creates, uh, .NET team creates, uh, .NET team creates, uh, or has a or has a or has a code generator that emits the code generator that emits the code generator that emits the interceptor. We interceptor. We interceptor. We can look at can look at can look at interceptors. Hmm, interceptors. Hmm, interceptors. Hmm, maybe I deleted maybe I deleted maybe I deleted the warning? No, the warning? No, the warning? No, they should be there. they should be there. they should be there. Good. Um, we can Good. Um, we can we can we can view the view the view the generated code in generated code in generated code in our .NET projects our .NET projects our .NET projects by going to our by going to our by going to our CS project file, going CS project file, going CS project file, going into dependencies, into dependencies, into dependencies, selecting the target selecting the target selecting the target platform, platform, platform, going into going into going into code generators. This is a code generators. This is a code generators. This is a really cool really cool really cool Rider feature that I use, Rider feature that I use, Rider feature that I use, not every day, but almost not every day, but almost not every day, but almost every day. And we see that every day. And we see that every day. And we see that we actually have we actually have we actually have multiple generators.

  23. multiple generators. multiple generators. We have a generator for We have a generator for We have a generator for JSON that, um, makes JSON JSON that, um, makes JSON JSON that, um, makes JSON AOT-compatible and also AOT-compatible and also AOT-compatible and also improves improves improves performance. We performance. We performance. We have a secure have a secure have a secure generator for the generator for the generator for the public program. public program. public program. So, apparently, the So, apparently, the So, apparently, the main method is being created. main method is being created. main method is being created. Can we just Can we just Can we just take a look at him? take a look at him? take a look at him? Um, so, okay, there's a Um, so, okay, there's a Um, so, okay, there's a code generator that code generator that code generator that creates a partial creates a partial creates a partial class of the program. And we class of the program. And we class of the program. And we have a have a have a request delegate generator request delegate generator request delegate generator that now emits that now emits that now emits this attribute. It this attribute. It this attribute. It does this based on the does this based on the does this based on the file type because file type because file type because it's it's it's only used within that only used within that only used within that file, and it's just an file, and it's just an file, and it's just an attribute so that attribute so that attribute so that the compiler knows, um, the compiler knows, um, the compiler knows, um, where where where this this this back back back jump operator essentially comes from. Um, sees jump operator essentially comes from. Um, sees jump operator essentially comes from. Um, sees them, and then the changes in the them, and then the changes in the them, and then the changes in the binding stage binding stage binding stage are not bound to the are not bound to the are not bound to the actual map actual map actual map get method that we saw, but get method that we saw, but get method that we saw, but to the intercepted to the intercepted to the intercepted method, which again method, which again method, which again has a compatible, um, has a compatible, um, has a compatible, um, signature. It is also signature. It is also signature. It is also static. It static. It static. It takes the same takes the same takes the same parameters as the method, the parameters as the method, the parameters as the method, the regular method, that regular method, that regular method, that we called. The name we called. The name we called. The name doesn't matter.

  24. doesn't matter. doesn't matter. The name may be different The name may be different , and now we have this , and now we have this , and now we have this intercepts location attribute intercepts location attribute intercepts location attribute here. In version one, there is here. In version one, there is here. In version one, there is this line that encodes this line that encodes this line that encodes information that you information that you information that you need to intercept need to intercept need to intercept the call from program CS from the 21st the call from program CS from the 21st the call from program CS from the 21st line and 10th character. line and 10th character. And don't call this And don't call this map get method from the map get method from the asp.net core shared libraries, but instead asp.net core shared libraries, but instead call this call this call this generated method. And generated method. And generated method. And if we look if we look if we look below, there will also be a below, there will also be a below, there will also be a map get one for another map get one for another map get one for another map get. And that is also map get. And that is also map get. And that is also intercepted. If intercepted. If intercepted. If I were to delete, say, the I were to delete, say, the I were to delete, say, the second one. Since I second one. Since I second one. Since I changed the source code, the changed the source code, the changed the source code, the code generator code generator code generator runs again and runs again and runs again and now the map get one now the map get one now the map get one no longer exists. There is no longer exists. There is no longer exists. There is only map get zero. So only map get zero. So only map get zero. So only only only this call is intercepted. And also, this call is intercepted. And also, this call is intercepted. And also, if we look at if we look at if we look at this encoded this encoded this encoded string, when we string, when we string, when we start changing the start changing the start changing the location that we're location that we're location that we're going to going to going to intercept, if I intercept, if I intercept, if I add a few add a few add a few linefeed characters linefeed characters linefeed characters , now this , now this , now this string, well, it's already string, well, it's already string, well, it's already changed. So, changed. So, changed. So, let's place let's place let's place them side by side. And I'm entering them side by side. And I'm entering them side by side. And I'm entering some line breaks, well some line breaks, well , I'm adding some , I'm adding some , I'm adding some line breaks here, line breaks here, line breaks here, and we see that the line and we see that the line and we see that the line here is here is here is automatically updated. It automatically updated. It automatically updated. It changed him again. Um, so a changed him again. Um, so a changed him again. Um, so a generator is a generator is a generator is a component that component that component that runs constantly in runs constantly in runs constantly in your IDE, so Rider your IDE, so Rider your IDE, so Rider knows when

  25. knows when knows when to run it, and then to run it, and then to run it, and then updates the generated updates the generated updates the generated code, in this case code, in this case code, in this case also the interceptor. And also the interceptor. And also the interceptor. And that's how we that's how we that's how we get native AOT and get native AOT and get native AOT and performance for free. I performance for free. I performance for free. I didn't need to didn't need to didn't need to change a single change a single change a single line of my source line of my source line of my source code because the code because the code because the .NET team was kind enough to provide .NET team was kind enough to provide a catch-all to make the a catch-all to make the minimal APIs minimal APIs minimal APIs compatible with native AOT as well. compatible with native AOT as well. Just for the last Just for the last part: what would a part: what would a code generator that code generator that creates an interceptor look like creates an interceptor look like ? Um, if you want to ? Um, if you want to ? Um, if you want to dive deeper into dive deeper into dive deeper into how how how code generators work, code generators work, code generators work, please check out my please check out my please check out my talk from talk from talk from 2021-2022 at JetBrains .NET 2021-2022 at JetBrains .NET 2021-2022 at JetBrains .NET Developer Days, where I Developer Days, where I Developer Days, where I went into detail about how a went into detail about how a code generator works. But just to code generator works. But just to highlight the APIs you highlight the APIs you highlight the APIs you need. So, we need. So, we need. So, we see that this is just an see that this is just an see that this is just an incremental incremental incremental code generator. We code generator. We code generator. We want to figure out what want to figure out what want to figure out what exactly we want exactly we want exactly we want to intercept, so we to intercept, so we look look at the syntax tree using the syntax provider.

  26. at the syntax tree using the syntax provider. at the syntax tree using the syntax provider. Cool Rider feature. We Cool Rider feature. We Cool Rider feature. We can take a look at the can take a look at the syntax visualizer to syntax visualizer to see what see what see what this this this C# syntax tree looks like. So, how exactly does Roslyn C# syntax tree looks like. So, how exactly does Roslyn C# syntax tree looks like. So, how exactly does Roslyn see our code. We see our code. We see our code. We see that we have a see that we have a see that we have a whole series of whole series of whole series of using directives. We have a using directives. We have a namespace declaration, delimited by file , in that , in that , in that namespace. We have a namespace. We have a namespace. We have a class declaration, class declaration, class declaration, fields, and methods, fields, and methods, fields, and methods, including this initialization method including this initialization method I'm looking at, and so I'm looking at, and so on. This is the whole tree, this is on. This is the whole tree, this is on. This is the whole tree, this is how Roslyn sees the code, and this is how Roslyn sees the code, and this is how Roslyn sees the code, and this is how the code generator how the code generator how the code generator sees the code. So we sees the code. So we sees the code. So we scan the code for scan the code for scan the code for things we things we things we want to intercept. The want to intercept. The want to intercept. The ASP.NET Core team is looking for ASP.NET Core team is looking for ASP.NET Core team is looking for these map get and map post methods these map get and map post methods . If she wants to . If she wants to . If she wants to intercept them, she can intercept them, she can intercept them, she can ask the semantic ask the semantic ask the semantic model to get a model to get a model to get a place to place to place to intercept. This intercept. This interception location contains interception location contains information about what information about what information about what needs to be done to needs to be done to needs to be done to create this attribute create this attribute create this attribute on the on the interceptor method. And interceptor method. And interceptor method. And when we actually when we actually when we actually generate the code, we generate the code, we generate the code, we call the call the call the get intercepts get intercepts get intercepts location attribute syntax. And then we'll location attribute syntax. And then we'll location attribute syntax. And then we'll look at the look at the look at the implementation here. We implementation here. We implementation here. We see what is actually going to see what is actually going to see what is actually going to happen. It happen. It happen. It generates an attribute, this generates an attribute, this generates an attribute, this attribute intercepts location with attribute intercepts location with attribute intercepts location with version one in our version one in our version one in our case and a case and a case and a data string containing the data string containing the data string containing the file path, string, file path, string, file path, string, character position, and character position, and character position, and also a specific hash.

  27. also a specific hash. I hope I I hope I answered all answered all answered all potential questions potential questions potential questions about interceptors and about interceptors and about interceptors and native AOT. If not, then native AOT. If not, then native AOT. If not, then I think now is the time to I think now is the time to I think now is the time to answer them. answer them. Oh, yes. This is, as always, a Oh, yes. This is, as always, a fantastic session with a fantastic session with a fantastic session with a great dive into great dive into great dive into some of the "deep magic some of the "deep magic " that goes on behind " that goes on behind " that goes on behind the scenes. I the scenes. I the scenes. I had no idea that so much was had no idea that so much was had no idea that so much was going on " going on " under the hood" of web under the hood" of web applications. I didn't know applications. I didn't know applications. I didn't know that the .NET team that the .NET team that the .NET team developed these developed these developed these interceptors, interceptors, interceptors, code generators, etc. code generators, etc. But this is a really But this is a really cool feature. cool feature. cool feature. Were the interceptors Were the interceptors Were the interceptors added specifically for this added specifically for this added specifically for this use case use case ? Because I always thought that ? Because I always thought that ? Because I always thought that interceptors were a interceptors were a interceptors were a somewhat niche function. somewhat niche function. If I If I remember correctly, the first remember correctly, the first remember correctly, the first interceptor interceptor interceptor used by the used by the used by the .NET team was the .NET team was the request delegate generator. So I can request delegate generator. So I can assume that I'm not assume that I'm not assume that I'm not sure if it was sure if it was sure if it was specifically specifically specifically designed for minimal designed for minimal designed for minimal API in native AOT.

  28. API in native AOT. Mhm. But overall, I can But overall, I can imagine it was imagine it was imagine it was created to created to created to facilitate facilitate facilitate native AOT scripts. native AOT scripts. Yes. Yes. And theoretically, you don't And theoretically, you don't And theoretically, you don't need an need an need an interceptor. You interceptor. You interceptor. You could also just could also just could also just generate the code at generate the code at generate the code at compile time, but compile time, but compile time, but then you would have to then you would have to then you would have to update the source update the source update the source code manually. So, code manually. So, code manually. So, the interceptor is a the interceptor is a the interceptor is a nice, yes, nice, yes, nice, yes, nice nice nice user user user experience. You just experience. You just experience. You just need to enable the need to enable the need to enable the checkbox and it checkbox and it checkbox and it will work because will work because will work because the compiler does the compiler does the compiler does the substitution behind the substitution behind the substitution behind the scenes. the scenes. Hmm, yeah, it's amazing that there's some kind of magic happening behind Hmm, yeah, it's amazing that there's some kind of magic happening behind the scenes the scenes . I . I even like it even like it even like it when when when magic happens that I didn't magic happens that I didn't magic happens that I didn't know about. I always know about. I always know about. I always worry when there is worry when there is worry when there is magic that I know about magic that I know about magic that I know about because I think something could because I think something could because I think something could go wrong. But if go wrong. But if go wrong. But if I don't know about it, and I don't know about it, and I don't know about it, and it just works, it just works, it just works, then it's like: "Oh, okay. then it's like: "Oh, okay. then it's like: "Oh, okay. It just works that way. It just works that way. It just works that way. And I am satisfied with that. And I am satisfied with that. And I am satisfied with that. So, that's good. But, no So, that's good. But, no , I really , I really , I really enjoyed this enjoyed this enjoyed this deep dive. deep dive. deep dive. It fits in It fits in It fits in my head.

  29. my head. my head. Honestly, that's all the logic Honestly, that's all the logic Honestly, that's all the logic I need. I need. I need. I understand you. I understand I understand you. I understand I understand you. I understand you. So, besides you. So, besides you. So, besides performance, what performance, what performance, what other reasons are there why you other reasons are there why you other reasons are there why you might might might use AOT, use AOT, use AOT, say, in a say, in a general- general- general- purpose web application or purpose web application or purpose web application or elsewhere? elsewhere? From what I've From what I've encountered, there are one of encountered, there are one of encountered, there are one of two reasons. It's either the two reasons. It's either the two reasons. It's either the startup speed, startup speed, startup speed, so that you essentially so that you essentially so that you essentially get, well, get, well, get, well, your web API ready your web API ready your web API ready in, I don't know, a tenth of the in, I don't know, a tenth of the in, I don't know, a tenth of the time of JIT time of JIT compilation. In particular, a compilation. In particular, a compilation. In particular, a console application. console application. Now, for .NET 11, the Now, for .NET 11, the .NET team .NET team .NET team is translating not all, is translating not all, is translating not all, but some parts of the but some parts of the but some parts of the .NET SDK to native AOT as well, .NET SDK to native AOT as well, .NET SDK to native AOT as well, just to make it work just to make it work just to make it work faster, because command faster, because command faster, because command lines are usually very lines are usually very lines are usually very short-lived. Well, not short-lived. Well, not short-lived. Well, not MCP servers, but regular MCP servers, but regular MCP servers, but regular command lines are very command lines are very command lines are very short-lived, so short-lived, so short-lived, so they they they start up quickly and start up quickly and start up quickly and disappear quickly. So disappear quickly. So , for scenarios , for scenarios , for scenarios like startup speed, like startup speed, like startup speed, or if you're in or if you're in or if you're in environments where you can't environments where you can't use a JIT compiler, compiler, compiler, like on like on like on iOS devices because of the iOS devices because of the iOS devices because of the " " exclusive OR" security feature where you can't exclusive OR" security feature where you can't exclusive OR" security feature where you can't generate code generate code generate code and run it on the and run it on the and run it on the same same same memory page, or something like that memory page, or something like that . So, in this

  30. . So, in this . So, in this case, we need case, we need case, we need native AOT, and the Maui team is native AOT, and the Maui team is native AOT, and the Maui team is now also moving now also moving now also moving to core CLR, and previously to core CLR, and previously to core CLR, and previously they used Mono, and they used Mono, and they used Mono, and Mono also had...it was Mono also had...it was Mono also had...it was n't native AOT, it was Mono AOT. n't native AOT, it was Mono AOT. So, AOT has So, AOT has always existed, but with the advent of always existed, but with the advent of always existed, but with the advent of native AOT, it's a significant step native AOT, it's a significant step native AOT, it's a significant step forward, especially for the forward, especially for the forward, especially for the two scenarios two scenarios two scenarios I've encountered so far I've encountered so far . . You know, I'm You know, I'm old enough to old enough to old enough to remember the remember the remember the NGen tool that we NGen tool that we NGen tool that we used to use for used to use for used to use for this kind of thing, and this kind of thing, and this kind of thing, and one of the reasons why one of the reasons why one of the reasons why it was it was it was abandoned in abandoned in abandoned in favor of this was so that favor of this was so that favor of this was so that you could you could you could compile the code to compile the code to compile the code to machine code and save machine code and save machine code and save those few seconds, those few seconds, those few seconds, especially in web especially in web applications and things applications and things applications and things like that in very like that in very like that in very old versions of .NET. old versions of .NET. So this actually So this actually solves a lot of these solves a lot of these solves a lot of these problems. Therefore. Interesting. problems. Therefore. Interesting. problems. Therefore. Interesting. And these days, if And these days, if And these days, if you have a web application, you have a web application, you have a web application, you actually have quite a you actually have quite a you actually have quite a few few few code generators. You have a code generators. You have a code generators. You have a code generator for JSON code generator for JSON so that you don't have to perform so that you don't have to perform so that you don't have to perform complex operations while the complex operations while the complex operations while the application is running.

  31. application is running. application is running. Also for Also for Also for configuration, for configuration, for configuration, for validation, a lot of validation, a lot of validation, a lot of things, to remove things, to remove things, to remove a lot of reflection, not a lot of reflection, not a lot of reflection, not only to only to only to improve improve improve performance, but also performance, but also performance, but also for compatibility with native for compatibility with native for compatibility with native AOT. As far as I know, AOT. As far as I know, controller-based APIs do not have controller-based APIs do not have similar capabilities similar capabilities , so they are not yet , so they are not yet , so they are not yet compatible with AOT. I'm not compatible with AOT. I'm not compatible with AOT. I'm not sure, I sure, I sure, I need to check the need to check the need to check the status of this direction. status of this direction. status of this direction. But yes, minimal APIs But yes, minimal APIs are a different matter. are a different matter. Depending on...Well, Depending on...Well, if you have any if you have any if you have any code using code using code using manual reflection, manual reflection, manual reflection, then you need to then you need to then you need to change it. These change it. These change it. These warnings warnings warnings will pop up immediately. But if you are will pop up immediately. But if you are will pop up immediately. But if you are not using not using reflection-based code or a reflection-based code or a library that is not library that is not library that is not native AOT compatible, if native AOT compatible, if native AOT compatible, if you only have compatible you only have compatible you only have compatible dependencies, you can dependencies, you can dependencies, you can simply change the simply change the publish settings and publish settings and try if try if try if it works for your it works for your it works for your scenario. But scenario. But scenario. But be sure be sure be sure to remember that the JIT to remember that the JIT compiler is a beast, compiler is a beast, compiler is a beast, it it it optimizes itself optimizes itself optimizes itself using on- using on- using on- stack replacement (OSR) and a bunch of other stack replacement (OSR) and a bunch of other stack replacement (OSR) and a bunch of other words that I can't words that I can't words that I can't remember right now. It's a kind of remember right now. It's a kind of self-optimizing self-optimizing machine. There machine. There machine. There 's also a 's also a 's also a multi-level multi-level multi-level compilation there, right?

  32. compilation there, right? compilation there, right? Multi-level Multi-level Multi-level compilation, yes. All of compilation, yes. All of compilation, yes. All of this. So, as with everything this. So, as with everything this. So, as with everything related to related to related to productivity: productivity: productivity: measure, measure, measure, measure, measure, measure, and measure again. and measure again. and measure again. Very quickly, before Very quickly, before Very quickly, before we go any further, do you we go any further, do you we go any further, do you think there are any think there are any think there are any reasons... Well, would reasons... Well, would reasons... Well, would you use you use you use AOT for your web AOT for your web application? You just application? You just application? You just mentioned that it can mentioned that it can mentioned that it can help speed up help speed up help speed up work. If you have a work. If you have a work. If you have a regular regular general- general- general- purpose web application, is it worth purpose web application, is it worth purpose web application, is it worth using AOT, using AOT, using AOT, or is it too much? or is it too much? or is it too much? If it is If it is If it is short-term, then yes short-term, then yes . If I quickly . If I quickly . If I quickly start it and start it and start it and shut it down again, for example in a shut it down again, for example in a shut it down again, for example in a container or container or container or Azure Function style, I Azure Function style, I Azure Function style, I think so. But think so. But think so. But if the program is if the program is if the program is long-running, running for long-running, running for long-running, running for hours or longer, I hours or longer, I hours or longer, I would choose just- would choose just- in-time (JIT) compilation. Uh, I didn't in-time (JIT) compilation. Uh, I didn't fully read fully read Steven Toub's post about Steven Toub's post about performance improvements in .NET 11 . Well, calling it . Well, calling it . Well, calling it a post is a post is a post is putting it mildly. This is a whole putting it mildly. This is a whole putting it mildly. This is a whole book. But yes, there book. But yes, there are always improvements in the JIT compiler. Therefore, for CLI applications, I try try to ensure to ensure to ensure compatibility with native AOT by default.

  33. compatibility with native AOT by default. Of course. Of course. Fantasy. Uh, we're out of Fantasy. Uh, we're out of Fantasy. Uh, we're out of time. So, time. So, time. So, thank you very much for a really thank you very much for a really thank you very much for a really interesting session. Again interesting session. Again interesting session. Again , I love these , I love these , I love these dives into what dives into what dives into what goes on behind the goes on behind the goes on behind the scenes. Uh, I scenes. Uh, I scenes. Uh, I shared shared shared links in the chat links in the chat links in the chat if you want if you want if you want to see more, to see more, to see more, like like like Stefan's previous presentation Stefan's previous presentation Stefan's previous presentation here, which was about here, which was about here, which was about code generators, which is code generators, which is code generators, which is also just also just also just fantastic. Uh, you fantastic. Uh, you fantastic. Uh, you can find them in the can find them in the can find them in the chat. In the meantime, chat. In the meantime, chat. In the meantime, thank you very much, Stefan. thank you very much, Stefan. thank you very much, Stefan. We hope We hope We hope to see you again soon. to see you again soon. to see you again soon. Thank you very much for Thank you very much for Thank you very much for inviting me and I inviting me and I inviting me and I look forward to the look forward to the look forward to the rest of the day.

No summary available yet.

View original episode ↗