Introduction to ASP.NET Core Razor Pages - Damian Edwards

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Good video, thanks for posting. However, I feel Razor pages risk adding more confusion as to how to create web pages with Core. Better to simplify the current MVC implementation than adding a second way of solving the same problem.

👍︎︎ 1 👤︎︎ u/klootas 📅︎︎ Oct 06 2017 🗫︎ replies
Captions
so we're gonna talk about razor pages he Nate's been on that core something I'm super super super super excited about I said I would never say super excited when I joined Microsoft but here I am Stephanie is later and I just said super excited because I got to work on this over the past year and a half and we we are very very happy with where it's turned out we still have a lot of great ideas about that make it better but hopefully by the end of this I can convince people in here who have to already dismissed razor pages as a complete waste of time that maybe it's at least worth looking at okay at least worth looking at everyone in here is an MVC developer I'm assuming all right okay anyone here web forms developer even if you used to be a web fonts developer it's me okay good no problem at all so what is razor pages so it's a new page focused approach or mini framework or not even that a bunch of stuff in MVC in asp.net core it is not separate it is part of a speed on that core MVC it's the same view engine it is part of razor alright it's not we have pages that's run by this view engine and view is run by that view engine it's all the same stuff like MVC is extremely malleable and configurable alright for those of you have ever customized MVC you will probably know that and in a spirit core we have this new thing called application model in MVC which lets you change lots of the conventions about NBC without you having to go and derive from the stuff in the box or replace it in DI it's actually very nice we use a lot of that capability to allow you to write stuff as pages and then we added a few niceties on top of that that we think really fall out of building applications this way it's designed and focused for people who are doing service at HTML generation so would you use this for your web api is obviously not controls and actions are a great paradigm for programming web api's well we think so I mean there are other ones that are very good too but controls and actions as where it's at or if you're returning anything that is an HTML you're not returning something that's going to be shown in a browser stick it in an action and put it on a controller that's perfect but if you are returning HTML from your server that's going to go into a browser I would thoroughly thoroughly recommend that you look at razor pages it is not meant to be like to PHP right it's not meant to be the new version of asp.net web pages that horrible framework that we built four five six seven years ago okay anyone use that thing no a couple of hands guys no one's gonna admit that one that's even worse than web forms um some good things came out of that though that's where razor came from like razor came from that effort alright so this is not that we're not trying to show you your Creator generation of developers I'll tell you not to use CS proj and tell you not to do dependency injection and all that I will not be able to write unittest right all those things are encouraged and possible and first-class citizens on top of razor pages right it's just MVC and it's not just for simple scenarios don't think of this is like oh this will be great when I just have a very simple page that does blah know it's designed to handle all scenarios for when you're doing server-side HTML in general okay if you're doing it with MVC and views today you should be able to do with razor pages and it should be better and if it's not I want to hear the feedback and if it's objective not subjective then we'll try and make some improvements to fix those issues you can integrate it with controllers and views so if you are migrating or you have a large code base and you don't want to go and convert or your controllers actions and views over to razor pages but you like razor pages you can reuse the razor parts all right so you can say common layout file used by both my pages and my views or comments enter partials and those are used by both my pages and my views okay it's just razor that's all it is it's nothing particularly special except that we've added some new stuff that's nice and all the conventions that I'm going to show there's a lot of conventions over configuration in here but it's not conventions in spite of configuration or without configuration you can change them all all right so what you'll see out of the box is what we decided we wanted things to be named and how we would find things and how we would dispatch and how we would invoke and what we would pass in that's what we chose to do out of the box but you can change it you can customize it to your heart's content just as you can with MVC all right so don't get too hung up on some of the terminology I might use if it doesn't sit well with you you can change it alright you don't like what we default in certain places you can change the defaults I just want to reiterate it is MVC all this stuff that pre-existed before razor pages still exists and you can still use it all in razor pages okay routing is obviously still there pages create routes you put a page file on disk it results in a route and it's built on the attribute routing system the good one not the crappy one all right models are still there obviously models are great they allow us to separate our concerns put things in nice simple classes that we can pass around that's what models are for action descriptors is really the heart of NBC NBC doesn't care about the sea right the actual framework doesn't really care that you have controllers all it cares about is there's a method that's an action that they can invoke and then it's mapped to some incoming function some incoming request sorry via routing that's it and everything else is just sugar on top of that all right so action descriptors come out of whether you're building controllers and actions or pages and handlers it's the same thing everything gets dispatched for an action descriptor in MVC that also means you get action results what happens after you execute an action you get a result right and that runs back through the other way of the MVC pipeline pages are exactly the same you can return action results from pages if you so wish obviously there are some new action results ones that rendered the page ones that redirect pages etc etc you can return the existing ones if you really wanted to you can return a view from a page I don't know why you would but you could you can return Jason maybe that's a good idea maybe it's not I'm not gonna judge you you get filters so you can do cross-cutting concerns the normal filters that you'd expect work there is a new filter a page filter that you can apply there only runs and pages as well you get model binding of course you get value providers to support model binding of course it's the same view context object that you've always used there is a derived page context as well but the view context is still there with all the same data that you've ever had that also means you get the same tempted you get support for tag helpers which are obviously fantastic if you don't like tag helpers for some weird reason you can still use HTML helpers they just work layout some partials obviously still work and anyone using view components from a street called 1x anyone done that ok couple of hands not many people have use those yet but they still work alright so if you factored out some logic into a view component I'm just kind of like a mini controller that you invoke from views you can call those as well from your pages alright and that's the end of my slides I think there's any more slides oh there all right let's just look at raisa pages in so I have a project here that I created I will say the Razr pages projects now are the default alright so if you weren't in my previous talk I mentioned this briefly if I go over here and do a file new if you're in vs and I choose a spinet called web application and I'm choosing to oh this template is the Razr pages template okay if you don't want to use razor pages for your HTML you would choose this one it says model-view-controller this gives you all the same UI and identity all the same functionality the three pages that's web stuff as this one but it's done using MVC Model View controller instead of using razor pages okay so we feel that strongly about it that we want people to use it by default so I've already done that over on this one here I'll make sure I get runs because I probably changed it and broke it because I usually do accidentally let's run that up do do your Facebook is like spamming me alright so there's my page it looks very similar to what you would have seen in your template before how do we add a new page well what does the structure look like I have a pages folder again by default if you don't like it you can change it that's fine we just decided that for good organization like we do in most of our unit core applications that we demonstrate and that we encourage people to do we have a separate folder to put our stuff in so we don't have our controllers folder with the views folder and the models folder to do basic HTML or just to get HTML at all you just stick stuff in here why do I have a controllers folder as well well because this application because it has off has an endpoint that doesn't return HTML as I mentioned and so it has a controller with a logout link so when you click logout we sign you out do some logging and then we redirect you back to the home page that's all the only reason we have a controller so we have an endpoint to do that okay everything else is in the pages folder well how did I configure this in my app it doesn't look any different where's MVC there it is adding NVC adds raiser pages because razor pages is part of NBC's normal view engine if you add the razor view engine you get razor pages it's as simple as that okay this method just adds the options so if you want to configure something about razor pages you do it in this method here now in this template because we've got off and identity and stuff set up we're configuring some authorization requirements for certain aspects of the folder so because everything in razor pages is folder based and file based because it's a page based framework everything becomes quite a lot simpler when it comes to organizing so this is my pages route by default and then inside here I have my razor files my index is going to default so if I make a request to the root of this application it's going to serve index CC HTML right straightforward it's going to use layout CSS HTML because that's been set up in V start and it's going to use view imports just like it would if you're using MVC's and views and everything else is very very standard and should be nothing new to people who have done razor and views before how do we add a new page well that's pretty straightforward I can add a new item let me add a new razor page which is here we'll call it demo Sydney there is a bug in vs at the moment where when you add a new razor page I hope to get fixed very soon the intellisense doesn't work so you have to close and reopen it which is a little annoying and then inside here it's just razor right so I can say hello from Sydney nothing is particularly new there I can run this we'll go back to the application I can go now to demo Sydney application is recompiling because I had touched one of the CSV files and I've got my hello from Sydney page up and running okay super super super simple now obviously we don't just put all of our logic or all of our stuff in a page inside here we have other ways that we can do so you can see the model directive is being used up here to specify what we call a page model so let me go and have a look at that demo Sydney model and let me show you where that is on disk so some of you eagle-eyed viewers may have already noticed the file name here demo Sydney dot cease HTML dot CS so if I go over to the solution Explorer again under demo Sydney if I expand that you can see I've got my demo Sydney dot C is HTML de CS now it's just a naming convention all right yes default the aspx dot CS is back it's just a naming convention all right it's not derivation right it is not merging together with a code beside file like we had in Asia I'm using all the turns from web forms because I did that stuff for 15 years it is not that this is a page model that is attached to the page okay the page model know of the page knows about the page model okay the page model doesn't have access to anything on the page it's no different to a controller being able to return a view but not being able to dive into it it can just pass data into it okay and you use the model to talk back and forth this is much more like an mvvm system so who's ever used an mvvm framework like zamel or Zama okay or angular even angular or react those type of systems where your model your view model isn't just a poco generally has functionality on it you call methods on it you bind from UI events to methods that are on your view model okay and it's live and interactive but still separated you can still test them alright nothing wrong being able to test those things what web forms got wrong was a lot of stuff but primarily it really wasn't very testable because things weren't really separated well you had a code behind and the view part that aspx file derived from the code behind but that was kind of problematic right then you often have this designer file that was hidden as well and that kind of got merged into the code behind and the front-end derived from that and that made everything kind of a big bowl of mess like we separated two things in different files but conceptually and architectural II they weren't separate concerns which made it very difficult to test and then you didn't have dependency injection the things that were on there the properties weren't settable right you couldn't lock in a thing so like it really wasn't set up in such a way to make it useful all those things aren't true of this nothing derives from this you get a page model class you make your model on top of that then you attach the page to it and then you put handlers on here they get executed certain reports come in so you can probably guess by the name of this handler when it's going to execute so when a get request comes in this will happen so let's pass some data from our page model back to our page well how do we do that well in a view and an MVC controller what we do you would create a separate model class generally and you would new that up you'd set some properties on it then you'd pass that to the view result right or you would do the abdominal thing and you would put stuff in View data and then you were just like hope it ends up on the other side you'd pull it out by a string key right no one does that because it's horrible we only do that when we have to pass data between views because there's really no other way to do it but in here we have a much better way I can it add a property so this is my message all right and then when get comes in I can say message is equal to hello Sydney and I could do whatever I want in there obviously and then rather than hello from Sydney now I'll just say at model dock message all right so if I go back to my up now and hit a five I should see the exact same thing I saw before it's just that now I'm setting this message from code rather than being hard-coded in the view right and I really should prove that shouldn't I so I should probably come back here and say hello from and I'll do something like this and I'll prove that it's coming from here name of demo Sydney model alright then we'll come back here five wait for that to recompile zoom it up a bit and then we'll see it's actually coming from the model now so already you should see that the separation that we're doing here still exists like the type of operation you're used to with views and controllers is still here there's still a formal way to pass data from one side to the other it's just that it's just easier right you just add a property and you code it as if it was an active view model just like you would do in the name vvm system now this is one way I'm setting stuff from here onto this property and then when the page runs it can read stuff from here alright that makes sense because unlike an mvvm system where you have an active UI this just last for the cycle of one request and gets sent down as HTML right but we also want to support binding stuff on the way in obviously right so we'll look at doing some of that stuff as well all right so I already have a model type up here in my data I have a customer object and inside here it's pretty standard first name last name email phone number blade a better barber that I've got some data annotations on here so let's build a fairly simple crud sort of view here but we'll do it using razor pages instead of MVC all right actually I might just tweak my I'm gonna freak out the AV guy cuz I just want to tweak my resolution I think my monitor is running at 4k and then it's trying to scale it down in the a/c that's not good let's do this and just watch everything explode that should be better I'm hoping that this means that my vs yeah hey you guys not quite as small as it was before good hopefully I'll zoom in and out though so we can keep saying all right so let's close my demo one we don't care without anymore let's go off and build some pages to edit customers so I'm going to create a folder called customers and I'll put a page in here I'll make any index dot C use HTML so what will the URL for that be any guesses slash customers right it's in the customers folder because this is file based when the route is constructed for this page it's to ride from go to the page route which in my app is slash pages because I didn't change it and then look at the path from the page route to the file customers slash index okay so then the URL is gonna be customers slash index but because index is a default document it's just slash customers okay simple as that now you can change routes as well and we'll talk about that a little later you can customize all this stuff so let's say h1 call this customers okay make sure that this is working before I go off and write a bunch of code so slash customers now in my application I should see a page that doesn't work because for some reason v/s decided to kill Elias Express so we'll just hit ctrl f5 again there we go there we go so now I've got my customers page showing up here all right so what do we want to do we want to list out the customers that we have in this application all right so let's do that I'm going to create a table and then inside that table I'll have a tea head and then inside that tea aired I'm gonna have a few I'm gonna have a row and inside that I'll have a tea head that does thing and I'll do HTML dot display name for and why my only display name for I don't have anything yet so that's a problem so let's go and add something to my model so that I can actually start doing things here well I'm probably gonna need some customers so I'll say I enumerable of customer I have a customer class already so that's good and we'll call it customers all right very good so now I have some shape keeping the wrong key there do all right have some shape let's go back to here so now I should be able to do customer is really its play name for model where is it m such that m dot customers will just go into will did you do the chip well yeah what do people usually do I always argue about this with people because I don't I'm gonna change that to a collection cuz indexing into this is just so much nicer than doing it this way I'm just going to this way right first name so do what ID in here customers dot one give me the first one please where's my intellisense gone first name do Oh touching doesn't isn't an index so I need to I list haha there we go so I'm gonna have a that and I'll just copy and paste this dude it to do will do first name last name and I think I had birth date or something here we go will do birthday very good and then I have to add a body so I can actually go off and loop through these which we'll do in just a moment lads and cells in here and then we'll do the normal thing that we would do here as well HTML dot display for and we'll do am such that well I'm gonna do a for loop now so we'll do customer will put our for loop in at for each customer in modeled customers [Music] okay up and then we'll finish this one out I'm to say display for EM such that because we don't really want to use em but we'll do customer dot first name and then we will copy and paste all of that okay and we'll make this one last name which it should be this one up here as well I've just noticed and we'll do birthday okay now I don't have any data yet so I don't think this is actually gonna work particularly well um this obviously has to be in a row as well which is why the editor is screaming at me right now all right that's probably the bare minimum I would have to do right to get something to work let's see what the page does I don't have anything yet so I'm just gonna assume it's gonna do nothing and it throws a massive exception because I haven't set customers to a value right null ref so let's do that let's go and add a constructor and oh and we'll get an exception from the editor that's awesome let's just not trust it and reopen it to make sure that's fine and then I'll get my application dbcontext I'll scroll that away dependency injection just works the same way and a razor page as it does in anything else in a screen it called its activate to take it in by the constructor and then use it down here and your own game alright so I'm gonna have to set customers I want to make this a sync because you know that's what we should be doing these days so async task we'll call it on get async you don't have to it doesn't matter if it has a you think on the N&R it's just a convention we just support both right if you don't like the word a sink on the Indy Racing methods it's fine we'll still call it so we'll do customers yeah we'll just do to list async we'll bring in EF to do that so I will set customers equal to underscore DB dot customers to link it to lists a sink let me bring in EF to make that work obviously I have to await that all right so now I should at least have something on my customers object so I might throw but I'm assuming it's not gonna do anything cuz I haven't had any customers yet so we'll go off and we'll add the ability to add customers next or we'll add some logic so there's nothing there get a table that's not particularly useful it's not very pretty either so let's just quickly tell bootstrap that I really want that to be a data table there we go that's a bit better and I'll add a condition up here if model dot customers dot count is greater than zero do that otherwise we'll show something else now we'll do maybe a P tag and no customers found try that all right so now says no customers found I don't particularly like having this much code I thought a lot of code right but I don't particularly having that much code so I'm gonna do what I would normally do an mvvm system and I'll do something like prop bull has customers and then I'll make that a derived or a calculated property which is customers count it's greater than zero all right and then I'll just change this to say if it has customers all right okay and it should just keep working the same way no customers found so we're gonna have to add the ability to create a customer so we'll do that next there we go so let's add a button down here so we can create customers so we'll do a button and we'll say that has to go to a page called new I guess doesn't exist yet create new customer all right and we'll give that a class or bootstrap makes it look pretty BTN BTN default does that look like okay so now I can create a new customer but the button doesn't know anything because I asked it to generate me a URL for a page that doesn't exist all right so URL generation in pages is routing it's no different absolutely no different so I've said please give me a URL for the page called new it doesn't exist for adding Caesar and I'll just give you a URL for the root of the application so that's what it did so let's go and create our new page so back over to customers we'll add a new item razor page we'll call it new so now I can build my new customer page so let's go and open that up again I'll add an h1 in here create customer let's see if that's working so I'm gonna hit f5 to get the app to recompile I mean I said that recompile quicker we're working on it it is quicker than it was in 1x but it still takes about 105 seconds okay and your customers still didn't go anywhere because I made it a button rather than a link that was silly of me let's change that to an anchor tag there we go so now I'm off to my create customer page so let's add the UI that we'll need to go ahead and create a customer so let's do that so I'm going to want to form method is going to be post all right so form tag helper now in a spinet core to always runs if you don't have any attributes on it telling it where to go it just assumes that you're going back to where you are because that's what you do when you're programming pages alright so there's just been little slight changes made to some of the tag helpers in the system based on some of the idiomatic sort of patterns that we found when building these types of applications rather than do this one from scratch I might just copy this one from an existing one so let me very quickly go and find that so you don't have to watch me type out every single form field because that's a little laborious so over here don't do that customers new let me grab that no this is nice it has titles and all types of stuff I'll pinch that I'll pinch that bit at least all right okay so what I do I add a link that takes me back to the customer list so you know ASP page back to index that's fine then I've got some bootstrap stuff in there and then a whole bunch of form stuff set up to edit the form I've got no code behind yet so I'll know page model sorry so none of this stuff is lighting up so let's go and add the properties that we'll need to the page model so I never gate to that let me add a customer property that's what we'll use to track the customer I'm actually working on not customer and this time because I want the customer to be bound on post I have to actually tell razor pages to bind this property when it's coming in all right so I decorate it with buying property this is a new attribute in a spinet core - and it works on pages and controllers so if you want to have properties on your controllers or page models that get bound on post or post like requests you can decorate them in buying property and they'll automatically get bound okay now you can also have stuff just come through in methods just like you normally would so I can do bode public void on post okay and I could take in here if I wanted to anything I can take a customer and customer will get bound as part of the post handler running okay but I'm gonna use just a property because I need the property anyway in order to be able to call these tag helpers and have the whole you know runtime scaffolding system generate the right HTML for me so I'm gonna do that well I don't really have to do anything on get in this page because this is a create page there's nothing I have to look up so let's do on post instead this will likely be async again because they almost always are let's do that and then let's look at the code that we have to do here so again this is all pretty bog-standard so EF stuff so let's go and add or copy this I'll just override the constructor name alright so there's my database so what are we going to do well first thing we'll do we'll say if the not model state dot is valid what would we do if the model state is not valid normally well we'd probably re-render the view right so I'm just going to return page okay that just renders the page that's associated with this page model okay now I haven't actually set a return type so I'm gonna have to do that well it's the same one reaction result okay nothing special you're probably noticing that it's actually not a lot of work to move code from controllers and views into a razor page and vice versa alright because all the primitives are basically the same it's just the patterns and the conventions for method names and dispatching are more tailored to the type of files that you're putting them in that's it all the conventions all the types are the same alright so then what would I do I have a valid one well then I'm probably going to want to go off and save it so let's go wait DB dot customers to add and we'll add my new customer which is the customer property good probably want to not that one silly let's say if changes isn't it then we'll save that a wait DB dot Save Changes async now if I was being really good I'd probably put a try-catch around this and I'd handle DB concurrency Bloodgood update exception all the rest of it but this is a demo so I'm not gonna bother so what I want to do after I've successfully changed it though is what I don't want to render the page because then I'm violating post redirect get right I want to redirect somewhere so I could either just redirect back to this page but that's kind of weird cuz this is the crepe form I probably want to redirect back to the list page so let me return the result of a redirect to that page so I'll say redirect a page and I'll just say index now for those who have been looking at these page names I've been passable passing in and wondering how this works when we do URL generation for pages we support relativity okay so this is a relative page referral I didn't put a slash at the beginning so that's going to look for an index page that's relative to the current page I'm on and that's kind of important we don't have anywhere else in MVC where this really makes sense but it makes sense in pages because you have a folder with pages in it right you can just do that type of stuff cuz we look at the file system or the metadata about the pages once they compiled if I were to put a slash in front of this this would go to the root of the site and go to its index page and if I did a dot slash that would be the same as just omitting it completely because that's a relative one you can also check you can do traversal all that type of stuff well what's the advantage of that it means that once I have a folder full of customer stuff I can take that customer folder and move it anywhere else and it'll continue to work in relation to itself right because all the links are relative that's kind of the advantage of doing HTML focused page programming right whereas if all of this was in controllers often when you make a routing change you have to go and find all the references to that route throughout the site and then unless they're named routes in which case you refer to them by name and but not many people I know go to the trouble of setting up named routes for every single endpoint in their app um so you have to go and refactor it so this is just a nice little thing that we're able to do because we're working with page files all right so let's see if this worked I should I think unless I miss something now have the ability to create a customer let's have a look all right so I have a form that's good so let me create myself all right now they are actually let's see validation work so I have validations working so I rendered the client-side validation so everything so far is good and then I'll hit save stuff seems to be happening and it's saved great so I have a record now in my database which is awesome but I kind of like to see a little bit more feedback when things happen so I want to add a success message to this page when someone creates a new customer so let's go ahead and do that well how would I do that because I'm redirecting across pages this gets a little complicated right yes yeah yes correct that wasn't a razor pages thing so the question is here it's specifically right this is a feature of the tag helper system which has been there phrase phonetic or since version 1 this property on the tag helper ASP 4 is of type model expression and model expression is a very special tag helper type that is built for tag helpers that says I want the value of this HTML attribute to point to something on the model all right so when we code Jen this we kind of prefix this with model for you and the editor knows that so when we built the tooling we do that for you as well and of course the advantage of that is because we have intellisense so I can come in here and hit ctrl J and the only Intel a sense I get is the stuff on my model which is really nice ok all right so let's go and add feedback now it's a little it's a little can get a little complicated right because I'm actually redirecting so if I want to set a message here that's going to show on this page well how do I do that how do I pass that from this page through the redirect to the browser and back to the server again what would people usually do so I think in the templates we used to have an enum that was defined somewhere in the app with the different messages and then we'd have like we passed the enum index through the query string and then we would use the query string to binder the enum to set the message in the move end of that message which sucks and then the problem with that would be that if you hit f5 and the browser after the first one the career string stays there so you just see the message every single time which is not really what you you could try and saw it in session you know that's not very nice you could use temp data but that requires session so that's not very much nicer either you can put in a cookie but then you'd really have to worry about securing it making sure that the cookie value was signed by you so you don't open a vector where someone can put a message in the cookie and then have a go to your server and then they you show it right you don't want to do they don't allow unvalidated content so we built a feature to make this really really really easy so all I have to do is add a property string message okay I'll set that property where I want it to be set where it's logical to set it I just perform the operation customer created successfully so I have all the states about the operation if I wanted to put in the the ID or the name or anything I could do all that here because I have all the state right I'm right in that method all right then all I need to do is go over to my index create ass matching property with the same name string message and I just have to decorate them both with an attribute that tells raisa pages where you want that properties backing value to be stored and incidentally this works in controllers now as well all right so every time we found something as part of doing this that we felt was a good pattern for doing HTML based stuff we said well let's set it to raise the pages and then we'll figure out whether it makes sense in MVC as well and if it does we add it there as well okay so now all I have to do is set this property and read it on any page model or controller where it has that name and it will always be backed by the same backing field so for those who don't know temp data works like this when you set the value of a temp data with a given key it stays valid for the current user no matter how many requests they make until you read it again and then when you read it we delete it all right does that make sense so it's not just one request it's as many requests until it's read again using the same key all right now before temp data had to be set up using session and setting up session was always a pain cuz you have to have read err so you had to have in memory session or something like that we change the default template a provider in 202 use cookies so we encrypt the cookie then we sign the cookie with all your temp data in it goes down to the client goes back to the server as soon as you've read it we delete the cookie so it only lasts as long as your temp data value lasts ok so now I have to display it I guess I'm actually displaying it anywhere am I let me let me cheat I know I have a nice little sort of alert thing somewhere or I could just cheat from taking the other one I guess couldn't I if I go over to edit no I think I have it on this one here we go this is what I want perfect I'm gonna add a little bit of logic to the top of my index page now and I'm gonna add a helper property that derive that calculates whether I should show the message or not and you can probably figure out how that's going to work it'll be a bull it'll say show message and that will be set to true based on whether the string has a value okay now again anyone who's ever built built mvvm style systems zamel any of those so this is pretty common like your model has a whole bunch of helper properties that are read-only that your view just kind of like asks ball strings data only cared I want a lot of logic just tell me what to do so you put all this logic in your model so you can test it it's really really easy to test it when it's here right and it keeps all the logic in one place which I really really like alright so now I have enough that hopefully if I do this again I'll get a nice little message so let's do that it says hit f5 to force the app to recompile then I will go ahead and I will create my second customer and I saw Jordan before so I will create a customer called Jordan Knight look at that now I get customer crater successfully at the top of the page all I did I'd have to worry about where the data was going enough to pass off the crew string set a property here read the property there but back them both with temp data and it all just works okay really really really nice if I hit f5 I show you by clicking it it goes away because the temp data is now gone okay now if you want to see all that happening under the covers you can obviously use the network tab hit preserve log go over to create customer create another one let me turn that let me turn it on let me clear this out and we can do like Joe Blow come down here it hit save and then down in here what you'll see is when I do the new when the header comes back we're setting this cookie there it is NBC core cookie temp data provider which includes a large crypto string which trust me it includes the message that I just wrote and then I get a redirect right to 302 so then I get a redirect and then I get a get back to the customers page of slash customers which is my index that request sent up that cookie so let me find the request here there it is so I've got a nanny for a cookie and then all the way over here somewhere there will be my temp data cookie there it is so I sent up the temp data cookie awesome but then in the response headers for that same request you'll see we're clearing that cookie okay set cookie temp data provider and that expired at the beginning of the JavaScript epoch which was in 1970 alright so that's how it is that we get this very simple way of passing simple data don't put complex objects in here please just put strings and balls and dates and things like that in there between pages or controllers very very very simply so that's really really nice including across redirects right so let's have the ability to delete all right we've got create but we need to be able to purge so let's do that let me go in add a button so I'll add an extra column in the head here and I'll put a non-breaking space in it because I'm old-school I don't trust browsers to render the right thing so I'll put a thing in here and we'll put a button in here and we'll make that button say delete and I'll give that button some class and we'll say BTN BTN extra small and we'll do BTN danger because I'm going to delete when I click on it and we want that button to go somewhere that will do the delete right well I don't have a form yet so I'd best wrap the whole thing in a form now so let's do method equals post and we'll stick that underneath here okay do I dare invoke formatting no don't trust formatting in a razor document that's not a good idea I get meds told me that's Kristensen he told me that they're rewriting all the formatting for the HTML editor in the next version which I was very happy about to make it less smart and that will basically mean it always does the right thing won't try and figure out we just indent every time I see something new all just indent simple simple simple so I'm hoping that's gonna solve all of our razor formatting woes that we've been dealing with for the last on eight years since we build the razor editor all right so I got a delete button now but it doesn't go anywhere so let's say I want this deep delete button to go well where well I don't really want a separate delete page I'm not gonna build like a delete confirmation I'm just going to assume that you do know what you're doing when you hit delete so I just kind of want to stay on this page you hit delete it deletes it that shows a message okay and I don't have to put it in a separate controller or a separate page I just wanted to be on a different method on this page so I'm gonna specify a custom Handler so we'll do a SB page Handler and we'll say I want this when it clicked to run the delete Handler well how does that work well I'm in a form which I didn't specify an action for so the action has already been set to this page but then when I set page handler on the button this renders out using form action alright which is an html5 attribute that lets buttons inside forms change the action of the form when you click them so you can have multiple buttons that go to different end points inside a single form rather than having to have a separate form for every single button yeah it's nice so we do that for you as part of this incidentally if I set there to ASP - controller it does the same thing all right it'll just render form actions and you can go off to a different place for that I mean have a separate form so let's add that handler so it actually does something so I'm gonna add a handler public async task on post delete async so how does that work while it's still on it's still post because it's handling the post verb but now I've added a suffix which is the handler name okay delete delete' is my handler so this one will get this one will happen when I do it late now I want to pass in the ID of the thing to delete right so I'll do ID and I better make sure I actually pass it in here well how do I do that I do it via routing that's how you pass stuff around in links so I'll do route ID and this we'll have to be customer dot ID all right so now when the URL is built that sets the form action it'll take into consideration handler and it'll take into consideration all the route de drive past it and I should get a lovely long link that eventually ends up in it posting to this one here with some data so let's go ahead and delete it what's the easiest way to delete using EF I usually do the hacky way so I do EF dot customers dots attached and then I do a new customer and I set its ID to ID and I do it in I do that and then I said it's state equal to the deleted state alright so you can do this multiple race right you could read it from the database first see if it's there and if it's there marketers check but I don't wanna do two database reads I'm just gonna tell it believe this thing right simple then I'll wait the changes save changes they sync I'm assume that's always going to work and then I will go ahead and redirect again I don't want to just render the page I've performed a post I need to make sure I redirect back to the page right it's a redirect return to whoops redirect to page and if you just pass redirector page no arguments it will assume you want to go to the current page super straightforward okay lastly helps if you actually return my action result I want to set a message so I'll say message is equal to customer deleted successfully and this is the same message field that I added to support the message coming from the other page but I'm just using it to support the message from itself okay so it's a property all it is in this code is just a string property that you set and then the framework is taking care of actually populating it and traversing it across pages and redirects and all that type of stuff all right so let's see if this works recompiling we compiling we compiling hopefully I know I'm gonna get a delete link good all right well I might actually debug this one let's put a breakpoint here it's attached to dotnet very good come over here hit delete good alright so it hit excellent there's my ID seven double O to go ahead and delete that good set my thing redirect come back to the browser and it's gone and the customer has been deleted successfully marvelous very very nice I think very straightforward and quite a few less files in order to achieve the same thing as in NBC with all the same levels of separation now what URL got posted to there we didn't see it right because it happens super super quick so if I delete Jordan it says gone like I don't really get to see the URL so we have to go down into here and have a look at what happened so I got the customers well I didn't preserve cat logs that's not gonna do much let's delete myself I'll clear this out I'll Joe Blow already believe myself hit delete there we go so I went to this URL here my mouse keeps falling down so ID equals blah and handler equals delete alright because we didn't tell routing where to put ID and we didn't tell it where to put handler right there's no route declaration for this page it's just a page name and so all it could do was add them as query strings that's what routing always does if you say there were two routing here's the route I want you to use and here's the route data or what you use to construct the URL if there's no matching tokens it just shoves it all on the end of the query string right that's how it's always work if you want to change this though because you don't like the fact I'm passing all this is at the query string it's really really really easy so let's do that let's change the URL come back to my index page come back up to my page declaration and what you can do up here is you can specify extra route segments to add after the page route you can't change the actual page route declaratively yet we're gonna add that into point one alright in - oh it comes from the file name and if you want to change it you have to do it in code alright and I'll do that in a minute but you can augment this so I can say I want this to be ID question mark because that's going to be optional and then I want it to be handler question mark because I want that to be optional as well all right so what is optional mean it means that more than one route is basically getting generated for this page alright obviously I'm going to match just index and then we have a second one which is the default one which removes it and then I'm specifying an additional one which is index and then ID and Handler if I didn't have the question marks there index wouldn't match anymore right because I would be telling routing that it needs to have an ID and it needs to have a handler all right now this is just attribute routing so you can do all the standard things I can put a rack and straight on here right I could say has to be and I an int and I could reorder these if you prefer to have the handler name first and then have the ID delete this one then you could do that right so now without doing anything else that should be enough to change this application so let's add a new a customer I'll add myself back hit enter right so I've got my new customer let me clear the log and delete so this time you can see now that I've gone to customers ID and then delete all right the whole thing just continued to work that's the advantage of routing that's why we built it all those years ago I didn't have to change any other code all I did was state that I wanted the route to be different and then everything else just continued to work right super super super nice yeah so the question was what if I want to change the method for the forum or for what in the link you can't change a method by a link right oh you want to do a different HTTP method I'm sorry so you want to handle something other than delete other than post right so yes you can do that you can't really make HTML forms do anything other than getting posts because HTML doesn't support that but if you have like JavaScript on this page and you want to make a put request or a delete request then all you would do is say on delete async and we will just map that so we don't get too opinionated out of the box the default convention is look for methods that start with on then look at the current h2 be verb and look for that here and then if there is a handler specified look for that after that and then optionally look for async and that's it and if you don't like that convention you can change it and there's already a blog post from a dude in the community who said I don't like all this I just want verbs and you made it look like web api too so we just has pose get put blablabla and he just doesn't that way no just works just fine so two lines of code very very simple to change all right so now how functional have we gotten here we've got two the ability to create a customer ok myself again that's deja vu all right I can delete I can't edit but you can imagine what it looks like I'm not gonna waste your time doing it I have edit over here in this one and it looks pretty much the same right so it's just the same form as create except it says in it and then the Edit code behind looks exactly like you'd expect I bind the customer I have my message like I had before when I do a get I have to do one get now right because I have to look up the customer that I'm gonna edit so I take in the ID I find them if it's null I set a message it says hey I couldn't find you and then I redirect you back to the index otherwise I return the actual page so you can edit the customer and then after that on post when you've hit Save Changes it looks like you'd always see right check the model state if it's about invalid return the page you can see the errors update the entity framework type go ahead and scroll save say it was updated successfully look I actually add a DB update concurrency exception here and when it's finished just redirect to the page all right super super super simple well what if you want to change I said that you could change this URL but that you couldn't do it declaratively so how would you do that well you can do that in card so let's go and do that I think this is the app I was doing yep so if I go after my startup and I go down to here in my razor pages options I can change the root directory as I said by default it looks in pages if you don't like the fact that there's a pages folder you can just set that to nothing and then we'll just look for razor pages in the root of the app all right some people like that but we decided to make it that one by default so I can say conventions I had paid route all right so I can add a pager note it's not set paid route you're still just adding extra routes on top of the page not changing the route route of the page you're kind of adding an additional one so I can add a page route my first thing so it was a once is the page name so this is page route relative so I want to go let's change customers slash index that page two also or let's add a route not change it so that it responds to all customers Museum out of it alright so now if I go to all customers at the root of the app I want it to render customer slush index let's see if that works well just have five because I changed c-sharp I have to recompile we compile and we compiling so customers will still work because I didn't change it I simply added one all right but now I can say all customers and that works as well now I have multiple routes now for that customers page right so what happens when I ask you to generate well this link here is generating right back to customer list I asked it please give me the link to customers flash index and what did it do if I click on that it's now using my custom one right so when you add custom page routes they basically go to the top of the list so if you ask for generation it's always going to use that one at the top okay yeah well you absolutely can so the question was around if it's named index do you have to include the index so you don't so if I just go slash customers oh you mean when you're referring to pages yes so the convention around making it the default is for navigation is like when the URL comes in when you refer to the page you're basically pointing to the file from the page root all right now we don't excuse me right include the extension because we know it's the HTML but you have to point us to it's like when you do views and you say find me this view right there's kind of a search hierarchy that goes on alright cool ER what else oh let's get a page filter so I said you could run filters if you already have resource filters or all filters they work with pages right there don't just work you have to do anything they will run when the action result comes back from the page it's a resource all your filters will run you can authorize these with attributes if you want you'll note I've got code here to authorize a folder the accountmanager folder because you can't get into that unless you signed in and then to authorize a specific page which is log out now in to Oh your only way to mark a folder is authorizing code because there's no attribute way too stuff in a folder like where would you put it right it goes on a class you can't put it on a folder so you have to write code to do that but when you're authorizing a page you can if you want to use attributes and I mean why wouldn't you it's kind of nice so I could say that customer deletes that action or I could say customer new is authorized I could go to its model and I could come up here and I could just decorate it with authorize just like you would do anywhere else and now that that particular page will require authorization right because all that does it's a marker that the authorized filter that is in the pipeline looks for right that's all it is it's very straightforward if we want to do a new one though let's build a new one now incidentally we are going to add a feature in 2.1 i hope that will let you do this declaratively for folders so what you'll be able to do is you'll be able to go down to the view imports and do something like this add attribute authorize and you yeah if I can type it authorize and you could put in your policy in here or just do something like that right and then that would add the authorize attribute to every page that that view imports applies to all right so if you put the view imports a different one inside customers then would only apply to that folder right so you get the whole hierarchy thing that you get with view imports and raiser which is kind of nice by the way this is new and it works in raiser views as well as razor pages the app namespace directive will change the namespace of the C sharp classes that are generated from the razor files and it honors the folders that the files are in the razor files okay and so this way your derived or your generated class names that come from your razor files can very easily end up in the same namespaces as the c-sharp files of next time that's not true today I don't know if anyone's run into that where they try and put a c-sharp file in the same folder as a view and they wonder why they can't see each other it's because all views by default get put in a fixed namespace it's like a spinet court views or something well you can't change it you can now right sorry that makes it very very easy to find stuff which is kind of nice all right let's add a filter don't make my app not compile there we go I'll add a folder and call it filters inside here I will add a class we'll call it a logging page filter and I will say I page filter and I will implement that and so basically it looks like any other filter that you've ever looked at it has stages depending on what the filter is targeting page filters target pages so when the page handler is selected you get a context that lets you change stuff you can either log it out you can override it you can tell it to execute a different handler if you want it's up to you when it's executing you get one and then when it's executed you get the outcoming action result and you can modify it the way you normally would ok who's ever written a filter for MVC okay let's attack the same thing all right so use it you just add it to the MVC filters collection with all the other filters like it's not different just throw it in there and it'll work alright I'm not gonna bore you with that it does - it does just work I can show you the code and the other one if I go to the startup alright so here's my filters here's my page filter that I wrote I've added it to my MVC options filters collection and then that page filter will run for his every single page that I have yes the page filter does have a sink support so I think you can do an i async page filter yeah if you do now a sink page filter then you get task based methods instead of alright as I said you can change the convention so if anything in there offended you only because you didn't like the fact that I called it a handler or you didn't like the names of the methods but you kind of like the overall thing you can just change it say pronoun who was one of the developers on Razer pages he has a github repo @preneur km customizable page handlers and he has an example there of using the page conventions type to basically change a whole bunch of stuff around how stuff is found there's also a bunch of good community blog posts about how to do this as well there's at least two I know of and if you watch the asp.net community stand up everyone watch that page make you stand up if you don't you should it's great we featured a whole bunch of those links in the last couple of weeks so you can go to live a spinette if you've never seen this before to a plug live a spinette we do a mostly weekly show that goes for roughly half an hour to an hour every week handsome and John Galloway and myself and if I'm not there then we have other people come on and we showcase community links we talk about the content I give an update on what we're doing that week and the team and then we answer questions in YouTube chat from people as well so if you're interested in that whole archive of we're doing about two years now the whole archive of stuff is there and you can see the next episode they had one today when I wasn't there I think and they're gonna do one next week which I won't be there either because I'm on holiday next week so all right some things for v-necks that are coming we want to add more conventions in box the fusion the most visceral feedback we get is like razor pages looks great but I hate all these defaults I want to change it to do this this isn't this and so if we get enough of that feedback where there are like factions of people that want certain conventions and we might just put some more conventions in the box so you can just easily change them right so yeah we'll have a default one but these some other ones that you can have in the box we want to add support for page model properties and page handle the parameter validation so what I didn't say is that when you have a page model property like customer you can't put validation attributes directly on the property there so you can't have like string message have an input bound to that and then have a required field on message on your page model and it's the same reason why you can't do it on parameters in action methods right you can't have like taking string message in an action method and then put required in the action method doesn't work it's never worked we're going to make that work in two point one all right because people keep asking for a week finally going to do it I talked about that attribute and I talked about adding support for attribute routing on pages which would allow you to then use that attribute to change the route of the page directly on the page model or inside the Razr file which would be nicer you don't to do in c-sharp that's it please go off and try it out give us your feedback over on the MVC repo because it's just part of MVC so we can make improvements to this in two point one which we know will be coming at some point in the future but please go off and try this now as part of two oh it is now in our TM and ready for all of you to give it I do give it a go so I'm done thank you very much you
Info
Channel: NDC Conferences
Views: 54,526
Rating: undefined out of 5
Keywords: NDC, NDC Sydney, Damian Edwards, .NET
Id: yyBijyCI5Sk
Channel Id: undefined
Length: 59min 52sec (3592 seconds)
Published: Mon Sep 25 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.