Full transcript of “.NET 10 Preview 6 Unboxed - Blazor State Persistence, Passkey, & What is DNX?”. Click a timestamp to open the video at that moment. Need another video? Use the YouTube transcript generator.
0:00 Heat. Heat. [Music] Feel [Music]
0:45 hey. [Music] [Applause] [Music] Heat. Heat.
1:33 [Music] Heat. Heat. N. [Music] Heat. Heat. N. [Music] Heat. Heat. N. [Music]
2:31 Oh my goodness. Hello everyone. Welcome to Net Unboxed. James is out of the country, so they left me in charge. Let's see what I can mess up here. I'm happy to be joined today by Dan, Chat, and Joel with some amazing things, including a cool surprise um that Joel's gonna wrap up with at the very end. So, welcome folks. Um all right, I guess we'll just get right into it because I don't know what I'm doing. So, I'm gonna kick Chat and Joel out of here and and you'll you'll hang out backstage. you're not totally off the hook. And uh we'll get going with Dan's stuff. So Dan, yes. Hello. How's it going? Overachiever showing up with some slides. What do you got? I know. I know some of these things are
3:17 a little harder to show other than in like massive hypers scale production environments, but uh they are still pretty cool. So I thought we would uh share share them. Yeah. Let's uh wanted to talk a little bit about the new ASP.NET Core features in .NET 10 preview 6. It's now out the door. It's in available to be downloaded which is which is great. It's a pretty packed release. Yeah. So I'll just go ahead. That is that uh I will disappear. You go for it. All right. Sorry. Okay. Cool. Yeah. So first of all um one of the great new improvements in net 10 preview preview 6 is that Kestrel our built-in HP server is now much smarter about how it handles memory. Uh Kestrel in its inards under the hood. it will pull memory to avoid allocations and it grows its memory pool
4:02 as needed based on whatever load is it's currently under. Uh but previously it never released that memory. It just held on to it even if traffic later dropped. Um this became an issue for some of our uh internal Microsoft partner teams like Azure App Service uh which use Kestrel to actually handle billions of requests per day on their on their front end. after a traffic spike, they would see a spike in memory usage that would just stay stuck at that high watermark. So, we've been working with them on this problem for for a little while now. Uh we've tested various uh approaches with them in production on how we could improve this. And the chart that you see on the screen shows the the new behavior. Uh unused memory, as you can see, is uh is going is being evicted and the total amount of memory is is going down, which is what you what you want.
4:49 Um so this is great for you know hypers scale services like Azure app service but it's also great for all of you. Uh these improvements are now built into the framework in net 10 preview 6. Uh you get them by default. You don't have to change anything. Uh and I think this is really a great example of how Microsoft's experience using asp.net core uh at scale uh results in platform benefits for everyone. You get better scaling uh lower idle costs and smarter resource utilization uh thanks to these improvements. Next, uh, I wanted to share some updates about our validation support, the new validation support that's int net 10. You may have seen previously that we added support for validation to minimal APIs uh, in earlier .NET 10 previews and that included support for validating
5:36 nested complex models. Well, uh, these validation capabilities are now available for Blazer 2. Uh this means you can now validate nested complex models in your blazer forms uh just like you can in minimal APIs. Uh we've integrated this new support into the existing uh uh data annotations validator component uh so you can use it to validate your models in a familiar way. Uh both minimal APIs and blazer use a shared validation implementation which we've now moved uh to Microsoft extensions.validation. The validation APIs themselves are currently still experimental int net 10. Uh but the validation functionality in net 10 that's used by by blazer and minimal APIs is uh will be fully supported. So I thought I would show you that. Let me show you some of the uh
6:21 validation improvements. So I've got here uh a um uh this is a aspet core app that has both minimal API and uh blazer logic wired up in it. Below we can see our our single minimal API endpoint. this map post uh endpoint which uh takes in an order model. And if we go to the definition on that, we should be able to see what that model looks like. And here it is. And this is a fairly you know complicated model. It's got uh you know customer details which is a complex type. It's got a list of order items which are all you know complex types themselves. If we look down at the the customer model it's got you know a shipping address. And then if we look at the orders they have their own their own properties too. So you know deeply nested structure and you can see that
7:07 we've uh annotated all these properties with various you know validation attributes various data annotations to say how this data should be validated and we can test this now with our minimum API like if I have a an HP file set up here and if I just go ahead and uh send a request there's a this is a valid request so it doesn't have any validation issues and you can see we got a 200 okay which is what uh what we want. If I do some mangling here though of the data like let's uh make this no longer look like an email address and let's uh request uh you know an excessive number of of widgets and if we resend this request you can see now we get actual validation errors for minimal API. So an invalid email address and an invalid uh quantity for that that property that shipped before that part's not new int net 10 uh preview 6. But
7:53 what's new is that in this app let me undo those changes. In this app, I also have a Blazer uh component, this homepage which has a a Blazer form on it and it's using the normal Blazer data annotations validator component. Uh but this component has now been uh enabled to do complex object graph validation without without uh any other change to to the form. The data annotations validator previously would only go like one layer deep like it would only uh validate your top level properties. This has been a long-standing ask in Blazer. I think at one point we even had a uh you know a separate uh comp validator component implementation like an object graph data annotations validator component that shipped in preview but it never shipped a stable version. Uh this functionality is now built in to the uh
8:40 existing data annotations validator and below you can see we're you know present uh uh uh displaying all the validation messages associated with the model. Um to light up this functionality in the data annotations validator, you do need to make one one change, which is just to turn on the new validation system, which is this uh API call right here. In program CS, just make sure you call add validation, and then that new functionality will light up for your your Blazer forms. I think I've got that form already running over here. Yep. So, if I go ahead and like try to uh submit this form for that order model without making any changes, you can see that everything is currently invalid. And as I start typing in data, let's order some pizzas. This will be for me. And uh I don't know, dan example.com. An email
9:26 address. If I, you know, had messed up my email address, I get that same validation for email addresses that we saw before. Uh let's send this to Microsoft. And this is the zip code. Yep, looks good. And what should we order? Let's order some Hawaiian pizzas, which I know is controversial. So, we'll say, you know, hold the pineapple. And that looks good. And so, everything is now valid. If I instead, you know, put in like, you know, I want 120 uh Hawaiian pizzas without pineapple, then I get my validation errors as as as well. So, this all looks great. I can submit and it's a fully valid form. So that's complex object graph validation that's now enabled for blazer using the same exact validation infrastructure that we're using for min APIs new inn net 10 preview 6. Right? So
10:14 that's the new validation. Uh next uh we've also added support for webn and pass keys uh to asp.net core. This is something we've been working on uh for a while. Uh if you're not familiar with pass keys uh pass keys are cryptographic credentials that replace traditional passwords. And the great thing about pass keys is that they're fishing resistant. They're easy to use and they're secure by design. Uh pass key uh consists of a public private key pair that's scoped to a specific account and origin. uh the private key is typically stored in an authenticator app like that might be you know Windows or it might be a uh you know a separate device or you know a hardwarebased based key and the authenticator handles uh val uh verifying the user identity before allowing authentication with a a stored
11:01 pass key. So that's how it works. Uh we've been adding built-in support for pass keys to ASP.NET Core identity. Uh we've been taking a lot of inspiration from uh the open source 502 net lib library which is a really great uh open source project and we've been working closely with uh that project's maintainers. Uh we plan to support both resident and non-resident keys uh but we don't plan to support attestation for the authenticator in net 10. So that's one one area we don't plan to to handle at least not yet. Uh in net 10 preview 6 we've already updated the uh blazer web app project template uh to add the pass key support when you enable individual user accounts. Uh we plan to also uh update the blazer identity scaffolder as well in in a future update. Uh for your existing projects that are perhaps already using ASP.NET core identity uh
11:47 we will of course provide guidance on how you can manually add the uh the pass key support. So let's take a look at this. Let's try out the new pass key support in uh net 10 preview 6. So let me go ahead and create uh I'm going to create a new project from scratch. Let's create a new blazer web app and we'll just use the project template here. Let's call this uh blazer pass keys. Is that name used yet? Looks good. Okay. And I'm going to say that we'd like to use individual user accounts, which now has the new pass key support. I'll leave all the rest of the uh default settings. Now, it'll create me a project template that will include all of the uh component code for uh setting up as core identity. And as you can see here, there's even let me zoom in a little bit. You can see that there's some added code now for dealing with fast keys. So
12:33 let's go ahead and get this running so we can see what the the app looks like. Usually just take a second for for this app to build and get executing. But then we will try setting up a user account with this application that um has a pass key instead of using those old usernames and passwords that you easily forget and can be easily uh you know fished from front of you. Okay, here's the app. So it opened up on my other other monitor. Um now let's go ahead and register a user. Let's see. asking me and I'll just I'm going to start out by doing it the old school way, right, with a password and we'll go ahead and register that. Now, initially I need to set up the database with the database schema. So, this should give me a a page that says, "Hey, the database isn't there yet." Uh, do you want to set that up?
13:20 Let's give it a second to figure that out there. Okay. And so, I in order to set up the schema, you just need to apply the entity framework core migration. So, I'll go ahead and do that. And now when we refresh the page, we should see that we have a registered user and we can click on this link to simulate the like you know email confirmation. Okay. So now if I log in and we'll use my username and password initially. Uh if I go to my user account, you can see we now have a section for pass keys. And so I can add a pass key to my account. And now here this is this is my authenticator app, right? This is Windows saying, "Hey, this this browser wants to uh set up a pass key. Let me first make sure that it's you, Dan, that it's not someone else." So, it's asking for like my, you know, a PIN in this case. It could use a variety of techniques for doing that
14:06 verification. And you can see Windows has now saved a pass key associated with my user account for this for this origin that I can now should be able to use to to log in. And I can give that pass key a name. Let's just call it uh Windows. Uh and save that there. Good. So, now I have a pass key. Uh, if I wanted to add additional pass keys, I could. Like you could see I have options for adding a pass key that's stored on like, you know, my phone or UB key like style device or whatever. Uh, but I'm just going to use the one that I have currently on Windows. All right. So, use that pass key to to log in. I'm first going to log out. And then you can see that down here there's the option to log in with a pass key. And here, Windows says, well, what pass key do you want to use? Let's use this one. And it's going to again verify that I am who I say I am, that it's not someone else trying to log in with this pass key. And voila. So
14:52 now I'm I'm logged in to my my Blazer application using the new pass key support. Okay. So it's just that easy. Uh that's available now in the templates in .NET 10 preview 6 and we'll be adding it to the Blazer identity scaffolder as well uh in a in a future uh update much better authentication. It's pretty nice. Okay. Uh lastly thing the thing I wanted to show you is that uh one of the really big investments that we've been making in Blazer for 10 is support for uh state persistence. Now what is what is this all about? Um so Blazer today actually already uh has support for persisting component states uh when you're pre-rendering your components. So pre-rendering is when you like browse through a page and instead of waiting for like the web assembly
15:37 runtime to be downloaded or for the the circuit and the websocket connection to to be set up, you just go ahead and render some HTML directly from the server into the uh the server response. You're pre-rendering the the page. So you get HTML down to the browser as fast as possible and a much better uh initial load experience. Now some sometimes when when you do that, you often want to uh um take the state whatever state you used to pre-render the page, you want to reuse that state when the that page then gets set up for for interactivity, either using web assembly or using the the interactive server model. if you don't reuse the state, you can end up with sort of flickering patterns and it's just wasteful, right, to like um hit the database twice to to request the same data. Um, so we've had support in Blazer for a while for dealing with that problem for persisting that pre-rendered
16:23 state. And we have this like uh imperative uh API called the um persistent component state uh service that you can use for like saving some data into the page that can be uh reloaded later. It was a bit tedious to to use and so um in a previous in previous attempt previews. We actually added a declarative model where you can just attribute a property on your component and say this is my component state take care of the details for me and it involves much less code for you to persist your pre-rendered state. So that's already shipped and that's was kind of the first step in this uh blazer state persistence uh journey for fortn net 10. Now on top of that support uh we also want to improve the resiliency of your Blazer server apps by giving you the option to persist your circuit state when the client uh gets disconnected. Uh
17:10 in Blazer when a a user disconnects for an extended period of time. Uh and this can happen like like if they're in a on a phone and they swipe away from the browser and put the browser in the background. Often when you do that the browser will like kill all the connections because you know it's sitting in the background. It's not currently doing anything. Might as well save on power. I might as well save on resources. But then if the user, you know, comes back say 10, 30, 60 minutes later, uh, Blazer, well, when that disconnect happened, Blazer will have a a state on the server and it'll be like, well, the user just disappeared. They're no longer connected. It will wait a little while holding on to that server state, holding on to that circuit, but if the user doesn't come back within a certain timeout, and by default it's like three minutes, it just evicts the circuit. It kicks it out to save on those server resources. So if you have a user that you know disconnects from the
17:57 from the app for a prolonged period of time, they might come back to the app and they've lost all their state because the the circuit is is now gone. In net 10, we would really want to uh improve on that experience. So what we're doing is we're g we're giving you the ability to automatically persist the state of your circuits before they get evicted. Uh this means that if the uh client uh reconnects after a prolonged period of time uh the app can then restore that state and the user can then resume the work uh uninterrupted. Okay. So they can swipe away on the on their mobile phone, go to lunch for an hour, come back, swipe back and then you can reload the state that was persisted uh by the server when that circuit initially got evicted. So it can be effectively resumed. So that's uh you know improved resiliency that is now available in net 10 preview 6 and I'll show you that in
18:42 just a second. Uh the third piece of uh blazer state persistence is also improving scalability. You know each of those circuits that you uh you hold on the server is taking up server resources. Um some of the circuits might actually not be uh not may not be uh be actively used and so you might want to free up those circuits by persisting them uh and then reload them later when they're actually needed. Now this is not something that we are planning to do automatically for you in Blazer and 10, but we're giving you the APIs so that you can implement an appropriate policy for your app. Like maybe, for example, if the browser is no longer visible um that the user is using, might as well persist that circuit and free up the state because the user is obviously not using the app. Or maybe if the circuit is idle, like you detect on the server that nothing's happening on the circuit,
19:28 it hasn't happened for like 10 minutes, you could persist the state and then uh rehydrate it later. Okay, so let me let me show you a little bit of of what I mean. Okay. So, let's go back to our uh Blazer Pas keys app and we'll use this and we have um a little bit of uh interactive server functionality in this application. Like if I go to the counter page, you can see I can click the count and the uh the count goes up. Now, uh remember I said that when the if a user disconnects from the server, server will hold on to the circuit state, the server state for a few for a little while. By default, it's three minutes in case the user tries to reconnect. And if if they reconnect within three minutes, everything's good. If they don't, then that's when the problems occur. Now, I don't want you to have to wait the three minutes to for the circuit to actually get evicted. So, I'm going to do a
20:14 little bit of a tweak to the app. Let's go in right here and let's change this to set this setting. I'll make it a little bigger so you can see. So, I'm just setting the the disconnected circuit max retained to zero. That's basically telling Blazer, don't hold on to any circuits. a victim immediately if the uh if the user disconnects. Okay. So, let's go ahead and restart that. So, we get the new behavior. And that will allow me to simulate a disconnected user a little bit easier when I'm on like a a live live stream call. Okay. So, that should be now be running. And let's go back here. Okay. So, what I'm going to do is let's um let's make sure we're let's bring up the browser dev tools and let's uh refresh the page. Okay. Now, let's make sure our circuit's working.
20:59 It's working. Okay. So that the user now has some state. They've clicked on the the counter six times and they don't want that to go away. That was an important number for for whatever reason. Now to simulate a um a disconnect where the client actually disconnects from the server. I can't exactly yank my network connection right now because we're we're talking. Um so instead I'm going to use this internal Blazer uh uh API that's just for demo purposes. This is not something you should be using in your apps. This is going to allow me to sort of force the browser connection to be closed just using the browser dev tools. Okay. Now watch what happens over here in the uh to my my counter. Ah that's a empty cache refresh. Let me do that again. So got some state and let's force the connection to close. And you can see that the it was very quick but the the the the browser detected that it was no
21:46 longer connected to to the server. It tried to to reconnect. The server was still there. So it was able to reconnect but when it did the circuit was gone. and starting in like .NET 9, what Blazer does is it will just automatically like refresh the page and and basically say, well, I'll start again and create a new circuit. So, we lost our state. This is effectively what happens to like your, you know, Blazer server mobile users when they swipe away from the app for for a long period of time. Okay, how can we fix this? So to fix this, what we're going to do, let's go back to our app and let's go to our counter component. And I'm going to instead of having the state just be uh in a field, let's update it now so that it can be persisted. So I've got this current count property. And now it's got the supply parameter from persistent component state property, which basically says this is state for this component that should be persisted. And
22:32 let's uh update the component. So this fully compiles and that should now now allow us to um uh persist our circuit and hopefully resume it. Let's see if that now works. All right, so we should be back up and running. Let me clear all the cache. Make sure we don't have anything stale kicking around. And let's go ahead and get some state. Let's get uh you know, we're up to 10. Okay. And then I'm going to kill the connection one more time. That same issue. I'm not sure what why it keeps happening. Let me do that one more time. Reset that. Set the state. And you can see so this time I killed the connection. The bl uh the circuit on the the server was evicted because we said don't keep any circuits. When blazer tried to reconnect um the server was
23:18 able to basically re hide reload the the persisted state and we kept our current count at at six. Okay. So that should help make your blazer server apps more resilient. The other part of this is also making them more more scalable. And to show that I'm actually uh I'd like I'm going to uh use net Aspire and some of the new metrics that we've added in net dev. Let me close this app and let me go back to uh the Visual Studio. What I'm going to do is I'm going to enable Aspire for my Blazer app. If you if you've never used Net Aspire with Blazer, you should. It's great. It really helps improve the developer experience. Um there is a little issue right now that Net Aspire has not shipped support for .NET 10 yet. So if I try to do like rightclick add net aspire orchestrator support which is the easy way to add Aspire to your blazer app. Currently it'll say hey I can't find templates for for net 10. So there's a
24:04 quick workaround for that which is just I'm just going to uh uh downgrade this back to net 9 just really quick while I add Aspire support and then we'll switch it back to 10. So now that should allow me to add Aspire. Great. And the net 9 version of Spire works fine with with with net 10. They just haven't shipped the official net 10 support yet. And then let's make it go back to to 10. Okay. And then I also want to use the new metrics in uh Blazer int net 10 so we can see what's happening to our circuits as we do something something fun. So I'm going to go into the this share uh service defaults project in the extensions uh file and I'm going to add some more meters. I'm going to add the blazer meters the Microsoft Acemate core components and Microsoft as core components uh server circuits. And you can imagine that that's the one that's
24:50 going to be really useful for us to see what's going on with our circuits. Okay. And that's it. That's how easy it is to add Aspire. So now let's uh get this app running. And this should bring up the super fancy Aspire dashboard, which by the way is also implemented in Blazer. And then we can see if we can make our app more scalable. So get this run. Succeeded. Just waiting for the browser to pop up. So well like I was saying before you know every time some a user connects to your blazer server app you have to create a circuit and now there's state on the server for each user that's connected whether that user is actively using those resources or not like they might have started the app and then gone
25:36 off to lunch. Uh so what we can see here is if I bring up the app and let's put this side by side with the dashboard. Here's our dashboard. In the dashboard in Aspire we can go see all of our metrics really really easily. So, if I go and look at the metrics for my Blazer application and then let's uh let's get a a circuit going by going to the counter page. There we go. So, we've got a counter. You can see now these um these metrics right here, these uh server.cscircuits metrics. Let me see how many active circuits I have and how many of them are actually connected to the user. I actually have an active network connection. And so, if we look at this right now, we should see we have one circuit. And yes, that's what we have. We've got one. In fact, it's a little easier to see in the table. We've got one circuit. If I like duplicate the tab, we should have uh two circuits. Yeah, now we've got two. And if I duplicate again, I should have three circuits. So, every time we get a new
26:22 user, we allocate a new circuit and we're using server resources. I close one of these, it should go down once the browser Yeah, there. There we go. So, now we only have two active circuits. And that's fine. Uh, but you can see that like when I have these two browser tabs open, like I'm only using one of them. Like I'm not using both of them at the the same time. So, is there really any point in having two active circuits on the server? Uh, no. So, what I can do is let's add a policy to our app to free up those server resources when the app isn't currently visible. And to do that, let's go back here to our components. And I'm going to find the app.razer file. And I'm just going to add a little bit of JavaScript. This this API is a client side JavaScript API, but it's pretty easy to use. So, here we have Blazer pause and Blazer resume. That's
27:08 going to allow me to explicitly say, "Hey server, go ahead and pause. The app's not is not being used. Go ahead and persist the circuit state when you pause." And then resume says, "Hey, start it up again." And here's uh use whatever state was was actually persisted. And we're doing this whenever the visibility of the app changes. So if the app is hidden, then go ahead and pause the app. If the app becomes visible again, then then resume. Okay, pretty pretty simple. Let's go ahead and hot reload that into the the app. Let's close this down. We'll refresh so we get those changes. And now if we go back to the Aspire dashboard. So currently it should say we have one circuit. Yeah, we have one circuit. And now if I duplicate the tab, notice it doesn't it doesn't change. Like I can uh I can duplicate again. Like it's still saying I've got one at the top there. You see that? I've got
27:53 one circuit. If I but if I grab one of these tabs, let's make it visible by pulling it down here. So now I've got one, two circuits. I'm not sure why it's saying three. Is that because it uh I think the third one might have popped into view momentarily. Can I can I close it? Okay. Yeah. Now we're to to back to two. So we have two active circuits. And if I hide one of these tabs again, so now we only have one visible tab that should trigger the the browser visibility notification. There it goes. Yeah. So now we only have one circuit. Okay. You see? So as the you know uh the browser is visible or not, you're able to save on server resources by pausing and resuming those circuits. Okay. So that's the uh laser state persistence uh features that's now available in net 10 preview sex automatic um persistence of evicted
28:38 circuits that when the client gets disconnected and then API so you can implement a policy for making your apps more scalable by explicitly pausing and resuming uh circuits. So that's just some of the stuff that's new in ASME core and .NET 10 preview 6. There's a whole bunch more. I'll point you to the the release notes to to check out all of the new functionality. And that is what I've got for you guys today. Dan, that's a ton of stuff. Is there So, as I was going through and helping with the release, so much of the stuff this release was net 10 preview 6, did stuff just kind of line, sorry, was ASP.NET for this release. It just kind of lined up that way. I mean, yeah. I mean the the some some
29:24 features take longer than others and take multiple milestones. So you might have like you know kind of uh uneven uh um distribution of the of the when the features ship on on any given milestone. Uh but yeah this happened to be a fairly feature uh functionality rich release for us and we're I think we only have we have one more preview left right like preview 7 I think is the last official preview for net 10 before we go into release candidates. And that's when we expect to be uh you know functionally complete in terms of the uh you know new features. Of course, we'll still be working on bug fixes and stuff after after that and polishing it up uh uh getting things ready for for production. Uh but that's that's where we're at. We're getting pretty close. So wrapping up those big features was kind of uh important at that at this stage in the release. Okay. Well, I want to say make sure we
30:09 have enough time for a chat and Joel, but we've got three questions. So if we can go relatively rapid fire through these. Okay. Is there a way to set the same behavior without attributes? This was for your first demo where you're showing the validation support. Um, so the validation model here is based on system uh component model data annotations. So it's a data annotations based based model. Um, there is like you know a low-level interface like I validatable object or something like that that you can put on the the type that allows you to you know define whatever arbitrary validation logic you want for for the whole whole type. So that's that's an option uh in that model but it is primarily a a declarative uh validation model. Cool. Um let me see this was a question on um the stateful persistence stuff. So
30:58 a question about sticky connections and server resource use. Yeah that's a great question. You know one thing I didn't mention is like when you persist where's the state stored? So when the circuits get uh evicted and you're persisting the the circuit state um by default if you don't do anything it'll just it'll actually store that state just in memory. So it'll be in memory on that that server. So sticky sessions would still be important then because you need to be able to connect you want to connect back to that same server to get that persisted state just like you would with um you know your reconnection logic if the circuit the whole if the whole circuit is actually still in in memory. But what you can do is if you're using uh hybrid cache which is a you know multi-tered caching uh uh abstraction which will do both in-memory uh you know local in-memory uh caching as well as distributed caching like with Reddus then um the blazer state
31:45 persistence uh logic will just pick that up and and use that instead. So then you could have state stored in your like in your distributed cache and it could be picked up from from there. And then I think potentially in that case you the the sticky sessions becomes less less uh critical. But you'll probably still want it though like you you'll still want it for like uh like the reconnection case where the circuit hasn't been evicted yet and you just want to come back to it. In general you'll I think sticky sessions are are still to stay in in in Blazer server for for a while. But what you you save on is the number of circuits that you're having to keep in memory. Um that can that can be pushed down. Okay, one last question for you and this is just about the supply comp parameter from persistent component state. People don't like that.
32:33 Uh yeah, we know so uh this is actually being changed for PB7. Uh I believe the API we this when we when we uh defined this attribute the the engineer who worked on it Javier deliberately picked the the longest most uh obscene attribute name he could because he knew when it went through the API view review process which we review all of our new public API surface area as a team and discussed like what's uh is this what's the right name for this what's how can we make it as clear as possible u make it consistent across the whole framework we do all that u with each um each new API uh he knew that this was going to have uh going going to have some debate. Um the API review is done for this and I believe it's persistent state attribute is where we landed for for this attribute. So there is a new attribute name that's coming in preview 7 that will be much shorter. So don't get too
33:18 attached to supply parameter from persistent component state. It will be uh getting an up a facelift. Okay. Awesome. All right. Well, that was amazing stuff, Dan. I've got to bring on chat. Um but thanks a bunch. And you've set a very high bar here for chat to follow. So thanks good luck with that chat. I mean I may not have supply parameter from persistent component state but I have MS build project XML. Okay that's pretty good. Everyone loves XML everybody. Um so I mean the XML is in service of what I think is one of the the more unique features of the .NET CLI which is uh tools right there. There are lots of parallels for these things in
34:04 different ecosystems. Uh but the the core idea is wouldn't it be great if there was an easy way to distribute .NET binaries so that other people who have the .NET SDK can easily go grab them and run them. And they've been massively successful. Like you see this uh in uh in Go, you see this in npm, right? this concept of my project provides some binaries that I can use to do X and easily get them and collect them and pin their versions and that sort of thing. Super useful. And up till now it's like you could do it, but it's not like kind of natively, right? It's like something they've been this kind of weird side thing. Uh if you pop up my um my screen, we can actually sort of talk about what
34:51 makes a tool today. Okay, just a second. add to stage and then I have to do a new thing here because there and add to sta I have to remove Dan that was the problem there we go okay I'm going to disappear and you go for it okay sounds good so this is a tool as it appears today tools are what we call framework dependent runtime agnostic binaries right so when you run net pack and you have the pack as tool MS build project file property set. The .NET SDK takes over and builds your application, adds some additional metadata and then shoves it in this format and then later commands like .NET tool install uh global and and whatnot
35:38 and .NET tool restore will then acquire and make these packages and their contents executable uh by the end users. The key thing that makes a tool a tool well there's sort of two pieces. One is this package type net tool. But just as important is this file called net tool settings XML. And the point of this file is to say that when we run this tool or when you install this tool package, you will get access to this command and you invoke it using net pointing at this thing. And all of this is orchestrated for you for free by the .NET SDK. We love our framework dependent runtime agnostic tools because they're easy to use. If you have a .NET
36:26 SDK, then any tool available today that you know matches your target framework your runtime identifier or your target framework versions can run right. They're uh very portable is is what we say. But there are some downsides to this layout here. Um, as anyone who has like built a framework dependent application or a portable application before knows, this means when you bundle your application, you end up with a whole bunch of runtime specific assets. So, if you've ever looked at a layout like this and you've seen the runtimes folder with a whole bunch of runtime specific uh bits in there for Linux x64 and Winx64 and Mac OS ARM 64, you're
37:13 carrying all of those bits for every single platform along with you. And no matter what platform your users are on, they're going to pay the download cost of every single one of those other platforms. And so we took a look at this structure and we said we think we can do better. We think we can support platformspecific tools if we want. And that's the big headline feature of for the SDK and .NET tools in preview 6 is supporting these uh platform specific tools. What I've got here in this repo, this is a repo called Baronfell/multi tool. This is a sample repo I've been working on, but we have a little program
38:01 called tools that uses spectre.conole to create some figlet text. This is like as art that you may have seen other tools use if you've run the net tool or the cows tool. These are like in the same family here. But this tool is very simple. It lets you supply some text. uh it lets you pipe some text into the the application and if you don't specify anything then it will use spectre.conole console to prompt you for some text and then once you give it some text it will output it. Right? This tool doesn't have any runtime specific uh components to it but I would like to make it native to Windows or
38:47 native to Mac OS. Well, it's really easy int net 6. So assume I have all of this stuff set up for a a normal tool. This is all just stuff that you do to make a good Nougat package. You give it a package ID. You give it a version, you give it some description metadata and a license. The big thing that changes in .NET 6 is now you can specify runtime identifiers for your packages. And if you do this, then you can run Netpack just like normal. And I'm going to use this tool type property because I've set this repo up to have a bunch of different kind of scenarios here to show you all the choices you have. But I'm going to skip to a simple one and just say
39:33 uh we're going to try the self-contained version of this tool. And when we run this, this is where things will start to get different because you'll see our sort of agnostic package. And then you will see all of the runtime specific packages. And if we go look in our package output folder, I said if we go look in our package output fold, there it is. You will see a bunch of other packages. So I want to take you through uh I want to show you what's inside some of these. So the arrangement that you see here for these tools is the same name as we had before now, just with only our little mapping file in here. And if you crack these
40:19 things open, this file now describes a mapping of .NET runtime identifiers to matching implementation packages for your tool. But what's in those uh platform specific packages? Well, in this case, because this is a self-contained application, it will work. It has no target framework because it carries the runtime with it, but it is specialized for Windows x64. And so if we pop this open, we will see all of the DLS that are by default part of a U platform specific executable. And there's our exi and the DL chains to all
41:05 the things. So this is kind of a chunky chunky package similar uh for ARM 64 for all the other runtime identifiers I specified but I just want to show you that this works great. So here I am. I'm going to run net tool exec. Uh our tool name is tool say and the source I'm going to point to a local source in the artifacts package release directory. And this is the second new feature in net 6. Net tool exec is a command that does sort of npx style acquisition and execution in one shot. Right? So this is awesome because your docs or your getting started or whatever for your users can now just say net tool
41:52 exec your package. So in this case I want to run tool say I'll get a prompt so that it's not downloading things without my permission and then it immediately went in to run my app and there's there's my app run. And if I do this again the second time there's no prompt because it's already locally available and it works just great. This net tool exec works with any kind of package, not just these new platform specific packages. So you should feel free to use it today as long as you've got preview 6 installed. When we look at these packages, they're kind of big. Like there's no reason that hello world in some fancy asky text should be 30 megs.
42:39 And luckily the NET runtime team agrees with you because they've given us a whole bunch of tech that we can use to manage the size of our applications and all of those tools are compatible with the new ridsp specific.NET tools. So I've got the self-contained version that we just showed. Uh there's a bug so I can't show you the trimmed one but I can show you the super awesome AOT one. So to make all of this work, you've got to have a sort of agnostic package and then specific RID specific subpackages. Well, you can make those RID specific sub packages through net pack as well. So if we do our AOT tool type and use the uh
43:31 the new for net 10 preview 6 uh runtime flag on net pack. We can tell netac to AOT just the package for win x64. This is kind of a quirk of uh the .NET tool chain. You can only AOT generally for the platform you're on. So that took a second and it didn't take as long as it was supposed to because I forgot there's a bug in the SDK. That'll be fixed in preview 7. But if I blow that away and do the pack again, then we'll see it take slightly longer because AOTing applications does take a little bit longer. But then when we go look at our uh thing here, here's our here's our
44:17 package that we just made. It is only 1.8 megs. I want to make sure that you all see that. That is the beauty of AOT. And if we go look inside it now, it only contains the super small executable and the executable uh mapping that lets the .NET SDK work with it. So, if we come back here one last time and I clear out my uh Nougat packages directory and I run this one more time. I'm going to have to make um I'm going to have to make my marker uh package again. Do that real quick. Yeah. So, we can see our agnostic package is back there. So, we make that
45:02 guy one more time and then we do net tool exec one last time. re Oh, redownload it. Lightning fast AOT applications, baby. So, I'll pause for a second. The gist of what I'm trying to tell you now is the .NET SDK tools have more options and you as the user can figure out where you want to land on the spectrum of options. If you are happy with platform agnostic, runtime agnostic tools like you have today, keep making them. Everything still works with them. But if you need to lean into native platform specific tools for whatever reason, we've got
45:49 your back. You can do self-contained, you can do trimmed all the way to AOT. If you do want to do AOT, you have to do a little bit of orchestration yourself. My repo has an example of that. Essentially, you just have to matrix over the different platforms you want to support and call pack for the specific uh runtime identifier to make the individual packages. So, I've got an example here that shows all this. You have one step that builds all the platform specific packages, one step that builds the agnostic package, and then you can collect them all into a single artifact to publish up to Nugat. So that's what that's the the net new feature. But I wanted to show one last little
46:34 awesome thing here. Net tool exec. I hate typing it every single time. npm doesn't have to do that. You can npx and run any tool you want and it just feels natural. Why can't we do the same? Why can't I come over here and do something like this? Oh, it turns out I can because we did that for you, too. Starting in preview 6, you can DNx run any tool, automatically acquire it if necessary, and then invoke it. Boom, done. It is so freaking awesome, and I love playing with it. And I really, really, really hope all of you do too as well. Uh, at this point, I will stop, pause, take any questions or comments or whatever that there might be. What are what are we looking like, John?
47:22 unmute because that's what we do. Okay, I got three, but I want to make sure we have time for for um Joel, too. So, a few quick ones. Uh, one Jimmy said just kind of a thing to bring up here, but oh boy, now we have security issues like go. I did notice that you had like a prompt, right, that said before downloading. So, what are some talk about security? Yeah. So definitely uh you have to provide positive affirmation to install these things, right? The second time I ran it, there was no prompt because it was already local and and that kind of pattern you'll see all over the place. If the tool already exists locally, we can run it. If it doesn't, then we have to ask permission to acquire it. We would love your feedback on whether or
48:09 not to flow that through to non-interactive scenarios, meaning scenarios where tools or setup instructions or your CI/CD are running .NET tool exec or DNx. Today, even in like a GitHub action script using these tools, you're using .NET tool exec or DNx, you have to pass dashy. npm doesn't have to do that. Other platforms don't necessarily have to do that. let us know how you feel. Um, there's also the question of like managing versions and managing sources. All of these tools are Nougat packages. So, if you have a Nougat config that defines the allowable sources and if you have package source mapping set up, all of those uh like traceability mechanisms
48:56 work with tools as well. Finally, uh, one thing I didn't mention is that .NET Tool Exec and DNx are sort of they implicitly understand local tools versus global tools. If you are using a local tool config manifest to describe a set of tools and you invoke a tool via DNx that you have in that manifest, we will automatically only use the version that you have in that local manifest. So you can pin the versions that DNx use through a a local manifest like that or by a package at version syntax. Okay. Right. So you uh you have a few options and uh and the idea here is to always do
49:44 exactly what you tell us and no more. Awesome. Okay, let me see. Um, do one more question here. Uh, if I install the tool on Winx 64, it'll download that version only or other RDS. I think that's what you're Yeah. So, we navigate, we download that tiny top level package, crack into the sort of manifest that has in there and decide which of those packages is the best fit for the platform that you are on. So if we dig into this file, we've got Linux x4, Linux ARM, Windows x4, Windows ARM, and OSX on my machine. This is the best one. And so that's why we downloaded just that package. And I can actually
50:29 show you that code and get packages. We can see that just the top level package and the Winx64 package are present on my system. Um there is some interesting like uh bits and pieces there. If you pack for a runtime identifier and like it's not super specific, we will handle walking up the tree and find the most correct rid for the the platform that you're trying to run on. Right? So there's kind of a balance there. I've chosen these five runtime identifiers because they are the most broadly used across our ecosystem per our public uh telemetry data. But I mean you can choose whichever set you want and future enhancements to this whole feature coming in preview 7 will allow
51:16 you to mix and match these RID specific tools as well as a any tool which is just the like platform agnostic tools that you can make today. So you can have a built-in fallback to running non-native for platforms that you did not explicitly support. So look for that coming in preview 7. Very cool. Um, all right. Well, I want to make sure we have some time for Joel, so let's bring him up. And I love this because chat, like this all works together. I was joking before we started. There's a lot of things releasing that all just kind of magically came together. And um, so you showed off DNx, which is really cool.
52:01 And then Joel's gonna take it to the next level, I think, here. All right. Thanks a bunch, chat. We'll kick you off and we'll we'll get ready to see some Joel awesomeness. So, uh Joel, let me go ahead and I'll share your screen and I'll go ahead and disappear and let's see what you got. Yeah. So, what I wanted to share is a new um package scenario, Nougat package scenario. Essentially, it's packaging MCP servers inside of a Nougat package. So, if you're not familiar with MCP, it's a protocol uh introduced by Anthropic to basically augment your your copilot agent or your your LLMs with uh
52:48 knowledge not in the base uh in the base uh model. Um, so there's a whole ecosystem already out there of MCP uh MCP components um often written in JavaScript or Python and but there is a SDK for writing MCP servers uh using C. Uh so what I'm going to show here is how uh we released a new template so you can get started and create uh your own MCP server and how this can be packaged uh into a Nougat package put pushed to nougat.org and then consumed and used inside. Uh we're going to use VS Code to consume the MCP server. Um so yeah, I'm just going to breeze through this real quick. So we have a new template. Um uh there there's a quick start guide which you can find on .NET Docs. I'm just
53:35 going to install that template real quick and it'll tell us which uh templates were installed. So we have this new MCP server. So we're going to just uh create a new one. Oh, I didn't. Yeah. Okay, great. CD sample MCP server and let's take a look at what uh what's in the template, what we set up for you. Um, so we have a CSR here and this this kind of plugs into what chat was talking about about .NET tools. Essentially, this is a locally running .NET tool, but inside of it, it's running the MCP protocol. So basically it'll start a um it'll be a running process and then your
54:21 local agent will talk to this server and maybe call out and do your um whatever special features you want for your MCP server. So I'm I'm looking at a CS project here. I just wanted to call out a little bit here. So this is package tool. This has been here for quite a while innet. What's new is we're adding an additional package type. We're saying this is a net tool, but it's also this additional thing, this additional new thing called an MCP server. And we have some package metadata set up. But let's look at the code. So this uses the SDK, the uh C MCP SDK. Um pretty simple entry point, but I wanted to call out it sets up some tools. And so what these tools are are these these are the tools that your um AI agent can call once it knows about this MCP server. And I'll just
55:08 look show very briefly. This is a boilerplate tool. It just generates a random number. So what I'm going to do is I'm going to run this MCP server locally, invoke it using VS Code, and then uh do the Nougat parts a little bit later. So let's just get some config here to use the um the MCP server in VS Code. So I'm going to do uh VSC code and then there's a mcp.json file. So I'm going to paste this here. This is basically saying this copilot agent will look at this config and know of this mcp server. So I'm going to just do relative path is current directory
55:53 because my uh workspace is this root directory here. And I'm going to make sure that the server can start. I'll just hit start here. Looks like it's running. It's running. Running. Running. Do we have any tools? I think so. Let's check. Oh, it says one tool. Wonderful. And then I can click this to see what tools it's discovered. It's found my get random number tool. Wonderful. So, I can say all right. Um, copilot generate. Uh, no. How about two random numbers? Let's shoot for the stars. We'll just do that. And what I'm hoping it does, yeah, it says, "Okay, I want your permission." The copilot's saying, "I want your permission before I call out and do something because these tools internally run arbitrary code, right? They run net
56:40 code." Um, so I'm going to hit continue. Yeah, it's generating a random number from 0 to 100. Seems fine. And it's running it again. Seems fine because I asked for it twice. And it did 61 and 25. So what it did there was invoke this method via MC the MCP protocol and internally it's generating random numbers and it's showing them back. Okay. So this is existing behavior with the with the C um MCP SDK. Uh what we've added is this template and the nougat.org side. So I'm going to pack this up and um net pack and it will create a nougat package in
57:27 the release. Think I can actually do it here. Yeah, that there's the Nougat package. So, what I can do is I can now publish this to nougat.org and we've enhanced the browsing experience for MCP servers. So, I'm going to show that now. Uh it's this is a little bit later in the guide. Um so, I'm going to go to nougat.org And we have this new filter package type filter for MCP server. As you as as I showed before, this string was defined in our CSR MCP server. So that's where that's coming from. Um, so now this is filtering all the MCP servers on nougat.org. It happens to be one because this is just releasing today and it says unrecognized because we're still enabling the filtering feature. But if I
58:14 click on this, you'll see, oh, okay. So, there's a new tab, MCP server. And so, I'm now imagine I'm the not no longer the the author of this MCP server. I'm someone that's interested in consuming an MCP server and augmenting how I use AI in my uh dev loop. So I have this config and what I can do with this config is use this in VS code to call out using DNx which C talked about before uh to pull in this specific package version and launch the MCP server. So I'm going to just call copy this guy. I'm going to paste that in there. Uh it looks like Yep, that looks right. I'm going to start a new chat window.
59:01 And you'll notice um to the to the point about the the yes parameter that chat was talking about before um we've supplied it here because we believe that the explicit action of copying and pasting this into VS Code is essentially providing VS but we want uh feedback on this of course. Um so this this is going to download that package of this version and launch it with some parameters. So I'm going to hit start. Oh, it looks like in this MCP server I have some inputs um configured. Uh this is weather choices. So I'll do hot or cold. Sure, why not? And then now let's see what tools are available in this MCP server. There is city weather and random number.
59:47 Okay, so like what is the weather in Cincinnati, which is the city I live in. And it's again prompting me because I should know what what my agent is doing. And it's saying it's hot, which is one of the values I provided in in the input just to show that you can plum um configuration into your MCP server. Um I think that's pretty much all I wanted to demo. I would love to get feedback on this whole experience. There's this quick start. Um, John Galloway who opened the talk uh has a blog post out and I think there's a feedback link in there. But anyways, I'm really interested to see what MCP servers uh people build in. Net.
1:00:32 This is awesome. Thanks Joel for for um for joining us for this. Um, and yeah, this this was an amazing thing that kind of came together because we've been wanting an MCP server and then Joel said, "Hey, I got this thing started and and Nugat team had something going and we had DNx like all arriving at the same time." So, it was just beautiful to see it all come together. Um, I'll share my screen super quick just Whoops. Just to show off that um that post. So, um D share. Let's go with the entire screen. And here we go. So, and yeah. So, here's the the post. So, um John Douglas, Joel and I
1:01:18 collaborated on this. Um John, I think wrote John Douglas wrote most of it, but we all and then uh the team of course all reviewed, but this is a walkthrough on how to do it. Um important things here. You'll do this um this net new install. Let's blow the page up a little bit. So it's it's net new install the same way you install like um Aspire templates or whatever, right? And then uh walkthrough on how to do that. And then the thing that I want to point out is down near the end and I slapped it in here right near the um this went out right as we were going live. But there's a thing here for this uh survey. And as Joel pointed out, this is a first release of this template. So we really want to hear from you how you're using it. what sort of scenarios you'd like to
1:02:05 see. Um, that sort of stuff, too. So, um, yeah. So, anyways, uh, this this is amazing. Totally appreciate it, Joel. Thank you for, uh, thank you for the great demo. Um, I didn't see any additional questions here, so I think we can probably go ahead and wrap up. So, um, all right. Thanks, Joel. Thanks everyone for watching. Um, we'll we'll play the outro music and we'll say goodbye. Thanks, folks. [Music]
1:02:54 Hey. Hey. Hey. [Music]