Lets build a complete full stack Blog App with new Blazor SSR .Net 8 | Step by Step Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys I'm back with another video and this is going to be a complete full stack blog web application using the new blazer in net 8 so we are going to use Blazers SSR static server side rendering we are going to use interactivity for admin Pages we are going to use enhanced form navigation we are going to use streaming Rand Ing we are going to use uh enhanced form submission we are going to use all of these new uh features which we have for Blazer web app template in net 8 so this is the app we are going to build we'll we'll build it from scratch to end we'll do everything with the uh authentication as well the login functionality okay so this is the app we are going to build this is called blazing blog V2 this is version two because version one we have implemented I already have uh one version of this blazing blog which has different UI and it was built using Blazer server and it was with net 6 or 7 I don't actually remember completely but it was using net 6 or 7 with blazer server only now this is a version two totally different with a lot of features included including the image upload as well so this is the main homepage we have one featured blog post here with this title description and short description then image read more button which will navigate us to the detail page then we have this featured but the with the different UI we have username we have this categories then we have couple of latest posts then we have couple of popular posts after that we have these categories so asp.net core right now we are on this category page so we have popular in this particular category we have featured in this particular category then we have latest in this particular category then we have this all asp.net core post so all category posts we have one dedicated page for that one so let's go here and this is the page where we have paging I have kept it page size two so that I can show you paging let's go to C which I think has more articles so here we can go to the next page then this is being updated we have previous page we have next page then again next page right now there is no next page so we don't have that next page button we just have previous page button so these are the category Pages then we have detail page where we have this category image title we have this username then we have all this description the all the content then we have some related blog posts okay so all these pages are public Pages which are totally completely uh statically server s side rendered and we have this uh subscribe box as well so these are statically Serv render but still we have this subscribe functionality and here we can use I already added this so if you subscribe it it will say subscribing and you are already subscribed so we are using streaming rendering for this let's add some user let's say t six temp six subscribe subscribing and thank you for subscribing so we have subscribed there is no pce reload no page refresh nothing and we have not added uh web assembly or for websocket connection on this page for this this subscribe box for submitting this form all this is being done using the new Blazers new feature that is enhanced form posting with streaming rendering okay so that's all for the public Pages then we have this login functionality so we can go to login page we have this nice login box here we can provide as username and password if we log in you see now I am the logged in user so we have log out button with this name of the logged in user and if we click on this logged in username it will navigate us to a dashboard which has some additional options which is this welcome name then we have manage categories manage blog post and manage subscribers so now if we go to manage categories this page for this one we are using quick grid the new component Blazer provided for us so we have this quick grid and all these categories we have we can do this we can uh change this dynamically you see this so on this C is on this top list if I do this C is on the left there is some logic going on here so if I remove C from here you see this got removed from here but added at the very end this page uses uh interactive server mode for this category section but this top section is still SSR this is coming from layout so but we can see the changes in real time we can add it category we can modify from here as well we can create a new category here let's add some category do we have razor Pages yes let's use Tailwind or let's say net Maui I'm adding it to show on naar save it right now our main naar is supports only five items to be shown on the Navar if I remove any of these let me remove razor Pages you see I removed razor page then do and Ma is being shown here right we can go here there are no block post under ma because we just created this category there are no block post so this is manage category we can create a new category we can addit an ex category or we can update the show on flag just here in real time okay then let's go to manage blog post so here this is again a quick grid with pagination this is again coming from Quick grid only we have these items here title image name category name then we have this featured feature in this featured or published so for these sections you see this slug URL this is in blue color and clickable if we click on it okay we need to fix I need to fix this URL I didn't fix it okay I'll fix it but it is clickable but on the first one it is not clickable that's because this article is not published so first one is not published if I just change it here it says yes this is published and we can see it changing to blue color and now it is clickable so we have this I can p size smaller here so that we can see the paging so we have right now total 13 items and this is page one of three if I tap on it we are on page two with some different set of data page three okay now we can create a new blog post so if I click on here add new blog post we have this add new blog post page where we have title then we have a category drop down then we have introduction short introduction after that we have image upload and this image these are uh we can preview these images before uploading so if we select some image you see this is did not get uploaded yet we just can see this preview here and when we'll uplo upload it let's say sample blog post under Maui so here I select do and Maui from random short introduction and then let's have it here and I'll say some random short uh or let's say do this come here let's say net Maui blog net Maui so let's copy some of the stuff and write this let's copy this much we'll come here and we'll add it here and this is what you see is what you get this Rich Text Editor here let's make it featured and published let's save it it got saved we moved back and now we can see it here okay now if you go to muu category we can see this post here because now we have added this now this is not empty we can open this so we are on detail page and we can see everything right let's go back to this manage blog post and edit we can edit it and we can unpublish it save it now it is unpublished and now if you go to nmi again we do not have any blog post because this post is not published now this is unpublished we removed it from published okay after that we have this manage subscribers so I have kept paging of items two items per page so that I can show you the paging so all these are the subscribers which we have added so time 65 and all these paging okay then we can log out from here as well so log out and we are again back to the homepage so this is the application we are going to build it has a ton of features there is there's so much going on inside this we have uh routable Pages we have different layouts we have nested layouts we have Authentication login streaming rendering we have different set of pages we have shared components which we are sharing for example uh if I go to this category page you see we have this subscribe box right now if I go to this all sisha post page here also I have the subscribe page if I go to Details page there also I have the Subscribe box so this box is being used as three places but this is a single component which is is being used everywhere same goes with this type of sections same goes with the this popular post and all these we are using a ton of shared components all right so enough talking let's get started and if you're following this so do let me know in the comment just let's spin uh let's drop a comment that I'm excited for this video Let's drop in the comment okay so now let's start it now first we'll check what all common things we have so that we can design our components right right now we just added we just created footer component header component not header that nav bar component and then we have all our Pages directly right but in those pages we have different kind of sections if we see in a temp temp plate this is the main homepage category page detail page okay so on homepage we have this main hero section this is separate cool after that we have this section which is the feature section with next section so we have these three items here one item at the left do we have similar design anywhere no right yes we have it you see first item here then three items on the right and if we check on the homepage first item here then we have this three items on the right so these two designs are same right so we can create a separate component for this let's create it we'll call it this is featured and here this is uh read next so what should we call it let's call call it two I I I don't know I'm bad at naming this first thing this is direct shared component so inside this components folder initially earlier I used to create a components folder to store all our components but now with net8 everything is in components folder so in here I'm going to create a new folder which I'm going to call share like this and here I'm going to create a new razor component this I'll call it uh two or maybe I don't know what should I call it blog post let's call it featured only featured blog post list something like this okay and then inside this we can simply copy that what is that we'll go to Pages homepage and on homepage first thing we have this header section we are not going to touch this then we have this call ld6 this section then we have this second content section right so which is going to have one item in this eight then couple of items in this no no this is not the one that should be in this Co lg6 so after the first component first item we have the 66 right so first one is okay first one is this header this second section this container this is the section lg6 L6 these two these two and the same design okay one 2 3 4 1 2 3 4 cool so what we are going to do if we check on the detail page where is our Details page let's pin these remove those home category post and then where is detail page details details where is detail page blog post detail this is the one okay on blog post details after header we are going to have main content and after main inside this row LG first item then these three items okay this is the section if we check row with call lg6 call lg6 row col6 col6 right insert container no so we should have this row this section inside that so we'll go to our this featured blog section and we'll add that here cool so save and now we'll come here we are on homepage we'll directly call that component which is featured blog post right so let's copy this blazing blog v2. component. shared and add it to imports. rer so that we don't need to add it again and again so whatever common name spaces we have we can add it toore import. Razer these are going to be available in this complete folder so all the razor Pages can have access to this and when we add this we can simply remove this section and feature blog post start same thing we'll go to detail page and we can remove this section and we will say we will make a dynamic later with the actual items but cool now let's see after this what we have okay after this one 1 2 3 we have this section popular section right we have this on homepage and we have this on category page so both of these Pages have this popular section right 1 2 3 4 1 2 3 4 items so we can extract this out in a separate component let's go to Shar create a new razor component and here we'll say popular blog posts play okay and go to home and check for the populars this is popular we have this o so we can simply cut this o section and add that section here save and in here we can simply use that popular block course same thing let's go to category and category also we are going to have that list somewhere where is it it is here so just remove this and use that popular blog post like this save everything and now we are F okay let's check what other common thing we can find cool after that on homepage we have this all story section which has this design we have this left uh blog post title s description then category and author and then we have this image on the right side and if you go to the category page we have the same design for this latest right same design on home this is not so on homepage and C page we have this design latest section so let's call it we'll call it uh maybe just blog post list I don't know so let's create a faction here here we'll say razor component in a shareed folder we'll say blog post list go to homepage and let's get this section which is all stories we have this Dave Dave Dave 3 div we are going to cut this and let's use that blog post list like this and add that thing here same thing let's go to category page featured in signs after that we are going to have same Dave Dave Dave three s these three things so let's delete this and add the same blog post list something like this okay cool save everything after that we have on category page we have this uh this subscribe box and on detail page also we have the Subscribe box right so let's use this although it is on this detail page page it has only email on this category page it has first name last name but we'll use the same design for both of these but first thing we'll need to create a new component for this so let's create a component so shared I'm going to add a new razor component and let's call it subscribe box subscribe box like this and let's go to the category page on category page we have this section so inside this container borders and if you go to the detail page let's see what design we have there in there we have this border so from border we need to get this right border P5 light blue this section so let's cut it add this to subscribe box and here just use that subscribe box and same goes with blog post Dil page let's remove this and just use that subscribe box here like this cool so save everything and now we will run our application to see if all these components and everything is still gives the same look and feel and we have this function. JS alert we need to remove this we'll remove but right now let's see homepage looks same everything is still fine let's go to category page category page looks fine we have this subscribe box at the very bottom go to homep page again let's go to some detail page and on detail page also everything looks fine and we can see this so you remember initially earlier we have that email address on this but now we have a common component so the first name last name that means our design and our components are working so now we have all this great now we can start working on the actual thing now this is also essential part we designed all our components now we make these components Dynamic but before making these components Dynamic we need to have some data that means first we need to work on the database side all the entities and everything what we need okay oh before that let's uh fix the footer let's go to layout footer and here also we have this application name so we will change this to same blazing blog V2 and then copyright copy and then the current ear so it is using this JavaScript but we'll change it and we'll say date time do today do here like this copyright this thing and then this all right Reserve like this cool and after this made with this template and I'm going to add one more section and here I'm going to say let's say built with let's make it [Music] bold Blazer plus net 8 okay and after this buy me how by prints cool print let me add my YouTube's URL here so here I'll say www. youtube.com/ theate cool let's save it and let's run it let's let's see if we can see the current here and this additional section I'm running it and let's remove this JavaScript as well I'm keep on forgetting this so let's remove this alert rol save run okay still because this is getting it from cash hard refresh and now we are good in footer now we can see the Blazing blog we can see this built with net 8 everything made with this and if I click on this it opens the YouTube right now my internet is again not working but that is fine Twitter cool let's start with working on the main data part so we'll add our entities first let me close everything so close all tabs now in our data folder we have migration all these things so I'm going to create a new folder here new folder entities like this entities it is cool and here I'm going to add all my entity so start with categories so first we'll have our category and this category is going to have one ID we can have it as short then it will have a name String name then it will have URL slug then we are going to have one flag here of type bu which will we'll say show on Never So if this is true then we'll show this category on the main Navar right because we cannot show all the categories on Navar so whatever category we think we should show on Navar we will handle that using this flag so I think that's all for this category let's add the required attribute data annotation attribute on this and and let's say max length of somewhat 50 so these data annotations this I'm using so that I can uh have the data annotation validations when I will work on this managing these categories on admin side when it is trying to create it we will use this okay clug show never and everything looks fine cool let's create the second one here I'll say blog post so whatever blog post we are going to have let's add all the properties for this so first thing we'll have an ID blog post ID after that it is going to have a title title then it is going to have a slug slug string slug let me add all these I'll explain okay so I have added all these in blog post I have ID then I have title which required with max length 100 then we have slug image because all the blog post are going to have some one image at least one image then a short introduction then the actual main content the all content of that blog post then we have category ID which is this category category ID user ID who is the user who is creating this uh this blog post then is published if this is published or not then we have this view count so I'm going to use this to show the popular blog post because the higher the number the popular the blog post is Right higher this view count is then is featured this is a flag if this is true then we are going to show this featured blog post on the featured section on our homepage and category post page then we have these two audit Fields created at and published at when this blog post was created and when it got published then we have this navigation property so category for this category ID then this application user user this is for this user ID okay after this let's move it to its separate or its own class after this I'm going to have public class we have the Subscribe section on our uh pages right so let's handle that as well so here we'll say let's say subscriber here first thing I'm going to have an ID after that I'm going to have an email and let's have the name okay and then we'll have one datetime field that when did user subscribe to this subscribed on like this okay on email we are going to have this should be email address and required and max length of somewhat let's say 1 15 and the name it is going to be required with a max length of let's say 25 cool save everything and now we are good let's move it to it separate class as well move type to subscrib is cool so now we have these three uh entities set up now we need to add these entities to our DB context so we can create our own DB context other DB context if we want or we can use the same application DB context which this Blazer template created for us because it added all those identity related stuff so we can use the same application DB context right so I'm going to use this only here what I'll do I'll simply add all these three entities DB sets so here I'll say DB set of category category from our entities categories then second one is blog post so we'll have our blog post and then third one is going to be the subscribers subscriber subscribers like this cool now we added these we need to add these to the migration so for that let's open our package manager console so we already have one migration we did not run it yet on the database but let's add this migration so here we'll say add migration and we need to add migration we can name it whatever we want we have added these blog entities so let's say add blog and like this let it run okay let's verify if everything is fine so we have categories table small in identity name and slug we get 50 and on slug we have NW care Max which is not right so on category we should have some max length max length of if name is 50 then max length should be 70 or 75 not more than that okay apart from this subscriber we have name and email this is fine after that we have blog post so on blog post we have title 100 slug again nare Max that is not what we want so let's go to blog post on this let's have a max length of if the title was 100 so let it be 125 maybe not more than this and then we have image which is 100 this is fine introduction 500 content Max category ID user ID is published view count and all these okay I think we are good so now what I'll do I want a new migration so first thing I can maybe remove this migration or I can add one more migration which will fix these data annotation Valu so let's create one more migration so here I'll say add migration add uh Max lens something like this okay build succeeded it created and if we check slug is now 75 and this slug is now 125 okay good we are okay with this let's close everything again close all tabs now we will do one more thing and that thing is we have this application user which this uh identity created for us so it does not have the user name for this if we go to the very top we can see it has lockout and two Factor nabl phone number confirmed phone number concurrency step everything we have this email username and for this identity username is actually email only ID and everything is but it does not have actual user my name is AB it does not have that AB it will have this username is actually email ID only so we are going to add a new property here and I'm going to call it public string and name just now I am modifying the default buil-in identity which came with this template okay so this is going to be required first thing and max length um 25 name is 25 cool now we added this so we need to add a uh that migration for this as well because we need to add this to this application user class so let's open as package manager console again we'll say add migration and we'll say add name to application user this name is up to you you can name it whatever you want it does not matter the content of this class matters and we are adding this name to spet users with this Max l25 and we are good cool so we have already added all these ANS and all these entities now I think from entity side everything is fine now next thing what I'll do let's go to app settings. Json where we have our connection string database Bas connection string okay I'm going to modify this to my settings what I have first let me make a push it to The Rao then I'll do the thing okay so I'll make it dot I'm making it compatible with my systems database you can modify it as per your system so let's have it blazing blog V2 only database name trusted connection true multiple active results are true and for my local I can say encrypt false cool now we can run the these migrations on a database so for that what we can do we can go to package manager console again and we can say update database if you want to do it programmatically you can do that as well but for the first time let's do this update database and what it will do it will create a new database for us and it will add all these tables for us okay it is creating a lot of things and and we are good created everything let's see I'll check from the server Explorer only let me connect to it can do this new connection equal server server name is start Windows authentication men optional FAL server certificate and we have blazing blog V2 right test connection fine okay and we have our database here if we check tables we have all these table so blog post category subscribers these two we have created explicitly and all these tables identity has created for us right cool let's remove everything and now we are good great now in order to work on this application first we need the admin part which the admin is going to create the first admin is going to login and then admin is going to create the categories and blog post right so for this the login part that functionality is already in our components accounts Pages login do raiser we have this functionality here we just need to tweak this design a bit we'll see this H and then we need to have our services by which we can create basically manage our categories and maner BL blog post but before everything let's let's work on this uh this login only so right now we don't have any user but we have that register functionality but we are going to remove that register page but for now let's go to this register. Riser page or maybe let's do this because we are not going to have register page we will ship this admin user as a part of our application only that means the admins user credentials those are going to be seeded directly to the database when application is running for the first time so we are going to do this for this what I'll do I'll create a new folder in the solution I'll name IT services and in Services I'm going to create a new class let's say seed service in this I'm going to have one method public async task C data async here we'll see admin role then we'll see admin user and then we'll see the categories initial categories okay couple of C categories we will add by default then we will provide the manage category screen as well category list and add edit categories all those things we'll provide but we'll add some default basic initial categories cool first thing admin role admin user and categories We'll add a Constructor here and for categories we need our DB context we have our application DB context and for admin role and admin user we need couple of other services which identity provides asp.net core identity okay so we have if you go to register here we are registering a new user it is not using rule it is just using user but still if we see it is using user store user manager okay and couple of other Serv Services which we don't need so user manager and user store we need these two things we'll go here and we'll say I user store of application user okay we'll say user store after this we are going to have user manager of type application user so user manager and these are for user and then we have role as well so for that let's add role manager and the type is default which is identity role identity rule this one so this is Rule manager like this cool so we have all our dependencies now we can use this so first we need to see admin role for this what I'm going to do I'm going to create uh new static class here so I'll say internal interal static class let's say admin account like this and here I'm going to have couple of constants so public const string name admin name so let me add my name only then public const string email so let's have some random email ab. email.com then let's have public const rule so rle name is admin and then one password and let's have this P atate password 1 2 3 like this because by default it needs this complex password we can modify all these settings from program.cs and here we have all the identity related stuff we can modify as for our need cool so this password or all maybe all these details you can have these in app settings and you can simply inject I configuration here and then get these values from there as well that is also an option but I'm not using that I'm having these hardcoded here cool so now first thing we need to check we need to se admin role but this section we are going to call it for the first time and if our application restarts then also this method is going to be called so for this what we'll do first we'll check if we already seed the admin rule or no for that what we can do we can simply add a if statement what I'm saying we have on role manager we have a method which is find by name async which expects a rule name so here we can provide our rule name which is account admin account. rule right so we will check if a wait this rule is null that means this rule does not exist in our database if that's the case we need to create this okay so we can say this admin rule does not exist in the database let's create it like this okay so here what we'll do let's say we'll say where admin rule equals here we'll create identity rule class identity rule like this and we can pass the rule name here so we'll say admin account do R like this cool we have admin Ro now after this we'll simply say where result equals we have role manager and on this we can simply call our create a sync method with admin Rule and it returns identity result we'll await it and then we'll check if result do succeeded if it was succeeded if it was not succeeded then let's throw an exception so we'll say Throw new exception and it has string message inner exception so the message from this result object result dot errors it is a enumerable of identity errors and on this we can say select e goes to e do it has description so these are error descriptions right so we can have it errors string something like this this is all the errors so what we'll do we'll simply join the so we'll say string do join and let's join these by new line environment do new R and error string something like this errors string oh no what what have I done copy and it was this description okay and that thing I'm going to add here so in exception I'm adding all these errors and we are good we'll simply throw from here we will not continue further fine now if we already have admin role or we have successfully created admin role then move to the second part now we need to seed our admin user here so for this we'll follow the same approach which we have on register page which identity provided for us so from here when we sub submit it it calls this register user method and it creates this bunch of stuff it uses this right first it created this user create user if you go to this create user activator create instant application user it is simply creating the application user instance after that setting username email store email Ling all this stuff it is doing let's do the same thing for us so first we need to have username before that or maybe before that let's check if we already seated the admin right it might be the case that we already seated it so here we'll say admin user equals let's do the same approach user manager do find by email isnc okay and here we'll say admin account. email now we'll check if admin user is null okay that means this admin user does not exist in our database let's create it okay so here what we'll do we'll say admin user equals new application user which is our admin our user class like this after this we need to set username missing from user store so let's do this same thing we'll do this user store for us that isore user store set username asnc user is admin user for us email is actually this admin account. email cool before that let's do this admin user. name this property we have added explicitly right so if we have added it we need to explicitly set it so we are setting it like this like this and then we are setting the username using user store this is coming from this this register page now we have this email store section and I think we can skip this email store we don't need to use all this email stuff because if we need this email stuff we need to generate a code and then verify the user there only so instead of doing all this we can simply disable email verification how we can do this we can go to program.cs and here when we are registering our identity so this is builder. services. ADD identity code here application user and then we see we have options do signin do require confirmed account we can simply disable it so we are not using this email confirmation at all okay save everything cool register SE service we were here right okay so now we have set this username after this we are just going to create the user and how can we create it we have user manager on this we have create a sync and here we can pass our user admin user admin user and we can pass our password which is admin account. password like this cool and this create async also returns this task identity results so that means the same thing we can copy this thing can use here and we can simply replace this call with this like this a wait let's remove this additional await and now we are good okay we have this error let's add one more section to this error so we'll say error in creating admin rule something like this and then we'll say environment do new line and then rest of the stuff okay same thing we'll do here H this we'll say Aon creating admin user like this and now we should be good cool we have created admin user if it was not succeeded we will simply throw from here we will not do anything further great now let's SE categories for categories again we'll check if we already have categories so for this we'll say if a with context dot categories as no tracking do any async if we do not have any category here we'll say there are no categories in the database let's create some categories okay so for these categories I have already curated a list of categories let me copy those over I'm going to add this in the category entity only so data entities category in here I'll have this static method with get seed category iies and I have these c.net core Blazer these couple of categories okay so never couple of these are shown true for others it is false false and true so we have this get seed categories it is an array of type category let's use this so here we'll say context do categories do add range async and here we can have category dot get seed categories like this we'll await it and after this we'll say await context dot save changes async and we are good so this complete seeding part is done and remove this cool now we need to call the seed service right so for this let's extract a interface add to the current file only and let's register this IED service to our dependency container so here before builder. build I'll say Builder doservices do add transient IED service I seed service and Seed service like this okay okay now we need to call this SE service right so this thing what we'll do let's inside this program.cs only let's create a method here so here we will create static async task and let's say seed async something like this and we will get I service provider services like this okay here first we will create a scope we need to create a scope scope services. create scope after this we will get our seed service service equals services not services from this scope the scope do service provider sorry do get required service and then I service like this now we have the seed service on this we can call I seed service dot seed data async like this cool now we need to call this cync method after builder. build we can call it directly so we'll say a wait cing can we do this app do Services we need to pass the service provider which is app. services like this cool let's try it out so I'm adding a breako here then let's add a break point in this C dat I think as well let's run it and let's see if we are able to create this role category and all this and we have an errors some services are not able to be constructed I service lifetime transient what is the issue resolve service type rule manager identity rule it is not able to get rule manager and why so if we check here is the identity registration so what are we missing are we missing something here identity code Entity framework store signin manager default token provider so add roles Okay add role manager add roles add Ro store add Ro I think this does everything so let's call this add rules which is going to be of type identity rule okay let's try it out where is the okay let's run again we have some issue let's see what is it this time is happening my okay system is freezing okay identity role lifetimes coded implementation type what is the issue some services are not able to be constructed error Val service service type identity rule manager we added rules right some instructed service type role manager can we maximize this now view details inner exceptions six in exceptions let me check what it is saying so it is saying this thing view unable to resolve service for type identity. I roll store Microsoft identity Ro while attempting to activate role manager identity role I roll store it is not able to construct this my R store but when I say add rules it was saying that it is going to add it right add rules T rule including IR Rule Store I Rule validator and Rule manager it is going to add all these add rules does this the order should not matter let's see run it let's see if it works this time okay it worked that means this add rules should be before I add identity framework store okay okay now we are here seed service we have this now we'll come here cool role manager it is trying to get it and it is null we know this is null because this is the first time we getting it result do succeeded it is true that means it created this Rule and we continueed further then admin user it is null we know this is going to be null and let it create user and it created the user this is also succeeded that means user is created then we'll go to our categories categories save as sync and continue that means all this data is seed we can verify it let's go here we have these categories so right click show table data it should have all those categories which we added let's see yes we have these same thing we'll check aset roles let's check show table data and we have admin role same thing let's check aspnet users show table data it should have that one admin rule yes it has it cool that means now we can try logging in because we already have this login endpoint let's try if it works right so from seed service email ID is this a email.com and password is this right so let's run it this time again it will go to the seed service and this time it will pass through all these no admin user is null still null it should not be null what is the issue duplicate username yes so user manager. find by email Ling this does not work or are we missing [Music] something by email ising this is error it is going to error in creating admin user username this is already taken what they using register they using user store directly that username we set it to user store but we checked with asp.net it has the email right oh email is null email is null email is null why email is n it set this username but it did not set the email so for this we need email store maybe so that means we need that email store so we'll go to register on register we have this email store and this thing right email store. email let's copy these two things go to our seed service seed service here and after setting this username is sync we'll use this so get email store what we have for get email store so get email store it is this thing right like this and this should be underscore user store like this okay now we have email store set emailings user which is admin user and email which is going to be this email and we are good let's do this for me what I'm going to do I'll go to the app settings and I'll modify this name V1 iPhone 1 can we have hyph in database name maybe let's add this 2 one or maybe underscore one like this save now it will going to create everything but we need to run that update database right so instead of doing that we can autom made that thing as well how we can do this in the C data sync what we'll do let's create one more folder here method here we'll say private async task and let's say migrate migrate database like this okay migrate database Sync here we already have underscore context so on this context we can check if uncore context dot database dot get pending migration isnc right await get pending migrations async on this we can check if it had something here we'll say do any if there is any pending migration so I have changed the connection string that means I'm in a new database so it has all these migrations spending only if that's the case we will simply AWA context database migrate sync we will migrate the database okay and we should do this Dynamic migration only in development mode we should not do this in production mode the reason is migration could break things right let's say there was some data in the database and and we modified the maybe max length we reduced it so it will going to truncate the existing data so that's why that is not a good practice to dynamically migrate database in production for this we'll do this we'll add if debug and if and we'll add this logic here okay and in SE data ising first line we'll say await migrate database ising like this cool let's try to run it so I'm running it seed service we are here migrate database we came here we have migrations now it is going to run the migrations and and same thing it will create role create user create categories and all these and right cool now let's try it out second time this time it should not have any pending migration yes it returned from here then role is already created then user we should have one user this time yes we have this and categories also we already have so it will skip all these steps and it will continue cool now for login we have this account SL login this endpoint design it off because we removed bootstrap and app. CSS so we'll fix this design we'll make it uh as a part of our current template only but right now let's try to check it so I have aate email.com and password I have three at theate password 1 2 3 to login and it logged in cool but we are not seeing anything here well we'll make that change but at least that thing is working it is able to get the user cool okay now first thing let's go to the layout top Nar and we'll modify this Lo uh this button get this theme we'll change this button to login button so let's say login and the URL is going to be the same account SL login save but now that we show you it will always be there we can tape on it and it will navigate us to the login page breako now we don't need it so we can remove this and this okay it's here login we can tap on it and we can log in cool so we logged in but this button did not change but it should change right so for this what we'll do in here we will use authorized view so this is a way in Blazer we can uh we can render our template HTML as per the authorized state so this authorized view it has three things first is authorized second is not not authorized and there is third state which is authorizing as the name suggest when it is trying to authorize it is get trying to fetch the authorizing state that if the user is authorized or not then this content is going to be rendered and when it has successfully get the authorization State and user is authorized then it will render this section and if if user is not authorized then it is render this not authorized section so in our case we don't need authorizing we just need authorized and not authorized so if user is not authorized that mean user is not logged in so we will simply show this login link okay now if user is authorized then we'll do we'll show log out button so we'll say this is going to be log out and before this log out we will display the current logged in users name so for this I'm going to use the same thing but the content and this authorized view it gives us one special uh variable special parameter that is context and using that context at theate context it gives us this authorized view gives us this on this context this is authentication State and we can access the claims from there we can access identity and from there we can access the name okay then identity could be null but we are adding this inside authorized view that means user is going to be always authorized inside this so we'll have access to name and identity will not be null so we can simply omit that warning okay HF for now let's leave this hrf like slash only will modify it okay let's save it and let's see if we can see this new UI it is here so we can see these two things that means user is already logged in and we can see this email and log out is not going to work I am moving it to the login page so this is not the thing which we want oh I made it yeah this is fine so for this log out let's check what was earlier which came with this default template so in the nav menu section we had a login section where is it sorry log out section this section so the way it is handling log out we'll create a form and from there we'll simply submit it because this is SSR so we need to submit this form and this is going to this URL account SL logout now if you try to search for this account logout page there is no page how they are handling it this is an end point minimal API end point we could say so we have identity component end points route Builder and in here we have this log out it is on this group so slash account this is the first part then slash log out this is the second part and here we are signing out sign in manager sign out is Inc and then we are redirecting it to return URL whatever URL we have in here in this hidden field so this is how it is working what we'll do here we'll simply copy this form and we'll go to our top nav bar and in this log out section we are going to add this like this okay and in here on this button nav link nav link everything looks fine cool now for this current URL if we check what we have here on the nav menu page we have current URL which is navigation manager. two base relative path whatever current URL we have and then it is changing it whenever we are navigating around somewhere okay but we can skip this we can just have the homepage URL so for that what we can do we need to inject navigation manager first so we'll say inject navigation manager we'll call it navigation manager only and then we can use this navigation manager display so current URL let's have it as a variable here so we'll say string current URL or maybe redir URL and override on initialized in here we can use this redirect URL to navigation manager dot to base relative path and here we'll use navigation manager dot base Uris so this is the base URI that means the default domain Port so in our in this particular case it will be Local Host colum whatever Port we have and if let's say I have hosted it on blazing blog v2.com in that case this base Ur is going to be that HTTP blazing blog v2.com so which is going to be the default homepage so let's use this in here cool so that means this post is done it should work now but before that this name let's remove this highlight class because we need this as same as other uh other links and from other links just let's remove these to about and this doc so we are not using these so save everything and let's run and let's see if we are able to log out the user and login back again okay it is here right now if you see we have this logged in users email and log out button and now if you log out we are on homepage and we can see the login now if I login and cool so this login log out and the status is working but now we have one problem uh not problem but it is showing this email right but what we need is so this identity. name this default is that email that username in aspnet identity but we need to show our uh users's name the actual name so for that what we can do when we are logging in so if I go to login page right now what it is doing it is using signin manager. password signin async with the current email and password that username and password and the way it works it automatically uh adds the basic claims and for those claims the name and the email our email only but we need to modify it so that name we are not going to use that name but what we'll do we'll use our own name uh what I mean is we have a name property in application user right so we are going to use that particular thing so let's do this let's create a new method here so that we can add our own logic in that we'll compare and then we'll remove this login user here I'll say private async task let's say perform login async something like this okay here what we need to do first thing we will check and then we cannot use the password sign in async we cannot add additional claims using this password sign in async method we need to use some other method and for that other method we need to do a bunch of things so first thing we need to check if this us actually exists so for that we'll say user a user manager dot not to get find user manager right do we have user manager Here sign in manager we don't have it let's inject user manager so we'll say inject user manager of application user user manager okay so on user manager we will use find by email asnc and this is going to be input. email so now we are checking if this user exist with this email now we will check if user is null that means this user does not exist so we can do the same thing they have done this invalid login attempt and let's return from here don't do anything further now if user is not null that means we have this user then instead of this password sign in async we have another method on this signin manager which is signin manager dot check password signin a okay so using this first we need to pass the user so we already have user then password we have this as input do password then lock out on failure we can set it to false with don't want user to lock out on invalid attempt and then it re Returns the same result identity result actually the same type which this sign in this password sign in Asing returns okay now we'll check if it was able to successfully verify the password so here we'll say if result Dot succeeded if it was false that means if the sign in using this password was not correct that means password was incorrect so we'll do the same thing invalid login attempt or we can say invalid password incorrect password like this okay and if that's not the case if we reach this point that means user exist and the password is correct so everything is fine now we can use one more method on the sign in manager that is sign in with claims Asing okay on this we have this overload so here first it needs user so we have user then second it needs is persistent so we have input dot remember me then third parameter we can pass additional claims okay so now we'll create those additional claims so here I'll say additional claim and let me change it to CL claim array and this is the best feature in this net 8 C 12 which I like the most that is like this we can use this array and in here we can pass anything here I'll say claim and here I'm going to say full name this is the key type and and then value we will use user dotame this is the name which we have defined cool and now we can use we can pass additional other claims as well if we want but right now we don't need any other so we should be good add the chal claims the name is up to you and then we can pass this great and now logged in logging in is successful then we can do the same thing they have been doing in login user and logged in user logged in and redirect to the return URL whatever it has cool so from this login isnc we can comment out everything and we can just call our perform login method a wait perform login ising like this and now it should work and we should have access to this full name now we are going to use this at other places as well so if you are following me I hate these magic strings what I'll do I'll create a new constant class so let's say app constants and this is going to be static class and here I'll do public static class claim names and here I'm going to create a public cons string full name full name this name and value is up to you you can name it whatever you want okay so when we are setting this claim let's use that constant so we'll use app constants do claim names dot full name cool now saving is done we need to get this value right when we add this two claims and if we go to our top navb we have access to the context this context user so this user is actually claims principle and on this claims principle we have a list of claims so we can get that claim from here we might need it somewhere else also so what we'll do on this claims principle I'm going to create a con uh extension method on this claims principle okay and we are going to use ID as well we we will need ID user ID so that also we will use so let's create a new file and let's call it extensions [Music] exens fine this is also going to be static because this is going to hold extension methods so here I'll say public static string get username and I'm going to create this extension method on claims principle so claim principle principle like this and from here I can access principle dot get username this is I am defining this does not exist so we have find first or we can use find first value and in this we can pass the claim type and that is going to be app constants do claim names do full name like this okay and if this is null although it should not be it should not because we are going to call this method from after logging in only so we are good okay now we might need user ID as well so for that what we can do we can use the claim types dot name identifier which commonly gets used for Unique ID and this is going to be get user ID okay now we are good to use these methods so what I'll do I'll come here on top nabar Razer and in here after at theate context. user dot I can use that get username here okay and let's do this let's check if we can get the user ID as well so after this username let's see if we are getting user ID get user ID okay now let's try it okay it is here now so if you see it was user was already logged in we can see the ID user ID which this automatically added but we cannot see name because that claim does not exist for that let's log out and now log in now it will use uh the that additional claim that full name claim you see I logged in and now I can see aapis which is the name of the user full name and hyph then this is the ID so that means we are getting users name and users ID cool so save it again and everything looks fine login log out getting the current logged in user credentials everything is working fine now we'll start working next and the first next thing is going to be let's fix the UI of this login page let's run this and we'll see this side by side the design so for reload sometimes it is working sometime it's not so I hope this works this time so that we can actually see the things okay go right now I'm logged in go to log out so okay we can't see this side by side okay so the thing is we don't need this external login we will just use this login and we can remove the recent email confirmation register user forgot password we'll remove all these options and we'll move this section to the center of the screen with some Shadow so let's see let's clean this up so first thing this call MD offset to this external login Pier we don't want this so let's remove this after that this forgot password register and recent email confirmation we don't want all of these so let's remove these as well now we just have login information username password then what we'll do we'll wrap all of these things in a container so Dave class container okay cut everything and and we'll add a div class call and sm4 4 is enough and we'll paste all those inside this thing cool now on this container we want this call sm4 to be in the center of the screen so let's use display Flex so dlex then justify content Center to move it to the horizontally Center and then for vertically aligning it we'll say align items Center but this needs height because for horizontal we set container which adds height so it knows how to center it but when we say align item Center so vertically there is no height defined so it will take the height what this content needs so for this what we'll do we'll provide explicit height so we'll say style Min height and we'll use Cal function this is CSS function by which we can calculate something St uh dynamically then we have a 100 VH which is 100 viewport height so this is a relative unit whatever screen size we are currently seeing the window size that is viewport height and from this we uh subtract we'll minus some height so we have header we have footer so maybe heer is of 60 70 and then footer is of maybe 100 so let's add 250 PX to be that uh that a margin basically so that it gets the proper height okay save it and let's see where is it and it's here cool this is in center but now now we don't need this call md4 right and this row we don't need all of this so what we'll do we'll simply get this status error message and this edit form and we'll add it right after login like this save and let's see cool it is coming pretty good right okay now let's add some Shadow to this box so on this container or no not continue on this call sm4 let's add a shadow so this is a bootstrap property bootstrap uh class which adds a shadow and we can see this Shadow then let's add some padding so on this call lm4 only let's use py3 and now we can see something yes cool then this remember me this button is getting out of this screen this shadow box let's move it to the right so where is it this so on this let's add ml3 so that margin left we get some margin left okay looks like it is coming pretty good and let's uh make it as five so that it looks a bit uh smaller and now we have everything just this email and password these are coming below the text box but this should not be the case so let's see what the issue is and the issue is this form floating which came with this current Blazer template so this is coming from bootst 5 but our template our UI design template which we referenced it is using bootst 4 so it does not have that form floating so that labels are not floating so what we'll do we'll simply move labels first before input text there should be label move it save it and let's see and boom so now we have this login use a local account to login we have email password remember B and loin great let's write login and we are here I can see my name and the log out button and everything is fine cool so I'm liking it all right now we'll work on the admin section first because that is going to uh add the data to the system which we can use on our public Pages home category and detail pages so for this uh the admin user it is going to see some additional options so for that what we'll do we'll create a separate layout for admin right now this main layout this is the actual main layout uh for the complete application but for admin we'll create a new layout we'll call it admin layout okay and we are going to to use uh nested layout basically so this admin layout this is first it should inherit from layout component base then we'll set layout for this layout which is going to be main layout so now this admin layout this is going to act as a Ned layout first main layout then admin layout and after that the actual body whatever uh content we want inside this admin layout so what this admin layout is going to have first we're going to have the complete width of the screen and then we'll have a de class row and inside this we are going to have two columns First Column for additional menus which admin requires that manage category manage blog post and then right section where we going to display render the content for that particular page for manage categories we are going to display the list of categories and all those so here we'll first have da class call md2 and then the second one MD 10 okay so this first one this is going to have menus and then the second one this is is going to have the content which will be passed as a part of body okay so for this call md2 what we'll do let's do this let's create a page in Pages folder add razor P laser component and we'll call let's say dashboard dashboard and P the URL I'm setting that is admin SL Dash board and on this dashboard page I'm going to set layout as admin layout and this is not coming up underscore import let's add component slash layout okay save everything and now we have admin layout with this S3 dashboard and now what we'll do when we are logging in or maybe let's do this on top navb bar when we tap on this logged in user this link we'll navigate user to this dashboard page like this and same thing we'll do from login so let's go to login. Riser after loging in return URL return URL and where is this return URL set return URL m okay that means we can set it hardcoded here or maybe let's add this directly to this the default value that is going to be this admin SL dashboard save and run it now we'll see that admin layout for this dashboard page and then we'll start designing that page okay let me pull this up and now if I log in I came here it should have gone to dashboard we'll check what the issue is but right now let's go to dashboard manually and now we can see this space right so let's do this side by side but because we need this complete width so what we'll do this maybe like this I don't know if you guys can see this but right now I don't have any other choice what I'll do I am on admin layout right so I'll pin this and I'll close all other tabs oh my God I close that one as well so admin layout fine now we can see if I add some heading here I'll say main menu or admin main menu save it we should see this admin main menu here right so this is the left call md2 and this is called MD 10 cool so now this left section let's design it a bit so here first thing we need we will display the username so here we'll say authorized View and authorized inside it we'll add let's say H6 and here I'm going to say at theate context do user do get username like this okay so we could say that welcome and this username and okay stop debugging then run it again I have it here let's navigate to dashboard so admin SL dashboard and we can see welcome Aints right now let's do this on this left section let's add uh some background so on this md2 I'll say BG gray and some padding from let's say vertically py3 save everything and we can see this cool let's make it bold and move it to the center so on this F6 I'll say text Center and font weight bold save and we can see this cool after this I'll add one HR horizontal Rule and then I'm going to add our menus so here I'll have div class list group which is coming from bootstrap and in here I'm going to have couple of links so nav link HF so first let's use admin SL manage categories okay and here the text is going to manage categories let me copy this two three times so that we can can see the design here okay these are coming now we'll add class which is list group item save and we can see this and we'll add one more class that is list list group item action save okay now let me copy this or maybe let's add other uh options so then second option we are going to have manage blog posts so the text is going to be manage blog post and after that third one is going to be manage subscribers subscribers save everything and now we'll have one more action that will be that log out okay so for this I'm going to add a div here so D class same list group item and list group item action and inside this I'm going to add the same form we have this for this log out so top never let's search for that form we have this log out form copy this go to admin layout and add it here okay the redirect URL we'll set it but before that on this button this has this nav link class right so we'll remove this nav link and we don't need this icon so let's remove that icon as well so we'll have button with text log out and the classes on this button we'll use BTN BTN SM and BTN danger red color save everything okay now it broke now for this redirect URL let's inject our navigation manager here so inject navigation manager and we'll use this navigation manager the same thing so we'll say navigation manager dot do to base relative path navigation manager. base so it redirects to the homepage like this okay and we can do one thing let's move this form to a separate controller right because we are using it at two places right so let's move it create a new component in shared I'm going to create add razor component and we'll say log out form and the design is going to be this one now this class this is the dynamic part right let's remove this in from here we'll add it here and in top na bar we had this thing so let's do this here inside code and this redirect URL let's add it here like this and now this design this buttons uh class these are different at both of these places right so what we'll do we can get one parameter so we'll say prop string uh button class classes something like this it should be parameter and let's say edit a required so that it shows that this button class properties required if we are adding this component anywhere okay now we are good now we can use this here so here we'll say button classes like this save and now we can go to admin layout and admin layout we can add that log out form here log out form so that editor required what it does this editor required right now if we come here on the admin layout you see we have this warning and here we can see component logout form expects a value for the parameter button class so it gives us this warning so that we knows that this is required so it gives good developer experience now I can show you if you remove this editor required save and now if you go here that warning is not here so now we can have unexpected Behavior so if our component uh requires something to functional properly we should add this editor required cool this warning is different this this is saying that this is uh not nullable and you did not provide any default value so we can do this this is different cool now here we'll provide button classes same BTN btns BTN danger save and for top neor now we don't need this redirect URI we can remove this form from here and just have this class and we'll say log out form with button classes this great we don't need this navigation manager now cool save everything and run it it okay we are here so this log out button it still has the same look and feel if you go to dashboard we have this log out button this is the same form but we have this small uh the different design right so that means that component is working as expected now first thing we'll do we'll increase the size of this uh this left section okay so that it takes the entire screen and for that what we'll do layout or maybe let's add that to this container fluid only H so here we'll say m height Style Main height same thing caly 100 VH minus the 250 pixel so it is taking this much of height by default should we add it here if we add it here it is not going to get that so not here we'll add it on this Co md2 Style Style and class okay save everything and now we can see this like this now for this dashboard this section this right section okay we'll have the same background which this has BG Gray so let's add a thing here 250 is a lot for this right so 200 maybe and for that left section let's go to dashboard we have Pages dashboard so what I'll do in pages I going to create a new folder I need to stop it to create a new folder I'll name it admin I'll move dashboard inside this admin here cool and on this dashboard this header section I need this header section I'll be different so what I'll do here I'll say div class BG gray the same thing then I'll have padding from all the sides right and then I'm going to have other classes so deflex justify content between what I want here so I can have uh the heading at the left side and the action button for example on manage category add a new category button that is should be on the right section of this so I'm adding this justify content between and here I can have H5 and here I will have Dash board I don't have anything for the right section right now but let's have D class we'll call it something action buttons and let's have deflex for this as well if we have multiple buttons and align item Center like this and here we can have our action button for example let me add one button so button type button and class BTN BTN SM BTN Maybe primary and some add something just save it and run it okay it came and if I go here we can see this cool this is working now this section this dashboard and this button this section is going to be applied for all our admin pages right so what we can do but it is going to apply for all the pages so that we can have this on the layout but the point is this text is going to be dynamic this button is going to be dynamic I tried with sections but somehow the events with Section does not work so we can have this text so what I mean is I can simply copy this go to admin layout and I have this section here I can have a section outlet with some name so let's say section name I'll call it header and then if I come here and here I can Define that section Outlet uh section content section content with the same section name that was header we can provide this thing so it will work and if I have something outside this section so let's say h 4 or maybe some p I'm saying content of dashboard so although it is before this section but this section is going to be rendered at the place which we have defined in our layout now the problem here is with this section this button let me add one event handler here so private void uh some ABCD okay okay and let me add a break point here and on this button I'll add this on click on click and I'll call this ABCD now if I save it and run it so this button click event so this interactivity this does not oh maybe it was because this page was not in interactive when we when I looked into it that's the case let's see right now nothing is happening so for all these event handlers and all of these things I can add uh render mode interactive server let's see if it works maybe when I tested I did not add this interactivity interactive server or interactive server or interactive web assembly but right we have set up our project for interactive server only so just interactive server we will need this for our manage categories and blog post pages but for this let's try it out no it does not work no it does not work okay I was not wrong so this does not work the text content is going to be Chang changed we can see this what I mean changed I can set any content that is going to be rendered there so in order to achieve this same thing what we can do we can simply extract this content out in a component in a saate component so in this not in pages in shared I'm going to add a new razor component and I'm going to call it admin header okay and in here I'm going to add this thing now this dashboard this title this is going to be dynamic so let's create a property here public string and string title and this is going to a parameter we are going to get it from the consumer of this component and we'll add editor required because this is going to be required for us this so title like this and then this button this section is going to be dynamic there could be multiple buttons there could be one button so how can we achieve this for this we will simply add a property of type render fragment nullable render fragment with default child content so user can provide TI content for this which will be the right side or we can add uh if Does this does not make sense in the way that this is not actually the body of this uh admin header what I mean is now let me show you first let's consume this so first thing I'll go to admin layout I'll remove this section I don't need this here then I'll go to dashboard I'll remove this and for this top section I'll say admin header it will ask me for title I'll provide dashboard and then for that for those buttons how the current implementation of admin header how this will allow us it should be a child content body that means we need to provide those buttons here like this but if you directly look at this this does not make sense the buttons are direct child of this admin header this does not make sense so instead what we can do we can have named fragment so for this we'll say action buttons okay we just named it and we are going to use this and now from here inside this what we can do we can use those action buttons like this right save everything and inside this action buttons we can add this not here here let's see if it works okay it is here let's see if I go to profile we have some issue it says admin header does not have a property matching the name child content but we don't need child content right am I missing something here action buttons admin header render fragment action buttons oh parameter save and if I go back to here I can see action buttons cool okay now let's run it now it should work now it makes sense because this admin admin header title is this and action buttons HTML is going to be here so it makes sense and it is here prints and we can see this right everything is fine cool let's remove this thing and right now for this particular page we don't need this action button so we can remove this we don't need this code section remove this we don't need this interactive server remove this save everything and okay now we good now we'll start working on the next page which is going to be our manage categories page so for that first we work business Logic the service layer basically so in Services I'm going to create a new class and let's call it category service like this and now inside this let's add a Constructor and we can use our application DB context now with this application DB context when we use interactive server with blazer so it's always a good practice to use DB context Factory instead of concrete DB context classes the reason is by default uh these ad DB context these are registered as code we can change those to be uh transient but sometimes we might trigger two different uh calls parallell on the same DB context so that can again give us that exception that this DB context is already in use so it's always a good practice to use idb context Factory how we can use this instead of directly uh registering the application DB context what we can do we can register I DB context Factory this one and this is generic type interface so we can pass our application DB context that we need a factory for this DB context so let's name it idb context Factory and whenever we need it from this we can simply access this create DB context method or create DB context Asing we could use any of these okay so now let's create the the methods which we need so first we need a method to patch all the categories so we'll say public a sync task and the category array let's call it get categories async okay now we can get access to the the context using this context Factory dot create DV context or create D context iing now we will use this but the context should be short lived we should create instance use it and dispose it as soon as possible and this idb context Factory R DB context it gives us uh I disposable so instead of using it like this we can say using and it is going to disposed right after this uh code execution leaves the body of this method okay now after this let's get the categories here we'll say categories equals a weight context dot categories dot as no tracking because we are not tracking anything here we are not tracking any change and then we can say to array ising and after that we can simply return these category so we are good now okay now let's create a method to save the categories public async task and let's return the category only and here we'll say save category async save category async and we will get category object and then we'll try to save it here so for this first we'll check if this is a new category or we are editing the category so for that we can simply check category. ID if it's equals equal Z that means it's a new category and if that's not the case it's an existing category like this okay so when it's a new category first thing we want to check if this category already exist in our database right let's say I have that uh Blazer category already and I am creating a new category and I again created bler category so this should not this should not happen right so now we need to check if this category with this name already exists for this we need context for that we need to again try creating a con context from this create DB context now if I do this here I need to do this inside this section as well else so one approach could be let's keep it just before if and else now again this line this thing we need to repeat it everywhere right we creating this context and then we are disposing it instead of doing this what we can do what I use for such scenarios I use uh template pattern what that is we will Define a method so private async task okay and it could return anything so task T result and then I can say qu or execute on context something like this and now it will expect a delegate of type Funk and it will pass application DB context as a parameter and it will return a task of T result as out T result T result like this execute on DB context okay and we can name it whatever we want maybe let's call it query I don't know if this is the right naming but we should be good okay let's use it query only and here what we'll do we'll get this like this and then we'll simply say query do invoke and we'll pass this context and this should be avitable and we'll return this like this okay now what we can do when we are doing this operation so instead of doing this it like this because now we don't have context so we will get get context from this method what we can do here we can say return return a wait execute on context and in here we will gu get access to the context like this and we can simply move this logic inside in this method and now we are good let's make it a sync so now this method we're going to use this in all our methods what it is going to do simply it will create a DB context it will pass it to this inner Lambda function and then it will execute it after that it will return the result and dispose the DB context that is what we need right so same thing we'll do here we'll say return await execute on context PR sync context and now we can have have this complete logic inside this method okay like this cool let's return this default category category okay now we need to check if this the category with the same name already exist right so what we can do we can check if a we context do categories do as no tracking or maybe let's um should we get it outside of this yes let's get this category outside of this mhm we'll say our DB category category equals no no no no no you should have it inside this only because the checking for the duplicate name that condition going to be different for lse case okay let let me show you what I mean here I'm just checking if a wait context dot categories do as no tracking Dot any async c do name equals category do name so this means one Cate there is some category of this name which already exists in our database so from here what we'll do we can simply throw an exception throw new uh let's say invalid operation exception okay and here we can pass our message which is going to be category with the name and we can have our category do name category. name already exist okay now after this now the category does not exist that means we can can work on it so for this category the slug we will create the slug so how can we create it we can simply say category do name and then we can apply our slugging logic but the slug logic slug is converting this title this name to uh URL basically by removing all the special characters and all those adding High so this logic we are going to need that for our blog as well so for this what we can do we can simply go to our extensions method and we can create extension method here here we'll say public static string and we'll say to slug okay and it will get a string so string text and then we'll convert it so how we can convert it we'll say first thing text Dot to lower after that we going to replace all the spaces with hyphens so there shouldn't be any space let me move it to the next line after that we are going to replace any double hyphen to single hyphen there could be uh multiple hyphens and then we'll simply trim the trailing and leading uh hyphens because we don't want hyphen at the very beginning and very end of the string now we have converted spaces basically but we need to trim out all the special characters as well so for this what we are going to use let's cut it and we'll use regx regx do replace input is going to be what we already have so let's do this let's make it a full body function so here we'll say were or let's modify the text only like this then we'll say regx do replace first we need to pass the input which is going to be this text only then the pattern in the pattern we are going to use anything which is not 0 to9 or 8 to0 okay so the capital are not going to be there there because we already made this lower so we are allowing 0 to 9 A to Z and we are allowing underscore nothing else okay if that's the case then replace we would have some other overload replacement we will replace those special characters with hyphen like this it returns a string right so now we'll say text equals this what it is saying use generate regx attribut generate the regular expression implementation at compile time and if I use this it is using this slug reg X I have not used it I have no idea about it if you guys know about this how this works please do let me know in the comment and I'm going to definitely read about it okay so slug rx. replace now what we should do uh this thing we should get this out and then return this thing from here so let me explain it what it is now cool so first thing when we came here we converted the text to lower case then we replaced all the spaces with hyphen mm if we are replacing spaces with hyphen we don't need to do this right because this regx is going to handle this so let's remove this if we are doing this then maybe we can simply get it and use this directly r x repace right like this now we have lower case and whatever character we have that is not 0 to9 A to Z and hyphen we are replacing that with hyphen after that we have this line which says now replace double hyphen because there could be double hyph what what if I had uh let's say maybe I created uh Blazer space hyphen was something like this now if it will be converted so it will be like this Blazer then hyphen this is space then again hyphen this is the starting parenthesis then was and then hyphen so it will convert like this right so now what we are doing we are replacing the double hyphens with single hyphen so we will convert this thing in here so it will become Blazer hyphen was Hyphen like this after this we are trimming the leading and trailing slashes so this line is going to remove the last slash so let's do like this okay so this will behave like this cool so now we can use this two slug category do name. two slug to slug great now we can add this to our context so we'll say context do categories do add async and we can add this category here us AIT cool so this part is done after that we can say await context. save changes I syc now in else part when we are editing an existing category so first thing we'll check if that name exists so for this what we can do we can copy the same condition but with one additional condition and that condition is going to be if this name already exists with some category which is not this current category so C do ID is not equals category. ID right if we just use the first condition and let's say I am uh modifying the Blazer was category so what it will do this this condition will return true because Blazer ver category is already there so it will fail but when we added this now this will check if this name exist with some other ID not this current ID okay that's the case we will simply say category with the name already exist so that is fine after this now we will get this category from database for the updated values so we'll say word DB category equals a wi context do categories and we can use find method so find a sync and we can pass our ID which is going to be category do ID like this let's move it to the next line okay now we have this DB category now what we'll do we'll simply say DB category. name equals category. name we are not allowing user to modify the slug the reason being when we first created the category there could be some URLs which already indexed by some search engine so if we modify the slug from here it will simply break those URLs which we don't want right okay this time we know this is not this shouldn't be null actually and then we have one more c one more field which can be updated that is show on NE so category. show on NE and then we can again save changes so instead of doing this at two places we will simply add this after if and else both the condition and then we'll simply return the category okay so before returning it we can do this category do slug equals DB category do slug in case somehow the client modified the slug we will revert it back to what the database L was let's do this here cool so now we have save category method we have get all categories method apart from this what other thing we can have we can have get category by slug right for the category URLs category pages so let's use that as public async task category and it could be in a label and here we'll say get category by slug missing and here we'll simply get the category slug okay here we'll use the same thing a wait execute on context a sync context and here we'll say AIT context. categories dot has no tracking dot where or we could say first or default directly first or default asnc we'll say C do slug sorry C Dot slug equals equals slug if that's again it is going to return it and now we are good with all our methods so our category service is done let's extract the interface for this and I'm adding the interface in the same class only what it is saying it is saying use primary Constructor I don't know I don't like primary Constructor so what it does primary Constructor means we can move it it from here to here like this but I don't like this do you guys like this primary Constructor do let me know in the comment if you like this primary Constructor feature I don't like it so I'm not going to use it unless unless my company my organization is using this feature then I'll have to use it but from my own I'm not going to use it maybe not yet maybe sometime in future I like it I don't know okay now let's register this category service so go to program.cs and where we register a SE service after that let's add this add transient and I category service with the category service like this cool now we can use this C category service to uh okay we can use this now so what we'll do we'll go to components and Pages admin and here we'll create a new razor component that we are going to call it manage categories let's add the URL and that we are going going to use at theate page admin SL manage categories like this save everything and then H manage categories we are going to have layout which is going to be admin layout admin layout right layout admin layout but we are going to use this admin layout on all these pages so what we can try we can create an uncore Imports file underscore Imports and we can add the layout here so we'll say layout and that is going to be our admin layout so when we have underscore Imports file that gets applied to all the siblings and uh we could say the hierarchy the file hierarchy so when whatever I add inside this underscore imports. rer so its parent is admin so whatever we have inside admin this underscore inputs is going to applied for all those so in this particular case this is going to apply it for this underscore input dashboard and manage categories and if you check we have onecore Imports on the components label directly sorry so this underscore Imports rer whatever we have in this this is going to appli throughout this components folder so on directly on app. rer routes. rer then in Pages accounts layout everywhere so that's how this underscore import rure works so whenever we have some common logic some common uh these kind of stuff adding the name spaces using layouts using uh yes we will need authorized attribute as well instead of adding it to all these Pages dashboard manage categories we can add it directly to this underscore inputs so this authorized attribute is going to be applied for this admin folder like this save everything and now we are good so from dashboard we can remove this and at theate layout it will use from underscore Imports and our manage category also we don't need this cool so save everything and from dashboard let's Okay on here let's add that admin header and here we need our title we'll say manage categories like this and on this we need that action button what was that action buttons right so we need a button to create a new category so button type button and classes are going to BTN BTN primary BTN SM and here we'll say plus add new category like this so save it and let's try to run it admin SL manage categories right so if you go to admin layout it should be like this only admin SL manage categor typ let's go run it and we got some exceptions some services are not able to be constructed service type by category service lifetime transient unable to resolve idb context Factory okay that's because by default if we check for application DB context this add DB context so instead of using this add DB context we are going to use add DB context Factory so save everything and let's run it again it should work this time yes it came cool log out there is some issue we'll check it later log in it is logged in now we can go to manage categories and we can see manage categories and add new category we can go to dashboard like this okay it looks fine cool now let's work on this section this page so now we are going to display the list of categories so for this what I am going to use I am going to use Quick grid which is a new component Blazer gives us so that is available as a separate new get package so I'm going to install that new get package browse and quick grid and we need the one which is coming from Microsoft which is this Microsoft aspet core component grid this is coming from Microsoft by Microsoft yes okay let's install it apply except and we should be good now cool so manage categories and here we can start using that so before everything we will inject our I category service and we can't get it that's because let's add the name space here so we'll say blazing blog V2 doservices and now we should be able to access it category service I category service what is happening categories manage categories inject I category service I'll call it category service only okay then after this admin header I'm going to add quick grid this one okay so I can remove this and add this name space quick grid okay now this quick grid it needs access to the list of items which we have okay so for this this particular thing this uh current uh categories we can have with the list of categories because we don't have much categories we are going to have hardly 15 20 categories so we can load them at once and use them directly but for uh blogs we are going to use a different approach with quick grid so right now how it works we need to provide items this this is going to be a i quable collection of items here I'll say private I queriable of category categories and this category let's inject this as well so here I'll say this dot t variable can we do this no okay we'll say numerable do empty category do as variable this is the default then on this quick grid items we can simply say add the rate categories so these are the quick grid items then we need to provide the actual value for this so on initialized a sync we are going to get our categories so at the rate uh sorry underscore categories equals a weight category service dot get categories isnc like this what is the issue the issue is it is an array of category so we can apply this as quable if we want save everything and now we are good okay now for this quick grid we need to provide what all columns we want so those are property columns in this property column we can Define it so this property columns it has a parameter of type property and in here we can provide a Lambda so this C this is going to be provided by quick grid and it will be the type of items we have the type of item is category so the C is of type category the First Column we need for c. ID then let me copy it a couple time C do ID C do name then C do slug then C do show on never okay looks fine save everything and now it should work let's run it okay let's go to manage categories and we can see this data cool so it looks fine now let's work on design first so we'll apply bootst step classes so on this quick grid we can add simple HTML attributes so here I'll say table table bordered table striped and table hover all these are bootst step classes we saved it let's see if it got applied yes sorry so we can see this it looks pretty good now first thing show never let's change this title okay this show a so what we'll do this property column it gives us uh title parameters so we can say show on never and we should see this cool after that it is showing this true false true false true false this is not what we want right we can it can be okay but for us let's add check boxes here with the word yes and no if this is uh showing if show on never is true or false we are going to display checkboxes with yes and no text so that we can allow changing the show on NE status directly from here okay so for quick grid if we need some uh customization to the columns generated HTML for that we can use templated column instead of a property column we can use templated column it does not have property because we need to pass our own implementation to this column but it has this title so we'll say show on never and inside this template column we has we have access to a special variable which is context which is of type category which is the type of items we have so we have this context so here we'll check if context do show on NE if this is true then do something if that is false then do something else so that's something is if it is we will display a checkbox for both we'll display here label text success so that it shows in green color and here I'm going to have an input type checkbox and this will be checked automatically because we have shown never true so that should be checked only and after this I'll display yes and now let me copy this paste inside the this else condition and here I'm going to say text danger I'll remove this checked attribute and I'll say no now save it and let's see how it looks and or reloading did not work so let's stop it and rerun it okay it's there go to profile manage categories and now you see this first one is property column this second one is templated column so template column we can have this yes no this this interactivity is not working we'll get it to work but right now you see we have this yes which are true false with red colored no with uh unchecked check boxes cool now we can remove this show and Ne this first one property column so let's remove this show and Ne this one we don't need this and after this templated column this show on nebor we will have one more templated column template column four are action button to edit this category here I'll say button type button class BTN BTN SM BTN primary and here I'll say add it so to edit the category again it's stopped stop it but before that let me do one more thing so we need to have this interactivity when if I'm changing this check boox checkbox status then it should actually modify it so for this what we can do we can have a method here so we'll say private async task and we'll say let's say handle uh show on nowar change like this okay then we will have the complete category object okay then what we'll do on this category object we'll say category do show NE equals opposite of category do show never so we will have the toggle effect show and then what we'll do we'll simply say a wait and category service dot save category ising and we'll modify this category like this cool now if I run it uh but before that let's call this method so we should call this from both of these check boxes here I'll say on change equals here I'll say handle this with context context c o and tx2 context and like this okay let me copy this same thing and add it to this next check boox like this cool now we have not applied any interactivity on this so that means this uh this page is server side rendered statically server side renders so we do not have these things we could achieve this thing using JavaScript but we are not using JavaScript we are using blazer with C so these things are not going to work because this page is not interactive that is the whole point of SSR if I go to here manage categories nothing is going to happen this check this is the default stml implementation that it shows this but this is not getting changed it should have went to no when I removed it right so in order to add the interactivity to this we need to change this uh a bit we will add a render mode to this and that render mode is going to be interactive server now this page is going to be interactive that means it will create a new signaler connection and it will handle these methods and we'll be able to use these let's run it and let's see if we got these things working manage categories can you see no yes no yes we are getting these things okay if I have it no so let's see the first one is yes then there are no till react if I refresh this page you see I have the same that means the data is saving now I have this alternate with last two yes so if I refresh it you see we have this data now there is one problem which we are not seeing that is uh this get categories iing this on initialized this is going to be called twice once for the on the server because by default the pre-rendering is in enabled what pre-rendering is for all these interactive components Blazer first try to render this component on the server side then it passes this component to the client and on client it again uh initializes this component as for the server or web assembly so in that case this on initializing executes two times okay so we can use per component state for this or if we do not want pre-rendering we can disable pre-rendering so in this case we are going to disable pre-rendering we don't need pre-rendering for this pre-rendering helps in SEO basically so for these admin Pages we don't want we don't need any SEO so we can it will be good so we'll say at theate new interactive server and here we can say pre- render pre render calls interactive server that is interactive server right interactive server render mode and pre-render false so it has this pre-render flag save everything and it should behave the same I'm running it and H prints manage categories and we are here and we can modify this everything still works same cool next thing is we want to work on this add new category and this edit functionality okay so for this what we are going to do we will uh show that create category and edit category form on this page only okay so here what I'll do I'll simply add a DA class row and inside this I'm going to have div class call sm6 I'll copy this and I'll have that at the right section of the screen on the above this quick grid so here I'll have an edit form and this edit form needs a model so for this we'll have one private category model here basically for uh which will hold the current operating category so private category at let's say operating category C default is null okay so the addit form model is going to be this category and in here first thing we'll have our data annotation validator after that I'm going to have one da class this is going to be container of our uh check boox and text so div class uh let's have a shadow okay and now inside this I'm going to have a div h let's have these two sections first section we'll have our label and category name text and on the second section we'll have our buttons okay so let's do this first I'm going to have first div and then I'm going to have a second div this first div I will have label and class form label and this is going to be category name like this and after this I will have input text and bind value this is going to be for operating category dot name the category name okay then add couple of bootst Step classes so we'll say form control and form control SM these two classes and then we'll have a placeholder text here placeholder which will be the same category name category name like this okay and after that let's have a validation message validation message for same operating validation message okay like this operating category do name okay after this what I'll have I'll have uh check box for are show NE so here I'll say div class form label okay inside this I'm going to have input checkbox with the uh do we need bind value yes bind value with underscore category not category operating C category dot show on Nar like this and on here I'll have text show on N part like this cool so we have these two sections here and in the second Dave I'm going to have two buttons first button of type submit class BTN BTN SM BTN success and this is going to be save button then a second button with the button danger and this is going to be cancel and everything looks fine but we will render this this div class row only when we have this operating category so we'll add if condition here if this is not null then only render this section now when this is going to be not null before this we have this add new category on here we can say on click and we can simply set operating C category equals new okay cool and on this cancel button we can say on click equals operating category equals null okay so add new category it should open this cancel should remove this and then comes this edit button this edit button right so what it should do it should do I'll have a method here private void handle edit category something like this and we'll have access to the complete category and then we can simply set operating category equals category save everything and on this on click we'll call this handle edit category and we'll pass the context which is the category object here okay I think it's fine we are good we can see this now let's run it it is coming let's see okay this we need to fix and here manage categories we have this now add new category we can see this right and if I cancel it got cancelled and if I add it we can see the correct values right right great so this functionality is working we need to to work on this uh UI a bit more and then we'll work on saving the changes and there is one more issue we need to tackle that as well okay first let's fix the UI we need to add some padding to this so what we'll do here on this sh Shadow let's add P3 so from all the sides we have added a pading okay it looks fine now this is also looking fine right but let's see how we envisioned it that save and cancel these two buttons should be on the right side so what I'll do here on this Shadow on this div I'm going to add a style and I'm going to say display grid and then I'll say grid template GD template columns so I'll Define two columns first one is going to be Auto whatever width it can take and the second one 150 PX for the buttons okay and then let's have grd columns gap of 10 PX now we have this two divs so first First Column with auto then this second with this 150 PX inside this we have these two buttons so let's have these buttons uh stacked vertically so on this I'm going to say deflex which is for display Flex plus deflex and then hm Flex column and let's have some spacing mv2 and now we can see this okay let's increase this spacing and let's increase this spacing and show NE let's add some margin from Top on this one okay let's go so this column Gap we'll make it 15 PX and on this label we'll say empty uh two margin top two save and let's see how it looks now okay it is looking fine cool save cancel this show un never everything is fine but there is one problem here you see this is Entity framework core we have Entity framework core here now if I'm changing it just change I did not save it it is modifying this value which should not happen because we have not saved it yet so can you guess why this is happening you can pause the video and check why it is happening and okay so were you able to figure out why that is happening if not let me tell you the thing is when we are clicking on this edit category button then we are passing this context which is this current category which is a reference type class and we are directly setting this to this operating category so that means this is the same reference which comes inside this form and when we check or uncheck or do any change it is actually modifying the original category which is inside that grid and we can uh see that change immediately in the grid but that should not happen so for that what we'll do you if you are following my videos you can tell that I often use this clone approach so what I'm going to do I'm going to create method inside this category entity and I call it clone and I'll use member wise clone as this category and I know this is not going to null so we can do this so now I I will have a clone different object okay so when I'm setting this operating category so I not directly set this category I'll set category do clone now this is a different object to save it okay okay okay cool now let's work on saving the category so for this let's create a method here we'll say private Miss sync task save category as sync okay so for saving this category we have this operating category we'll directly work on this operating category so before that let's call this method and we'll call this from edit form on valid submit we'll call this save category sing method save and now let's use it so how we are going to use it first thing we have category service we can save the category async and this is going to be operating category I know this is not going to null but still let's check operating category is not null then only we'll do this and here we can be sure that this is not never going to be null so fine save category async everything looks fine now okay let's see if this is working let's run it all right profile manage categories and let's use Blazer I'm doing this it is not changing that means this thing is working now I'm saving it and nothing happened why nothing happened let's see if there is any errors in console we don't have any error why this thing is not working save let's put a breakpoint data annotation validator everything is fine we'll add this breako here save save and it got hit okay it is getting saved but because we are not doing anything after that that's why we are not saying anything so for this what we can do let's have a loader so I'll say private it's loading or is busy it's up to us what we are using let's say is loading private buol is loading okay and this loader we will use this loader on other screens as well so let's do this let's create a loader component so in shared in component then shared we'll create a new component and we'll call it loader okay and here we are going to add some markup first thing we'll have an overlay so this is going to be an overlay and then the second we are going to have a div with let's say display Flex justify content Center align items Center and let's have a label first loading and let's use it and we'll design it let's have it here loader I'm adding it just to check the design so that we can see the design using H load and then we'll uh fix the the state and all those so let's go to profile manage categories and we can see this loading okay so on this loading let's have some style so sty file type text CSS and here let's have a full screen class okay full screen fixed and here I'll say position fixed left zero right zero top zero bottom zero so that it gets the complete screen full screen after that we have this overlay and overlay we can have a background color of black and we'll add some opacity to this maybe 0.5 0.5 we have overlay and then full screen fix let's use this here on this page on this overlay we use full screen fixed and the same class we are going to use on this one as well full screen fixed now this label it should be in the center save and see and that is not here there this is here here it is so it is in the center this manage categories on top of everything right so it is because of some Zed index the selected one Jed index 2 loader should have the highest J index so let's have the Zed index as maybe Tri 9 on this or maybe 1,000 we should not use a lot I think if we are using loader uh this bootst step uses 1049 for its modal I guess so let's use this 1050 for this one uh 1050 for overlay and 1050 51 for this section where we are going to have our uh text so let's call it maybe loader wrapper something like this okay here we'll say J index 1051 like this save everything and let's check it and now this is on top but because it does not have the this color and all this that's why it is showing like this what we'll do here for this loading table I'm going to have a div here div class I'll say BG white okay P5 or P3 maybe and I'm going to have a large Shadow on this and then I'll have my label loading so let's see how it looks is looking like this okay it is coming up good now if we go to get bootst strip.com version 4 because we are using four 4.6 maybe in this also it has the same design so components I need spinner this I'm going to use any one of these Maybe this one so after loading I'll use or before loading I'll use this let's see if it works no because this is 4.6 and we need 4.1 what if I use 4.1 like this not found 4.1.1 okay components maybe we did not have come with the Spinners in 4.1 utilities no we don't have okay that is fine if we don't have those there or we will let me search spinner no we don't have that okay no problem so we will simply show this loading text for this what we can do so this this we have P3 let's make it P5 and do we have some border radius or B okay we have borders border color border radius so we have rounded let's use this rounded on this da okay P3 was fine I guess P3 this is fine and on this label let's have M b0 so there is this margin bottom so let's have it Z so let's do this let's use this go there BG white P3 Shadow LG and rounded and we can remove this we don't need this and for this loading text we'll use class mb0 margin bottom zero okay let's save it and let's see and it is looking like this okay we can use this now what else we can do we can have this loading text Dynamic so we can expect it as a parameter so we'll say private sorry not private public string and we'll say loader text and we'll have a default value as loading dot dot dot and this is going to be a parameter and we are not adding editor required so we can skip this it will have default value of loading in that case and on this we will use this loader text like this so save everything and we are good okay let's go to manage categories we had this loader now what we'll do we'll handle this this loader using this is loading so we can place it anywhere on the screen because in this loader we have CSS it will always going to be on top of everything and it is going to uh capture the entire screen so the position where we put this loader component does not matter we could place it anywhere okay so I'm going to add it here so I'll check if this loading is true then only add this loader component now for this loader component we can have first we are patching the categories after that we are going to saving or uh saving the categories changing the Status so we can have Dynamic loading text right because the operations are different so here what I'll do I'll have a private string and let's the label and we'll say loader text or loading text like this okay so then what we'll do we'll pass this here we'll say loader text equals this underscore loading text un initialized async let's set it to H fetching categories like this okay and after this we'll set is loading to false so let's have default value of is loading to True like this okay save everything and then when we are using this handle show on n Bar Chang let's add the same thing here so we'll say is loading to True before that we'll set loading text to uh saving saving changes something like this and after updating it we'll say is loading to false and same thing for saving the category we'll use this and after saving it we'll say is loading to false so save everything and let's try it out I'm running it okay manage categories and let's use Blazer to never save and you see there was that loading icon and but at that time after saving it we should clear this out and this should reflect those new changes right this grid so right now the grid is uh using this categories is sing this categories I variable right can we uh on this quick grid maybe we can directly modify these categories we can refetch the categories or we can simply modify that particular category so okay so it would make sense if we load the categories again so I'll say private is sync task I'll say load categories is syc like this and let's move this logic also here so it's loading false and before this we'll say it's loading to true so now we can remove this default value and from on initialized async we will directly call this method a wait load categories async and then the same method load categories async we will call after saving the category from here is loading false after setting this we'll say load categories a sync like this we can make it a little bit better if it's new category we can directly add the new category which we will receive as a output of this method we can add that to this categories collection and if we are editing some category so we can directly uh update that particular category from this categories collection so we have these two approaches but I choose this the simplest one I'm reloading the all the categories okay but there are other approaches which I just told you so you can try those as well now let me save everything and let's rerun okay and I'm missing something let's stop it h so saving changes is loading after saving this we will reset this operating category back to null we don't need this section now so let's run it okay we have it manage categories this thing is working as expected now add new category or maybe edit category I am editing Entity framework code I changed this show n now I'm going to save it so it should change this as well save Entity framework code it got reloaded and that got removed mov from here so that means the things are working as expected let's try to create a new category cop asp.net cor Blazer SQL Server what else we can use uh let's say razor Pages rure Pages show number save so rure Pages we can see this okay now we can modified from here now if we edit it we have it like this we can cancel it we can come here here we can remove show never update it and we are good so that means all the category related operations are done now we can see the list we can modify this we can add new categories edit new category and everything is working fine cool now once we have these categories so why not populate those categories in this top Navar right we need these categories so let's populate these categories so what we'll do we'll populate top five categories which has this show on NE true right because that is what the show on NE flag is for we will decide that what all categories we want to show on this stop nbar okay first let me push this changes then will pull these categories on this Stop n so those categories are coming from our main layout so pages and not Pages components layouts we have main layout and in main layout we have top NE if you go to top NE here are all these categories okay so what we'll do here we'll inject our I category service first category service we'll call it category service and then inside this code I'm going to have a private category which is this entity and I'm going to use categories with a default value of empt AR okay then I'm going to override On initialized async and Here we'll simply populate the categories from our category service do get categories I think we'll load all the categories after loading all those categories we will add the categories which have show on never true c. show on never do two array okay but we can only take five so we'll take five so from all those categories which we loaded check for show NE where show Nar is true take five save everything now there could be a case with show on neor we don't have five categories maybe we have 1 2 three or we don't have at all any show never so for this what we'll do after that we'll get some other categories randomly from categories right so here we'll check if categories do length is less than 5 right if this is less than five so this 5 five we might have it at other places as well so let's have it as a constant private cons int and we'll say Max uh categories or category count to show something like this category count or no Max category would make more sense Max categories to show on never something like this and this is five so this should be five and if this is less than five which is Max categories to show so in this case what we can do we can get those categories additional categories from this categories uh collection which we got from the API from not API from this category service so here what we can do we can say categories dot where C do show on NE is false because we don't want to duplicate it right if we don't add this condition then we might duplicate it so we have to a show on NE categories and if we do not add it and we take three more from this categories then we might get the same two so we might have duplicated or plus our values so we'll say not show NE that means from other categories just take how many the show Max category show neor minus categories. L like this so if this underscore categories if it got three items three is less than five yes then it is going to get 5 minus 3 that means two so it will get two more items now what we can do we can simply add these to this categories are okay so what we can do we can say categories and then array then we'll simply spread these categories what we already have categories with this double dot I like this notation but intelligence does not work with this so and then we'll do this if you are coming if you are familiar with JavaScript you might have seen this in JavaScript we need to add three dots but in uh C of 12 we can have two dots cool so now we have categories selection now we can use this underscore categories to populate the menu items so after home we'll add a for each here for each we see in underscore categories and then let me copy one of the AL here paste it and then HF and this text these two things will change so C do name that is category name let's remove all these and then this hrf this uh you right now let let's have it category only we right now we'll just see if uh we are able to load the categories and everything is working fine then we'll work on this actual navigation okay so save and let's see if we are getting the correct categories on the top nav bar okay it is here we have c 2 to 415 login do this manage categories and let's do this let's remove all and let's have only two so we have EF cor and angular but we have changed this right and these are getting saved in the database but this thing is not getting uh changed that's because this section is not interactive if we refresh it then it will work so we have aspet core Entity framework core angular and then these two are coming dynamically from the C and bler these two right what should happen here if I add this it should change in real time right if I'm changing it here it should change so for this what we can do on our category manage categories page we can inject navigation manager inject navigation manager navigation manager and when we are changing the show never uh here show on never after that what we can do on this navigation manager it gives us one method which is refresh so we can use this method to refresh let's see if it works directly or we need to restart okay where is it it is here ASP net scoree and we have some error object reference not set to instance of an object navigation manager we have navigation manager okay we need to stop and run it so the template was able to use that but it was not able to get this from this uh di connection navigation manager navigation manager yes okay let's go here manage categories vfc first we have aset core second then we have Entity framework core but let's do this Blazer let's add Blazer here so you see we added this Blazer here and we can see this Blazer here now if we add this equal server we can see it if we remove all these it will get the first five then let's start adding razor pages so first one is Razor Pages then view so now we have View and razor Pages then ASP net code so that means the saving is working and this main top Nar is also able to fetch the correct categories in real time so this section is also working cool so we have achieved a lot till now right okay now let's start working on manage blog post page right now this is 404 because we don't have anything okay okay so for this we'll start from our business logic our service so in Services I'm going to create a new class and this should be blog post service blog admin Post Service let's call this this or blog post admin service because we are going to have two different set of methods for public and for admin the main difference is going to be the public ones should show only the blog post which has is published flag to True okay so in here first let's do this let's create a interface public interface I blog post admin service service and this is going to have three methods so task of blog post array and here we'll say get blog [Music] post and then we are going to have one blog post for get blog post by ID okay blog poster gu ID or int ID it has int ID so int ID and then there is going to be a save blog post sync and we'll get the blog post object get blog post by ID sync get blog post a sync like this okay now we are going to use Quick grid for this and we are going to use paged results because we are going to use paging with quick grid for these blog post because these can grow in numbers right so for this what we are going to have we are going to have a separate type for page result so let's create a new folder here uh let's call it models and in here I'm going to have a class page result like this and it is going to be uh record so public record page result T results the type of data and in here I am going to have t result array records and then total count like this okay so the return type for this is going to be that page result of type blog post like this okay now this is going to be page result so it should have some paging parameters so it will have an start index which will be provided by quick grid and then we are going to have page size which is records for page and I think we are good cool let's implement this interface in our service I blog post admin service and we have Implement interface cool now let's add the Constructor and in here we'll inject our DB context Factory I DB context Factory of type application DB context context Factory and we follow the same approach we followed for category service creating this execute on context method so let's copy this method and come here and add it here and now we are going to use this method for all our methods so first let's start from get Blog poing the list okay here we'll say return a wait execute on context as sync context and then we can have our complete logic here and the logic is going to be we'll construct our query first so this is going to be uh context do blog post do as note tracking we don't want any tracking for this and do we need any else on this one H let's include the category B do category so that we can show the category name B do category and I think that's all H now we'll use this query two times first we'll get the actual records we'll say records equals a weight query dot 2 array async like this and then we'll have count a wait query do account isnc and then we are simply going to return new paged result of blog post first we are going to have records then second we are going to have count now count is fine for these records we are going to apply this start index and Page size so on query not on this one what we'll do we'll say query dot or maybe this include we can add to this one only right yeah let's do this include query do include category order by uh let's say order by descending B do created that of ID these are similar things from here we'll skip start index and we'll take page size and then two erasing so we applied paging here so we need count before applying paging to show the total count total number of Records so that quick G G can uh know that if there are some previous page or next page and it can know that how many pages are going to be there page number 1 2 3 4 5 like this okay so this method is done let's Implement get blog post by ID isync so for this one we can simply say uh await execute on context a sync context and from here we can say await context dot context infut should be context so this name is up to you you can name it whatever you want this is simply a Lambda uh parameter D parameter for this uh fun delegate you can name it whatever you want so context do blog post dot as no tracking sometimes this intelligence is very bad dot as no tracking we are not tracking the changes here after that we are including the category include B do category and and then let's find it so we'll say first or default isync B do ID equals equals this ID so we'll return this and this should be a label in this case and we are good what is the issue here task blog I blog okay in the interface let's use this okay we have this method ready now we have the save blog post ising which is going to be a big method here we'll say return execute on context as sync context and now here we are going to have our complete logic so first we are going to start with blog coast. ID equals equals z that means this is a new blog post then else this is an existing blog post okay so we will do kind of similar thing we have done for our managing category we'll check for duplication then we'll do all the uh saving and updating let's do this so for blog post. ID here what we are going to do we will check if this blog post title exists already right for this what we can do we'll say existing or let's say duplicate title something like this duplicate title okay here we'll say await context do blog post dot as no tracking dot any a sync B do title is equals blog post. tile so this means some existing blog post has this duplicate title the same title so we'll simply check if is duplicate is title duplicate something like this this duplicate title if that's the case we'll simply throw from here so throw new invalid operation exception same thing from here we'll say blog post with title with the same title already ex something like this with the same title already exists okay now if the title is not duplicated now we can do this first thing we need to generate the slug for this so we'll say blog post do slug equals uh blog post do title do to slug now there is one issue and that issue is there might be duplicate slug now you will say that if the title cannot be duplicated then how come slug can be duplicated right so it can be duplicated and the case could be with maybe special character so let's say I have some blog post one which has something like how to do this in Blazer and then I'm saying this was like this okay then I have some other here here I can say how to do this in Blazer was you see these two titles first one has parenthesis second one does not have this and it has this all caps but this has this uh Pascal case so now if we generate slug for both of these those the titles are different if check the title these are different right so it will pass this duplicate title thing then we will have this slug thing so here how it will going to generate Slug it will do how to this in Blazer was this is going to be the first Slug and the second slug is going to be the same because these two are going to replace with hyphen hyphen then those those two hyphens going to be replaced with single hyphen and that is what here the same thing so we need to somehow modify this blog title how we are going to do this how we are going to achieve this if there is some case where the select can be same we are simply going to append some 1 2 3 4 some uh incremented number to this if then there is going to be some third blog which will have the same this so we could add maybe two or maybe after one we will add one more something like this so for this we need to have some long logic so for that I would like to have a separate method so private async task of string and here we'll say generate slug okay and in here I'm going to pass the complete blog post object and from here I'm going to use the same execute on context method Miss sync context like this and now what I'll do here first I'll have the initial slug that is going to be this blog post. title. to slug okay now I'll check and to check we'll check if a wait context do blog post do as no tracking do any async with the dot slug is equals equals this slug now we need to keep on repeating this conditions so instead of doing this inside if we can use while but that is not going to work because we need need to check if this exist okay let's check this if this is Slug we directly return from here if it is duplicated what do this show slug slug return slug threading task I sync task oh it should be a wait H and it should be a wait and for others I must have already awaited those right so await and await fine okay now while this is true now this slug we need to modify this slug to check so for this now if it is inside this so we can say slug plus equals maybe hyphen one something like this now it will check and if it again finds the same thing it will do something like this lug hyph one hyph 1 hyphen 1 uh that is not going to look good right so let's do this let's have some counter maybe count okay and then let's have initial slug or we could say no yes okay slug let's call it uh actual slug or original slug something like this original slug equals this int count with one and then we are going to have one more slug to check which will be the same original slug like this H okay now we are going to check this slug here and when we are modifying it how we'll do it we'll do it like this so we'll say slug equals original slug let's use string interpolation and here we'll say original slug hyphen count Plus+ okay so now it will do this slug one if this also exists it will be slug two then slug three so it will give us the thing which we need so I think it is going to handle all the cases right if this while is not true then it will simply return this slug okay we are good with this so now for this blog post. slug we'll say generate Slug and we'll use the same blog post object like this cool okay General slug this is an async method so a wait generate slug async like this okay save everything and we are good after setting this slug we need to set one more thing so on blog post we need to set the created at which is going to be datetime do UTC see now we are going to use UTC and after that we have blog post do created or user ID we need to set the user ID so we need to have access to the current logged in user so we'll get one more parameter for this user ID from the front end let's add this string user ID to our interface here hm so we can set this user ID to this user ID okay now we'll check if this blog post is published is true if is published is true we need to set the published at so dot published at we'll use the same date time dot UTC now like this all other properties will be set from the UI form only so we are good now we can add this blog post to the context so we'll say context do blog post do add sync and then that's this blog post like this out bit cool so create new is done now let's do the update existing blog post okay so here also so we'll check if it is duplicate title so let's get this first thing from here but this time we will add one more condition so B do title is not title and B do user ID is not equals not user ID sorry b. ID is not equals to this blog BL post ID blog post ID s it's duplicate title and we have this throw exception with this cool now if we pass through from here then we'll get the DB blog post the DB blog equals a wait context. blogpost doind a sync and here we can pass our ID which is blog post. ID I'm not adding as no tracking here because I want this to be tracked I'm going to modify this DV blog directly and then I'm going to save it okay now we have this DB block let's modify the properties so DB blog do first we can modify title it should be blog poost do title you could have some mapper or maybe you can extract this out in some separate utility method but because I'm going to use it only at this place so I'm having all these mappings here only DB blog. title ID created it I'll remove this I'm just going with the flow with this intellisense blog post Dot introduction equals no no no DB blog do introduction equals this blog post. introduction come on DB blog dot after introduction we will have content blog poost do content let me add all these okay I have it here so I have title image introduction content category ID is published is featured and published at we should not have it like this remove it h I am not modifying created at and user ID and slug these three things I'm not modifying these right like we don't want to modify because we don't want SEO to free out created at it was already created at this time so we are not going to use this you could use modified at if you want and then user ID who's creating this right now our application uses single user to which is that admin user who can create the blog post so I'm setting it user ID at the creation time only not at updation so yeah then I'm setting this Flex is published and is featured now we have one more thing now we will check if the blog post is published that means right now we got blog post published if this is published then we'll check what was it before it so DB blog dot is published we'll check so if it was published before and it is published now we don't want to do anything if it is published now which is this blog post. is published and it was not published before that means we have published it so we need to set the published at field published at equals date time.utc now okay if that's not the case we can skip it we are not going to do anything and else if blog post is not published now so whether it was published before or no we don't want to check that we will simply set published at to n because this post is not published right now okay so as we are tracking so we don't need to call update explicitly now we are good now we can directly save the changes so here we can say await context Dove changes I think and we can return the blog post like this save everything and we are good so I think our service is done let's register this service in a DI container and let's start using it so we'll go to program.cs after setting categories service we'll say it add transient I blog post admin service blog post admin service like this save and we should be good now cool let's close all the tabs and go to components p Pages admin and we'll create a new page here which will say manage blog post post like this add and let's add the page directive here with admin SL let's see what we have in admin layout so admin layout we have admin SL manage blog post like this like this cool it's authorized and layout admin is already done on this underscore import so we don't want to do this here and here what we'll need first thing we will need our admin headers okay and this will provide title which are which is going to manage blog post and then we'll have a button and we you can copy the same button from our uh manage categories so the name is going to be add new blog post and we can use this as anchor tag because this is not going to button this is going to be redirected to some new page so a h RF and it is going to be let's say admin manage blog post Slash new to create a new blog post okay okay now I think we are good and we can start using this first let's see if we can if application is building fine running fine and we can navigate to this manage blog post page let's run it okay so it's here let's log out log in come here manage categories is fine manage blog post and we are on this page manage blog post add new blog post right cool now we need to work on this page okay let's start okay so first thing we'll add render mode to this page this is going to be interactive server but on this page also we don't need pre-rendering so we'll say and this is intellisense again not working I don't know if Microsoft is going to fix this or no interactive server render mode it should work but we can't see nothing is working the intelligence is very bad in Visual Studio pre render false so save okay after this let's inject r i blog post admin service blog post admin service and we'll call it blog post service like this and then let's have let me close and open this file okay now let's have same loader from the manage category let's add it here as well is loading and loading text like this H and on manage category page we were using this quick grid with this items which had these categories as I queriable now on this blog post we are going to have a lot of blog posts right so how this I variable works we need to have that complete result set in memory here only then it is going to apply paging filtering sorting all those uh grid operations on this Psy variable but for our blog post we cannot do that we can if we want but we will not do that that's not a good practice for this particular page so we want all these operations the uh sorting filtering paging and all these operations to be happen on server side on database level in our service layer right so for this we'll use quick grid with some different configuration so that is not going to use this items that is going to use some different thing so I'll show you and do let me know in the comment if you want a dedicated video on quick grid because this is uh we could say this is a major topic and it is Big actually there is so many things in this quick grid we have all these operations which I told sorting paging filtering and then we have in memory collections we have uh external third Party Source in our case that is database and there are a lot of things related to Quick grid we have then those property columns template columns and other things so if you want a dedicated video on quick grid do let me know in the comment I can plan a dedicated video for quick grid cool so let's use this quick grid okay and in this quick grid we will use this item provider okay so this is something different this is not that items we don't have items beforehand so this is of type grid items provider of T grid item this is going to blog post and this grid item provider if you go to this grid item provider this is a delegate uh delegate which is the return return type is grade items provider result and the parameter type is grid item provider request okay we are going to use this one so let's do this first let's create a this provider here so we'll say private quick grid uh not quick grid grid item provide right grid items provider and of type blog post blog post I'm not using dto it would be a good practice to use dto here because on this screen we are not going to display everything but still I'm using this blog post entity I'm just trying to show you how we can use this you can simply have a d of the fields which you actually need to display on this page and then you can have that mapping in your service layer okay here I'll say blog post provider provider okay then we'll go to our on initialized method and on initialized we can use on initialized only H so in here we will provide value for this blog post providers so it was delegate delicate so we can use a sync and the request this is going to be the grid item request which I just showed you grid item provider request which will be provided by this quick grid when it is making any requests to somewhere and don't this request we can have properties if we check we have start index sort by column count and all these things we can have these properties so this uh quick grid is going to invoke this Whenever there is any operation on the grid so initially it will invoke this for the first time to loads the initial data then it will uh if we are using paging sorting filtering and anything any operation we are doing on grid it will simply going to call this blog post provider method with this actual parameters at that time the request parameters so start index we are going to use paging so we'll use start index which is the actual uh start so the for the first page it will be zero and if we have a page size of 10 so when it comes for second page it will provide it as 10 then for the third page it will provide as 20 so start index is how many items we want to skip before taking the next items okay so for this what we are going to do we'll fetch the blog post we'll say paged blogs from our blog post service do get blog post a sync and in here we had that start index right so we can use request do start index and then we can use request. count as the page size okay now not question comma start index is fine but from where we are going to have this count right this is nullable if this is null we can simply we have a constant here so we'll say private constant and we could say page size and we'll have a default value let's say 10 so if this is null then we want it to use page size page size like this now we have pasted blog post result okay now what we can do from here we need to return grid item provider not grid item provider what is the result type grade item provider result so we need to return new grade item provider result this one we need to return this then it will will be that complete delegate so in this can we have something no we have some Factory method on this right grade item provider result okay so that is going to be grade item provider result do from yeah we have this from and in this it expects two parameters one is the collection of items then second is the total count so those we can get from our past block object paste block. records what is that show model page result so we have page result right a wait page result of type it is not able to figure out the type get blog post a sync page result of blog post is the type I don't know what is happening here past result okay so paste result was in models right model so this is the name space let's try to add this name space in imports. racer maybe because of name space it is not able to figure out it using page blazing blog v2. models and now we have it okay so that means it should have it now no still not okay so for this we will use dot records and then total item count it will be same page blogs dot total count all right so we have return it from here so everything looks fine now now blog item provider this looks fine on this quick grid now let's set it to this blog post provider cool we can save it now and I am now thinking we should have worked on saving the blog post first then only uh we can see some item here right okay let's do we'll do this we'll design this page we'll work on everything but we'll test it after we create that save blog post page fine so here what we need initially we will set this is loading to true and loading text to patching blog posts like this or maybe let's do this we'll do this inside this okay like this and after fetching the data we'll say is loading to false like this save everything and we are good now after this we'll add let's add one or two property only for now we'll add others when we'll reach at that point so here we'll say property column property and it will be blog post so we can say B do ID and let's add one more for title for now we'll have these two only now we need paging as well for this right so for this what we can do Blazer gives us pation state pagination state okay so we'll say vagination State and we can create instance of this with a property items per page so this is going to be this page size okay so this we are going to to use this pagination state so how we can set pagination on quick grid we can use pagination and we can provide this now this will paginate it but it will not display those uh paging controls next page previous page so in order to display that we have a paginator control which comes from Quick grid only on this we need to set state which is going to be this pagination state so now this paginator which shows that uh next previous buttons and this quick grid where items are going to display these two are going to be sync using this pagination state so I think for now on this page we'll do this much only now next thing we will work on this add new blog post page and after working on that page when we have couple of blog posts then we'll come back to this page to uh see the records and do the check if paging is working these loaders are working and then addit functionality addit blog functionality okay but before that let's try to run it and let's see if this page is rendering without any issue let's try it okay here is it manage categories is fine manage blog post and we have this thing ID title zero items and this page one of one so this section which is zero items page one of one this section comes from that paginator control and then this is this our quick grid okay cool let's work on this page so let's create that page component so for this I'm going to go to admin Pages admin folder and here I'm going to create a new razor component let's say save blog post okay let's add the URL so page at theate page and then this one cool we'll use the same component for edit a blog post as well but we'll work on that after some time first let's uh work on the fresh creating a new blog post section okay so this is also going to be render mode interactive server same thing with pre- rendering false and we need this service as well so let's use both of these so render mode interactive server with pre-rendering false and we are injecting our I blog post admin service okay okay and on this page we will need category Service as well to display the drop down of category I category service and still again intelligence not working now it will work I don't know what this is Vis studio is not in preview mode now but still they are not fixing this we the developer experience that is very bad and it is getting bad day by day I think so category service save cool now let's add the admin header so admin header with title uh we'll make this title Dynamic okay but right now let's have it as this create a new blog post do we need any button here no we don't need any button any action button so we don't need to do anything we'll just use it like this only cool now we'll have our model here so private blog post blog post from here and let's call it model only with default new Constructor and on this also let's have the same loader so these two options and this loader component okay okay now we can start creating our form okay so let's add that it is going to be our edit form with model this underscore model and we are going to use data annotation validators for this tool now what we'll do we'll add simply div class row we are going to have two column approach in First Column we'll have uh all fields of this blog post so title category AG published image all these things yeah we are going to have image as well so we'll see how we can upload image in Blazer and then on the right side we are going to have our description box right the content main content blog post content that is going to be a rich text editor and we are going to use Blazer text editor for that if you have followed my previous the first version of this blazing blog using net uh I think that waset 6 or 7 it waset 7 I guess I I don't remember completely so in that we worked with the same editor we were using Blazer server then okay so in this row what we'll do we'll have two columns two equal width columns so Dave class call sm6 and six and then in the first six we are going to have Dave class mb3 margin bottom three and in here first thing we'll have our label with class form label and this is going to be for title and then we'll have our input text here with bind value bind value oh my God bind value underscore model do title okay then we'll add couple of classes from form control control and form control SM form contrl SM and then we'll have placeholder Place holder and here we'll say let's say blog post title and then we'll have our validation message message to show the validation message here so 4ore model. title like this and we can have class of text danger so that it displays in red color Okay save it and now we can start copying this thing so let's copy it second time so title slug will automatically generate so after this let's have introduction introduction so introduction that is short introduction so introduction blog post introduction okay after that let's have it again what other thing we have we we have image and category and is published right and in is featured so all of those are different so okay after title let's use category category and validation for category and this is going to be category ID actually this is going to be input select input select bind value model do category ID classes these and there is no point of placeholder for input select here we are going to have options okay H so first option we should have a default option option value let's say zero the default option we'll say select category and then we'll Loop through all our categories so for that we need to fetch categories so I'll say private category array and we'll say categories categories with the default value and then I'm going to overwrite on initialized as sync and in this I'm going to load the categories so here I'll say AIT category service do get category a sync and now we'll have this underscore categories so here I'm going to Loop through these categories so for each we see in underscore categories and here we are going to fill out our options so option value value is going to be C do ID and the text is going to be C do name like this okay so we have title we have category we have introduction oh what have I changed okay this should be introduction I changed that one introduction introduction introduction and blog post introduction like this okay after this we'll have one day class mb3 and here we are going to have our input file and before that we'll have one label and here we'll say image or image upload maybe or upload image we'll display the uploaded image we'll work on it later but right now let's keep it like this only let's keep going Dave Dave Dave fine now we'll have Dave class same mb3 and we are going to have two check boxes one for public and one for the featured okay so here let's have label label with class form label and inside this I'm going to have input checkbox with bind value bind value _ model do is feature underscore model what is happening bind value input checkbox underscore model I don't know what is this what is happening why it is not picking up so model dot is featured okay class form check input and then here we'll say is featured or well let's say featured and question like this and we'll copy this paste this one more time and this time for is published is published so here we'll say published question mark like this okay looks fine and after that I'm going to have one more div with the same class mb3 and this time I'm going to have button submit button here so button type submit with classes BTN BTN success and here let's Okay say save okay let's see how it is looking then we'll work on the then we'll integrate that R text editor so run it and we have some error let's see what is it private component render what the issue is underscore model I block Post Service could not be found I block post admin service everything is fine model is featured input checkbox bind value error the name underscore underscore value does not exist typ or names spacecore model could not be found why it is not found it is being found in this no this blog post entities using Okay close and open this component again this time maybe it picks up no it is not going it is not picking it up blog post using this data. entities do blog post right this was this only dot come on yeah Dot if I say data dot entities dot if I use this complete line in here entities dot I can see blog post then what the issue is here blog post if I use the fully qualified name would it recognize it yes what is the issue with this what is the issue if you guys know what the issue is here do let me in know in the comment what am I missing here did I miss something blog post blog post this is complete type if I do this here blog post and what it is saying blog post it should find this I mean it is able to find category no it is not able to find category as as well okay it is not able to find category I have added using here okay let me do this I'm going to close visual studio and open it again let's see if that helps I have reopened it let's see if the if it works okay and still not maybe I am missing something which I am not able to see right now if you guys figure out what the issue is here do let me know in the comment please maybe there that's some silly mistake from my side only I don't know okay if it want us to add the fully qualified name I'll add it same for category save save okay maybe I'll figure out when we'll continue it might be my mistake only but again looks like save block post. this runtime helper create inferred event call back keyword this this array save blog post already contains a definition for what is loading loading text model category save blog post admin save blog post I have save blog post only one right save blog post already have a definition for what okay let's do this let's clean and try to rebuild okay some issue invalid code on initialized is sync protected override I syn task on initialized is think manage categories we have same thing manage blog post we have same thing and for this this is not same thing Pages admin save blog post Pages admin save blog post category service it is not going to category Service as well Leist let's try to see if you could find the type name underscore uncore private component render model attribute model do introduction oh is there some problem with introduction underscore model. introduction model do introduction if I go to this ID title slug image introduction content everything is fine we have this introduction there contrl F introduction introduction introduction this same introduction H same input text bind value okay let me try to figure it out what the issue is I'll be back I just don't know what the issue is I tried deleting bin ovj files I tried clearing cash closing Visual Studio opening it nothing is working I'm getting those same errors I tried this so this this line this was not it should have in this color right greenish color but somehow this is not not uh recognizing this interactive server render mode I tried this complete whole thing and this also gives the same thing I can navigate to it we can see this but somehow this is also throwing error that it cannot find this so now what I'm going to try I'm going to create a new component yeah then I try to check the build action for this so property build action is content I got suspicious but then I tried other as well so all were build action content so I thought maybe it works like this only build action content but why this is not working I have no idea at all so now what I'm going to do I'm going to create a new component and let's try if that works we'll copy over everything from here so create a new component and I'm saying save blog post page something like this it is here let's see okay let's start adding the things the first thing that render mode only let's add render mode render mode new interactive server render mode with and it broke pre-render false okay then let's add page so we'll get the same URL so far so good let's inject these two things okay let's use head admin header and is loading but before that let's add this section the code section okay so for this I'll add using and it is recognizing it now remove this fly qualified name okay so far so good now let's use admin header and is loading I'll remove this admin header is loading everything still fine now let's copy this edit form was this the culprit yes that means there is some missing markup or something is missing in this addit form and what is that missing okay oh my God this model do introduction we should have double quote here close this maybe this was the issue yes oh so sometimes this is uh we could say a bad to tooling it should have shown me error here or some I wasted so much time on this okay let's delete the new page we were trying to add save blog post page now it should work right we don't need this additional thing remove this remove this and let's try to run it it's here let's see login login manage blog post add new blog post and we have this blog post title and then we have this categories introduction upload image and then published and feature why this is coming always coming to this left l why do we need to add margin padding always so maybe this is how this AB St for this template has designed they have some uh weird classes or maybe they have not added the classes which are required so we'll do the same thing we'll try to move these to right using the margin left okay so on this form label we'll say ML 3 ml3 form label ml3 save and this upload image let's have d block here so that this input file moves to the second line so save and let's see how it looks now okay is featured is published no file chosen blog post title category okay all these are coming pretty good now we'll work on this right section so here what we need we need uh a rich text editor so for that what we can do let me open my GitHub repo we'll take reference of that blazing blog version one application okay so this is on my GitHub if we check in placing blog first thing we added a new get package so that is going to be in CS Pro and that was this blizard text editor let's install this solution Explorer right click on Project manage new get packages browse blazer. text editor and install apply and we got it after that what we had to do we had to add something in the main page right so that should be underscore host Pages underscore host H so we had these two CSS and these three JavaScript files right so in that project I have added the those two underscore host but right now we are going to use a different apprach approach so these Styles and these scripts these are related to this Rich text or editor only and we need this these two sections this link these two links and these three scripts only I don't know if you are able to see this now maybe you'll be able to see this so but these apply only the single page so there is no point of adding these two things for the complete app right that does not make sense what what we'll do we need to add these Styles sheets in the head section so what we can do the main first page is app. Riser here we have this Head outlet okay and if we go to our page which is this save blog post page here we can Define things inside that Head outlet so that is a kind of uh section so head Outlet is a section and we can add additional things in this head content so this is going to be applied for that particular section only so this will be rendered inside that head section only save it we need similar thing for are scripts JavaScript files right so we need to add these three javascripts so let me copy these three and we'll be come here and on app. Razer we do not have anything like this Head outlet for other things right so what we'll do instead we will create a section here section outlet with Section name and I'm going to call it scripts only so I I defined the section outlet and on this page I'm going to define the section content for that with Section name the same scripts and I'll add these here okay so now these links are going to be rendered inside head and these scripts are going to be rendered at the very end at the very bottom because we have added this section at at the very end inside body okay so we do not have any reactivity any clicking on and all those event handlers that's why we can use section because event handlers uh currently not working with sections as I showed you earlier in that when we designing our manage category page cool so after that what we did I think we directly used it this is the only setup which was required so we had that Pages admin save blog on this page right H Blazer text editor this one so let's have this Al also and this complete div class mb3 let's use this complete class no not this complete class let's use this label Blazer text editor and this is the mb3 yes yes oh my God shift does not work yeah it works contrl C and I'm going to add it in the the second call sm6 here I'll add it here for this we need to include something using Blazer text editor okay let's use this using using blard do text editor okay after that this quill HTML we need to Define this as Blazer text editor so after these categories we'll Define it private Blazer text editor quill HTML this is the reference then this should be underscore model underscore model so I think it should work now yes there is no error on this page and we are good we should be able to see this content section now okay H let's try it out so let me run it okay it's here let's go to manage blog post add new blog post and there is some error and this is not loading let's see what the error is console unhandled exception on current circuit so the circuit will be terminated and what the what the error is actual error is we are not able to see it so what we can say we can enable circuit options. detailed errors to check what the error is so let's go to solution Explorer program.cs and here where we have interactive server components we can provide circuit options to this circuit options action delegate so here we'll say options dot detailed errors true let's rerun so it is going to show us detailed error from signal R okay we are here manage blog post let me open the browser Dev tools and we have some error and if we go there we can see Microsoft J JS inter of JS exception could not find Quil functions create quill Quil functions was undefined and why this is happening in network in JS did we loaded those JS no it is not loading those JS files right what about CSS it is not loading those CSS files as well it should load those CSS and JS files so CSS placing blog main app Styles quick grid bundle this is that we have repeated Js something is not right if I go to elements head and Head outlet head content is empty and why so let's see if we are missing something section name scripts and if if we go to where is our page here is it if we check section name should be the same scripts yes so because pre rendering is false after that it is loading this this is the issue let's try it out if I remove this that means let it pre-render and there is no issue with preer rendering on this right so maybe we set pre-rendering false interactive server render mode or it should be interactive server or what is it interactive server yes it should be the this one run okay maybe this was the issue because we were using inter interactive server with pre- rendering false it was not rendering anything on the server it was coming on this page and then it was trying to load those scripts and styles using uh signal R and then adding those things dynamically to the page maybe that was the issue Let's see we still have some issue and it is same if I run it like this it works okay okay okay I got it so if I do this add new blog post this time it came what is it manage blog post add new blog post we have error use see it is not able to get this now if I refresh the page then it works why the reason is when we are let me clean it refresh this page and let me come on this page now if you check when I tap on this add new blog post it is using enhanced navigation what that mean is when I'll do this if I click on this if I go to all you see there is this this is the URL this and it is doing a fetch request that means this JavaScript fetch so it is trying to intercept this request it is trying to send an JavaScript ax request to the server to F the contents of this page and then displaying it here so using this scripts are loading but SC uh sorry styles are loading but scripts are not loading because that is not how uh the scripts work we cannot load those scripts like this if we fetch the HTML if you check if I go there response I'm going to get everything but the Styles not Styles I'm again and again calling Styles so these scripts it cannot uh re we could say it cannot execute the scripts internal scripts like this so what we need to do for this particular page we do not want enhanced navigation we want this to a complete round trip to the server so that this page gets rendered at server rendered server side rendering so for this what we can do from manage blog post page where we have this anchor tag on this we can say data enhanced nav false so using this we are saying that do not use enhanced navigation for this link do not do that fatch request when I tap on this this link just uh refresh the complete page that is what it is doing so let's try it out data enhanced now I think this is the correct data enhanced nav is the correct attribute we'll check if this is not that should be data in enhanced enhanced NV this should be enhanced NV let's try it's here we'll go here manage blog post and add new no it is not it is still doing the same thing Network all manage blog post clear everything add new blog post and is still doing that means data enhanced nav is not the correct attribute enhanced NV this is the correct one or this is not enhanced navigation Blazer data enhance enhan NV okay data enhanced n not enhanced so enhance n like this save run fingers crossed okay okay blog post add new blog post and boom it is working now if you see if you go here let me go to blog post page Network I'll remove everything and now if I do this you will see it has loaded everything and this time this new this URL this manage blog post new this was actually the document that means complete page okay now we have this this Rich Text Editor but we want this section to be a longer in height so that it takes the at least this space What left screen is taking for this what we can do we can go to where is it okay save Blog the second call sm6 and mb3 so what we can do on this call sm6 let's use display Flex okay and on this mb3 we are going to use flex grow one so this display Flex is we are setting this display flex and then we are saying for this Flex grow one that you should take the entire uh space whatever we have inside this this display Flags Okay so let's save it and let's check if something has changed or no so yes it is changed right now we have this longer brid right cool it looks fine great so this text editor is here we can apply all these things so if I want to bold it I can bold it if I want to add numbering to this bulleted list it is bled list so everything is fine now next thing let's work on this image this is the I guess last piece on this page then we'll directly work on saving the uh values okay it did not not show error on category right category must be required and that is because on category we have not validation message yes we have validation message on category ID but because this is in integer so zero is a valid value so for this what we can try we can try range variable and we can say it should start from one and and then we don't know how many categories are going to have and how many values we can have so for this we can have into. max value that that is not right but at least we'll not allow zero and then it will uh display that range attribute range related message so here we want our custom message we could say please select a valid category save it and let's rerun it it should show the validation message for this this message it should show because we are saying that it it should categories valid values are from one to the maximum integer value okay manage blog post add new blog post and if I save it please the valid category list the title field is required introduction field is required okay we good the content field is required so all these field are required okay okay now let's start working on this image so for this image first thing what we will have let's add a meod on this image where is it it is here input file file so it should have this own change okay we will let's say on or let's say handle file something like this okay handle file upload Vis Studio 2022 this version there was one feature that if we add any uh event call back without defining the message it will generate the method for us but that is not working you see I have added this method but I have not defined this method it should have worked what visual studio uh this new feature in this Visual Studio they have said but it is not working okay so we'll Define it explicitly if it is not working we are good so we'll say private void handle file upload and it should be something file changed event ARS this is the one e file changed event ARS let's see file identifier no this is not the one or this is the one input file file change it should be input file right input file changed event T and what we have here we have browser files I browser files yes this is the one file count and all these okay we are allowing only one file input file we have not added that multiple attributes so we are allowing only single file so for single file what we can get e do file is for single file right gets the supplied file note that if input accepts multiple files then instead of reading this property you should call and then it cut we should call that get multiple files so here we'll use this e do file is to get the uh file data just to read the files data basically okay so e do file so what we'll do here H let's have one variable here we'll say private private string image URL okay and we'll use this image URL to display the image here so here we'll add one more div class plus MB 3 and here we'll check if the if not string do is n or wh spacecore image URL maybe let's move this inside this only so we will not have that empty div with margin bottom three if the image is URL is n here we'll say IMG SRC equals this and we'll have some fixed let's say height of 200 PX just to check now before uploading this file we will simply try to display this file here inside this image URL IMG okay so what we can do we can say here uh we can use the base 64 image so for that we'll do using word stream equals we can get e do file do open read stream okay now we have this stream and this is of type stream only okay fine so what we'll do we'll simply copy this stream to image uh to memory so here we'll say using memory stream let's say Ms equals new memory stream and then we'll say stream let's call it image stream image stream so we'll say image stream dot copy to async this Ms memory stream okay and it should be awaited so it should be a sync task and let's add a sync suffix to this handle file upload a sync like this cool now we have this images content inside this memory stream Ms okay now what we can do we can say image URL equals now for base 64 we have a predefined format that is data column image then type of the image then semicolon base 64 and then comma and then the content of the image okay so here what we'll do we'll say data colon image slash now the type of the image we don't know so that is actually extension of the image we can see so we can get the extension so we'll say our extension equals path do get extension e do file dot name it will give us extension with DOT this period okay so we need to skip this period for this what we can do we can use dot substring or we can use this one dot dot this range operator so start from one and take everything why start from one because it will give us something like this do PNG so for extension we don't need this dot so the indexes are 0 1 2 3 so 0 is dot so we will skip this zero and we'll start from one which is PNG P okay so we'll get this PNG from here this type is this m type so here we'll say extension then semicolon after that base 64 base 64 comma and then the content of this image so for this we can get Ms Dot to array and then we need to convert this to base 64 so we'll say convert. 2 base 64 string Ms do2 array now we have this image URL save everything and let's see if we are able to uh show this image okay let's try it out okay it's here let's see manage blog post add new blog choose a file and let's select some and boom it is coming here right let's try to change it select some other image and boom so we have successfully uh previewed the image before uploading it to the server this image is not uploaded right we are just displaying it here great let's continue then so what we should do next we should save the blog post right but when we will save the blog post we will save upload this image to to our file system right we should upload this image as well so right now when we are previewing this image when we selected the image so we are not sure if we are going to save this blog post or no right so what I mean is we cannot upload this image right now we should not upload this image right now we should upload it only when we are going to save the blog post so that means at that time we should have access to to this uploaded file uh the stream actually so for this what we can do we can have one more State variable here which we can have maybe uh what is this e do file I browser file so let's say I browser file in a label we'll say file to upload like this and we'll say and _ file to upload equals e. file okay and all this is related to previewing image so let's extract a method here and we'll say private async task preview image async and let's get the same thing I browser file as a parameter here file and let's cut this complete logic add it here and use it here await preview image async and we'll pass e. file okay and here we can directly use file file file cool so now we have this file to upload we can use use this to upload the this image file to the server when we are saving the this blog post all right so let's create a method to save that blog post here we'll say private as sync task save blog post as sync okay here all the validations will be done contents validation is also going to be done right by default so here first thing we'll say we'll say is loading to true but before that we'll set loading text to saving blog post dot dot dot then we'll set is loading to true then we'll say a wait blog post service do save blog post iing and then underscore model and now we need to have access to this user ID as well now we need user ID so in order to get user ID how we can access this user ID on this page we can because this is uh interactive page here we can inject authentication State provider authentication State provider so let's call it authentication State provider so using this authentication State provider we can get access to the current user so how we can get this here we we can have access to the authentication State current H state so we can say a authentic State provider do get authentication State ising like this okay and from this Au State what we have on this Au state or state DOT user is claims principle dot get user ID and get username these are the methods we created you remember we created these extension methods so we are going to use this so cool you all state. user doget user ID this is the user ID so we can pass this user ID here like this let's extract this out in a separate method because we are going to use this for uh we are going to use this when we'll no no no this is the okay okay we don't need to use this because those uh modifying the is featured is published that is going to be on the previous page the manage blog post page so we are good we can have it like this only cool so I think we are good after doing this we can set is loading to false save everything and we should be good now but before trying to save it we should do something and that something is going to be we need to upload the image right and before that H before that we need to do one more thing so this Rich Text Editor if you see it does not directly binds to the content property right we are displaying content like this here so what we need to do we need to remove this validation message first and if you go to this content do we have something required so we should not have it like this here anyway this field is going to be required on database side because we have not added the question mark here so that this is not aable so these data annotations these are helping us to show the error message on the forms ideally what you should have you should have that required here and for saving this blog post you can have an dto and separate subset of this and there you will add you will remove this required from that particular uh D but I'm not using that just because of time because this uh video is already very very long that's why I'm not adding any extra functionality but I'm showing you you the way you can first try to build it like this then you can enhance this using those D and all those stuff okay so now when we are here before doing all this we need to validate content how can we get the content we can get quill HTML do get content uh we are not going to set this we have get HTML method we are going to use this method so here we'll say what content equals a weight will html. get HTML and now we know that this is not going to be null so we can add this exclamation mark So null for giving operator now we'll check it here so if string dot is null or empty content we should show some error message now we need to have some error message so private string error message okay now we need to display this error message so we are going to display it right before the save button okay here we'll check if not string do is null or space this underscore uh this should be underscore error message I follow this convention because these are this is basically a class these are class- based private varibles so I use this underscore convention for these so underscore error message and here we are going to have the same thing da class mb3 and then I'm going to have on pag here with class text danger to show this text in red color and we are going to display error message here cool so if there is some error in this we'll say underscore error message equals we'll say content is required something like this and we'll return from here we will not execute further cool now we have this validation after this we are saving the blog post then here we'll check if file to upload is not null then we need to upload this file okay so let's create one method here we'll say private Miss sync task we'll say save file to disk as sync like this uh sync okay and we'll get I browser file as a parameter to this and from here we are going to call that method a wait save file to ding like this and we'll provide underscore file to upload okay and this save file to disc casing it should return as one URL right because that's what we will save with the blog post right so model Dot image right so in this we should have that URL so what we'll do we will return one string from here which will be the uploaded file URL okay here we'll say uploaded file URL and then we'll simply check what am I doing not this one this should return string return this here I'll check if upload file Ur is not null then on this model set the image equals this upload file URL like this okay now we are good and now you can proceed to upload this uh to save this blog post so save everything right now and let's work on this save file to disc casing this method okay H so for this first we need to have a name so we have two approaches either we can generate some uh guid or we can use the Microsoft recommended approach so we could say uh file name or let's say generated file name something like this and we can get path. get random file name there is this method which gives us a trusted random file name random folder name or file name so let's call it random file name random file name okay okay let's get extension as well we will need extension so we could say path. get extension file. name okay now we need to have a folder where we are going to save these images so we are going to save these in this triple W root folder and in here we are going to create a folder for images and then for let's say blogs so we can create this folder manually here or we can leave this to our code only so here first we need to get access to that this folder www root folder so for this what we can do we can inject uh ieb host environment inject I web host environment let's call it web host environment and on this environment where environment we have web root path so this is the www root path okay so when we are working with paths so it's good practice to use path Ro combine okay so here we'll say this ww root path after that we want to have images and then we want to have the third part as blogs or push like this so what it will going to give us it will give us the complete project URL then ww root slash images SL post it will give us this thing okay then what we can do we can say Direct do create directory so it creates directory if they are not exist already if those are already there it will not do anything here we could say folder or maybe let's rename this to folder path now we have this folder ready now we are ready to save our this file to this uh folder now what we'll do we will get the file name complete file name path from where we can generate our URL okay because the point is the URL that is going to be from here what I mean is this www root and the complete path of this physical folder that is not going to be part of the URL what URL which we are going to display on our public page right that should be a URL and which will start from this/ images SL post so initial part will be our domain then SL images SL post and then the file name so here we'll say file name path and it is going to be path. combine so this first section this we did just to create the folder you could say these folder images and posts so images SL post slash now we need to have our file name so here we'll have random file name and on this we can add our extension because this random file name it does not give us anything uh extension it does not give us extension so we will have the same extension as we have on this file so if it is PNG it should be PNG only if it was jpg then it should be jpg only right cool so now we have file name path and now we need to have the complete full path to save this image so we'll say full path and this is going to be path. combine and this should be this web root path and then file name path okay so now we have this full path where we can save our image so in order to save it we'll simply use a using file system not file system file stream file stream FS equals new file stream with path and file mode we can use this one so path is going to be full path and the file mode is going to be open create it should be create okay now we have this file stream let's wrap this inside a TR catch H okay okay now we have this file system FS now what we can do oner file or maybe let's rename this to browser file browser file so that it because there are so many files and we are getting confused with this files name so this should be browser file browser file browser file Dot we have that open read stream it is going to give us a stream and we are going to copy this asynchronously to this FS file system and we'll update it okay and that's that's all we have uploaded our image okay cool now after uploading it we need to return our uploaded file URL and that we can get from this file name path okay but the point is this file name path actually this is going to give us something like this actual physical path but these slashes does not work in uh browser URL for URL we should have that right slashes forward slashes not backward slashes so what we can do here we can say file name path dot replace and we can replace all these to this okay now we have return this now what if there was some exception if there was some exception we need to uh we are disposing it but it's always a good idea to close this is Stream So inside this we'll first set error message to ex. message after that we'll close this file stream okay and then we should check if we have this full PA this file this file will be there or no no I think okay we are good we're returning it from here so from here we can return null if there is some error we will return null so this should return task of nullable string and it's a lot of code now we are good now we can see we can come here if upload file URL is not null we'll do this if it was null then what so let's negate this condition we'll say uploaded file URL is null if that's the case we'll simply return from here and if that's not the case we can set it model. image equals to uploaded file URL and then we can continue further it will try to save this cool so after saving we could just set this underscore file to upload to null because after uploading it we don't need to do anything and we are good I guess let's try it out and let's put break points so that we can see what is actually happening let's run it it's here let's log in login profile manage blog post add new blog post and we should add some blog post let's say um Blazer blogs okay let's use any of this copy blog title is this select category Blazer introduction let's have one sentence from here let's add an image this one is featured is published and some content so let's copy some content from here let's copy this much let's paste it here so this is this text editor it has everything and now let's try to save it when we'll save it the break point should hit and it did not the reason is we are not calling this save blog post ising from edit form and now I need to copy all those things again oh my God on valid submit call this if I save it if for reload kicks in and it gets this it will be very helpful save and it is not going to work like this okay [Music] refresh first we have body let's we don't have it let's add this here go to the the Top Copy title category and introduction we could use the first paragraph then upload some image published featured save and we still don't have so that means there is some validation [Music] error what it could be introduction everything should be fine let's try to add validation summary here validation summary save save image field is required and we have this image field but we are not setting it so that means what we should do okay so we should remove required from this image as well save and now we need to rerun it before that let me copy that this post URL copy close run it should work this time okay it came manage blog post add new blog post let's open the URL let's have the title category Blazer introduction first paragraph then content let's copy this content paste choose file featured published and save and we hit breakpoint cool let's see content we have this HTML content okay loading text saving blog post it should show that loading indicator then file upload is not null yes we have file now we'll go here random file name it gave us this some random file name extension do jpg folder path now you will see the complete folder path D Blazer and complete folder path this is physical path it will create the directory then file name path images post and then this complete name with JPG then full path this is the complete path where this image is going to be saved then we have this file stream and something happened IIT code what has changed I just don't know sometimes it just shows this let's continue it will not continue disable hot reload for now H if I do this we have this file upload is not null okay okay okay that means this file got saved we'll check it then file name do replace okay there is some exception and what that exception is continue what is the exception saving blog post we have this reload error and now everything came and what is this console we have some errors it is saying cannot insert value null into column content and which makes total sense the reason is here we should have added this content to our blog post to our model so model do content equals this content how can we enable H reload it is not debug options where is hot reload enable hot reload yes it is enabl right okay where is it would it come when I I will run it at that time let's first see if we have this image image is post and you see we have two images because we got at this place twice all right that means if we had some error why it came to this returnal this error should be in this block right so let's do this let's add a try cach block here so try catch try catch fine if we are in catch block and if the model do image or let's say now we need to have uploaded file Ur right if that was the case we should delete that file okay we'll work on that but first what we should do we should reset this is loading to false first thing and we should set the error message if it came to this section so we'll say ex. message so that we can know what the issue is okay let's try it again this time I'm not adding any break point I'm just running it because I know that saving the image that part is working okay okay it's here let's see what we have manage blog post add new blog post and we have the same URL no that was Da blogs what was that yeah this one cool we have it so let's again try it we have a title and introduction category Blazer introduction file let's add some file and then this text content it's here and featured publish save an error occurred see the inner exception we'll see what the inner exception is this is canot read property of null reading remove child cannot read property null reading remove child and what this is I I have no idea let's try to add break point after this thing okay let's try it out so I'll try to upload them oh there is some error so now this is not going to work reload and try the same thing again do we have this no this did not get saved Right add new blog post add the body the title category introduction image and featured publish save we are here what is it changes not supported always reild when changes and now it will not allow me to go further and what has changed I have no idea I did not change anything if I disable it then hot reload is not going to work it is very annoying and disable hot reload or what we can do out State user ID we have it and we have Entity framework core exception which is saying insert statement conflicted category ID what table Dev category conflict occurred in database table DBU category that means in model the category did not get saved category ID is three category ID 3 so that should be there right what is the issue then and error occurred while saving the entity changes insert statement conflicted foreign key constraint FK blog post category category the conf in database table d. categories column ID we setting the category ID correctly that's why we have this here category ID3 and we have this in the database let's check what we have in database for categories so I figured out the issue the issue is I'm just checking the migrations and in migration if you go to blog posts and here you see we have all these uh properties all these columns and at the very end we have this category ID one okay so this is the issue why this is here and this might be because this category ID we made it integer if you go to our entities we have category and we have blog post in blog post I had this category ID which is of type int but the category uh entity in that I have this ID as short and here I had this category as navigation property so what EF code did for us it automatically created generated one property for this navigation property and we already had one category ID so it created category ID 1 okay now what is happening because that category ID one that needs to be that is uh that's not an optional field so it needs value for that and that we did not provide because we provided value for category ID so that's the issue so and using this we should always go through our migrations it proves this okay so now how can we fix this we can simply go to our blog post entity and we can change this int to short so now it will know that this category ID belongs to this category navigation property okay we made this change now we need to add migration for this change so for this package manager console and here I'll say add migration and change category ID in blog post something like this blog post change C ID to short the name is up to you you can name it whatever you want this name does not matter the contents of this name this class file uh those matters actually let it build build succeeded now it will going to generate one migration for us and let's see what it generated for us so it is dropping foreign Keys dropping index on this category ID 1 category ID 1 category dropping column category ID 1 and then it is altering the column category ID now it made it small int old type was int now the new type is small int right and then it is creating in new index and new foreign key for this category ID uh column right so we are good now we can run this we don't need to run this database migration explicitly because we have our seed service in which we migrate our changes automatically right so we don't need to manually if you want to you can simply write update database from here and that will work okay so that means now it should work let's try if we are able to save the blog post finally it's here let's log in go here manage blog post add new blog post and let's open the same thing what was that Blazer blog right Blazer blog okay let's open it let's open any of [Music] this I don't know this one let's add these block title category Blazer although this is not Blazer this is asp.net core okay let's use asp.net core then some description so let's have this line as description that introduction sorry not description then image and then the content so let's get this much paste it featured published and let's save it we are here continue disable hot reload continue and again some error let's see what is it this time console H what is it okay let's try it one more time we already have that break point and it is not going to hit that let's copy this URL we'll check it again run let it run and I'll uh yeah it is here let's see manage blog post and we have it okay it was saved but they after that there was some issue okay let's do this let's open some other let's create one more and then we'll see what the issue is here okay copied this is the title category do we have Maui no we don't have let's add it in C right for now introduction and then the content edit choose this choose file and save we are [Music] here okay duplicate title no it is not Slug It generated the correct slug late time everything is fine okay okay huh everything is fine after this there some issue no it ran right after saving there is some so this is some Blazer side issue after saving everything save blog post async it got saved we set is loading to false file to upload null we have this thing ready do we have something here mhm cannot read properties of null reading remove child in work update components circuit host I don't know what the issue is here maybe I can investigate it later for now what we can do after saving this if everything was fine we don't need to set is loading to false we can simply navigate to the previous page so we can inject our navigation manager let's go to the top and inject navigation manager navigation manager and we can use this navigation manager to navigate to the manage blog post page so navigation manager dot navigate to and here we'll say admin admin SL manage blog post save everything and let's try it out we should see two items on that page manage blog post we have these two items add new blog post uh view JS blog something the Viewpoint this is the title categories view this is the introduction then the content and then choose file sorry featured publish save continue disable continue and we still have some issue there is some issue for sure let me try to debug it and let me try find out what the issue is all right so what I found is somehow when we are navigating from this page back to the manage blog post page so uh there is some additional rendering happening and that is somehow breaking the state on server and client because we are using Blazer server uh interactive server mode so it keeps a we could say copy of the same UI on server and on client so there is some mismatch happening in between so uh what I found is if we somehow add some delay here then it works so I have added 1 second of delay I know this is uh not the correct solution but this is working so I'm adding it adding it here I will try to still uh maybe in future we found something then maybe I can create a followup video for this or if you guys know about this anything related to this thing do let me know in the comment okay now if I run this and I log in go to manage blog post add new blog post let me add one more I'm adding some random text only then choose a image any image and let's save it and it works using this so we'll continue with this right now we'll see if we could find something related to that delay but that is working okay so I think we are good with this now we can work on this manage block post first and after that we'll work on the this screen again for edit case so we'll implement the editing and existing blog post functionality but before that let's work on this yeah and I added this go back button so this is nothing this is just a nav link pointing to the manage blog post page so I have added it in action buttons for our admin header so it is just a nav link with admin SL manage blog post so that we can go back to the manage blog post page cool so let's work on this screen and our loader okay let's let's let's try to work on this screen okay so let's start working on manage blog post page where is that manage blog post let me pin these two pages we are working on these two pages and let me close all others so close all but pin okay then here we have this quick let's start adding uh other columns okay so after this title we'll add our category so we'll say category category name actually we don't want to display category ID there's no point of displaying that so we'll show category name and now this category is actually uh navigation property so what we should do let's stop it we are accessing this name directly so we need to eagerly load category for this so let's do this let's go here if we have that already no not here in our manage blog post service so when we are get blog post ising right this is the one okay we are already including category okay that's fine okay after category what what else we can get we can get uh image now for image uh this should be a templated column right template column because we need to display the image in imgsrc tag so we'll use template column in here let's have IMG SRC equals we are going to have context do image like this and let's have a fixed height style height 200 PX like this okay and after that for each published and is featured we are going to use the similar approach we had on manage categories page so we are going to have uh check boxes here and we will allow user to manage these checkboxes directly from this grid the same way we are doing this on category for show on NE so I'm just copying this show NE we'll modify this the text and uh the value inside it so this should be let's say is featured or well we'll say just featured context dot is featured and let's create methods for these so we'll say handle feature change like this like this let's create this method so here we'll say private I sync task handle feature changed and it will expect a blog post Okay cool so I'm going to copy the same thing one more time for published field published flag so this is going to be published published and we'll check is published and this should be publish change right so let me copy this method again and here we'll say handle published change published change handle publish change handle publish change cool save and now after this what I'll do we'll have that edit link as well okay so we can use the same thing what we had on manage category with template column without any title we'll simply have this but this time we cannot have button we are not going to have button because we are going to navigate this user to to the new screen next screen what we'll do here we'll say a the anchor tag HF this is going to be admin SL manage blog posts slash now right now this save blog post this just uses uh new blog post right this is right now not compatible with editing a post but let's make it compatible with that so we'll add one more page attribute on this save blog post and here we'll say admin SL manage blog post SL we'll say addit and then we'll add one more this is going to be ID okay the label int this is blog post ID so when we have this ID we need to add it in our code section so here we'll say public nullable in ID with get and set and this should be a parameter parameter like this save and we are good so here after manage blog post we need to add this edit and then blog post ID which we can get from Context do ID like this okay after that we have class and we don't need this uh on click and we'll have this addit now same thing we need to add this data enhance nav to false because we don't want enhan navigation for this so here we'll add data enhance NV equals false I think we are good with this page now let's see and before that let's add couple of bootst classes to this table so here we'll use the same classes table table bordered table striped and table hovered save everything and let's run it and let's see how it looks okay it's here let's try it out manage blog post and it is looking good but did you notice when I moved there it took some time initially and there was no loader so loader was not getting shown we need to fix that and now we can have we already have paging setup right 19 items are total in there we are displaying some of items then if I go to next page we are on page two and we can see the items from 13 5 to 13 right if I go back we can see 25 to 14 that means this paging is working and we can see this yes no featured and uh published Flags so these should also work fine M I think we are good we just need to fix this UI a bit more this is not looking that good so let's uh we are not displaying slug here right we should display the slug for published uh items for published blog posts and then this image let's do this title image and uh the slug URL let's have all these three in a single column and then this name should be category or category name and yeah these two things let's fix these so first for this category we'll say title category and then this template column we are going to modify this so for this let's have a div with class some padding py2 okay inside this I'm going to have my image and this is very big so we need to make it small so I'll have it 60 PX height and 60 PX width a small image and object fit cover so that it uh fits in that section so that we don't lose that aspect ratio and it looks good it uh should not look that stretched out something like that so object with cover after image we'll have a title and slug okay so here I'm going to have Dave okay so on this py2 let's add some Styles so first I'll have display grid what I need is in First Column I need to have my image and in the second column I need to have my uh title and uh slug sorry so display grid and then we'll set grid template column the first one is image so we'll have 60px then let's have Auto for the second column and then we are going to have some grid column Gap let's have 5 PX okay it's enough I guess okay so First Column we are going to have this then second column in this I'm first going to have a label label for uh title so we'll have context do title this context is provided by quick grid this is the blog post so here I'll remove the default margin bottom on label added by bootstrap okay and let's have d block display block so that it fits in single line uh not single line it takes the block and the next item should should start from the next line not from directly appended with this okay after that I'm going to check if context do is published is true if this particular blog post is published if this is published then I'm going to add an anchor tag here with HF for The Details page okay and I'm going to add Target to blank so that it opens in a new tab and we have our admin section intact and here I'm going to display slug directly okay now if this blog post is not published then we are not going to have any public URL for this so here I'll simply display the context slug inside this label only inside a t label context. Slug and and I think we are good then we can remove this title from here and let's move category after this okay okay let's see how it looks save and it is looking like this let's move everything to the center of the uh these cells vertically vertically Center okay so for this there's no class directly but we can add the explicit styling to this so what we'll do let's have a style block here so style t type text CSS and here we'll say table class which is this current Table we are providing this so inside this table we'll move to T body and after T body we'll move to tr and after TR we'll move to TD okay so on this CD we are going to set vertical align to Middle yeah this is Middle not Center horizontally it is Center but vertically it is middle so save it and let's see if it fixes this yes okay so I think we are good we can increase this spacing if we want let's increase this so on this grid column Gap let's make it 10 pixel okay so this is published that's why we have this and on this one this is not published so we have this uh without link go to we are on second page let's go to first page and all these are not published so we are good that means this thing is working uh the only thing is that loader is not working on this screen right so let's fix that first first let's see what I mean is because there should have been loader right so here I'm going to add and delay so that we can see that something is happening let's add a 1.5 seconds of delay okay and let's rerun the app it's here let's go to manage block post so you see there's no loader and after that it the data comes so that is why when we are pro when we provided this blog post provider this delegate so we could say this is uh executing out of this current components context so we added these but somehow Blazer was not able to figure out that something has changed but we have changed this is loading and loading text so what we need to do we need to explicitly tell Blazer that something has changed state has changed so you need to reender this component to show the loaders okay this I can uh show you we can verify after showing this loader we have this data and after that we set this is loading to false right so let's try it out I'm restarting the app it's here manage blog post we can see fetching blog post we have this but you see this did not get removed from the UI that's because we said that is loading is false but it is not able to figure out that something has changed so we need to explicitly tell Blazer that we modified some state so you need to rerender this this current component so using state has changed now it will work and then I figured out that this three dots do we have these already as a part of loader that's why I was saying multiple dots yes okay so let's remove these dots these will be added from there only here also we should have those three dots let's remove these manage block post so on manage category also we must have this yeah remove this okay so manage block post let's try it one more time this time we should have and let's uh decrease the page side instead of 10 let's have it five save everything and run let's try it out manage blog post we can see the loader and after that this is gone and if you go to the second page we see that loader right so that means the loader is working patching data is working paging is working everything is good now let's first remove this additional delay so that it comes quickly so save everything and let's rerun start it's here manage blog post you saw that so this is very fast but we can see that loader quickly right okay cool now let's work on these published features these checking unchecking first after that we'll work on this edit right now nothing is happening because we have not added any logic to these right so let's go and add these so now we have this blog post here so this is handle feature change right so we'll say blog post do is featured equals not blog post. is featur so we'll do simply the opposite of this okay and after that let's do this let's create one more method here private a sync task and we'll say save changes a sync something like this and we'll get blog post as a parameter here what we'll do we'll first set these two things and this should be in reverse order so first set loading text so we'll say saving changes then is loading to true then we'll call await and uh blog post service right blog post service do save blog post I thinkc and we'll provide this blog post and we need user ID for this so we'll do the same thing we are doing on Save blog post so let's inject authentication State provider and then use the same logic this logic to fast the user ID oh let's okay let's have it here now we have this user ID so after blog post we'll provide user ID as well okay and after that we'll set is loading to false again okay now from this handle feature changed we'll set AG feature then we'll simply call Save changes sync with this current blog post cool let's do the similar thing for published so blog. is featured instead of is featured we'll say is published AG published we'll do the opposite of age published and then we'll save changes and is that published uh published at did we handle that already Yes we handled already right if the current is published and previous was not published then we'll add this UTC now Okay cool so looks like this is also fine let's let's try it out so let me stop everything save everything and let's run it so this functionality should work checking and unchecking of featured and published okay it's here manage blog post and let's make it featured let's make it published you see right now this is not published so this is label and if I make it published then this got changed to link that means things are working now let's Let me refresh the page so that we can see that these changes are persisted so 25 ID 25 aset core category and we made these featured and published both true let's refresh the page and we see this that means this functionality is also working cool first time it did not does not work but after that it works this works fine this works fine this is also working this is also working what was that maybe I misclicked no this is working okay maybe something different happened but yeah right now the things are working we are good with this now we'll work on this add it right now if I click on it it will go to this same page the save blog now this has create a new blog post this should change to edit and then we should prepopulate all these fields because we are editing this blog post which has ID of 25 which we can see in the URL okay so we are going to work on this now let me close this stop all right so we are on this save blog post page now we have this ID we need to we have this ID we need to populate the blog post details from database if we have this ID that means if we are in edit mode okay so in on initialize Asing after fetching the categories we could check if ID do has value okay and this ID is actually greater than zero if that's the case we'll uh patch the blog post so here we'll say blog post equals a waight blog post service do get blog post by ID a sync and id. value now we have this blog post here to be on safer side we can check if this blog post is null if this is null we'll simply return back to the the manage blog post page so navigation manager. naate to admin SL manage blog post page and we can set the replace flag to true because we know this URL is invalid so we don't want this URL to be in the browsing history so we'll replace it directly and after that we'll simply set return we don't want it to execute further cool now this was not null that means we had our blog post so in that case what we'll do we'll simply say model equals this blog post okay and this image URL which we are actually displaying in edit form we will set this to blog post. image so that we display the image when we are editing some uh blog post all right now everything is fine this looks this looks fine let's try it out at least we'll be able to uh populate the details of existing blog post let's write out okay it's here login manage blog post and let's try to edit the first one and you see we have title we have category image featured published everything cool let's go back and let's try one more and we got everything right that means the editing the fetching of data on edit screen yeah I I cleaned up the that raw data which I add did when I was testing the those errors right so right now we have the actual articles these are also sample but yeah these articles we have these let's write out some which is let's say this is not published okay now if I edited it is not published but it is featured right now if I remove this featured from here and save it so right now this is not featured and not published so that means everything is working fine cool now let's go to edit and let's try to work on this section now saving will work but handling this image that should change right now why because if we go to the save blog post here what we are doing first thing we check if file to upload is not null in this case it will be null because we have not changed any file it was default and upload file URL because this is not going to execute we'll simply skip it model. image is nothing and everything will work fine file to upload will set it to null which is already null so this is fine the problem would arrive when we try to change this file okay so if we change this file what I mean is if I choose some other file okay and then I save then what would happen it will come to this save blog post isnc and then file to upload will not be null we will it will come here it will upload this new file it will set this new file UR and everything will work fine but we will have that existing image in the physical location right that image will be there on the disk we need to delete that image right because now that image does not exist so there is no point of having that image here so for that what we can do we can have uh let's say [Music] one we should have some state for that so we'll say let's say the way we have file to upload the same way we will have private string and we'll say image URL to delete something like this okay and now when we are uploading a image okay when we say handle file upload Asing here what we'll do we will check and how we should check let me think so here what we'll do we will first check if model do ID is greater than zero first thing that means we are in edit mode and if we are in edit mode and we try to do this thing H then we should check if this thing image to delete is null if this is null that means this is the first time this is the first time we are uh changing the image changing the image if that's the case then we should do this image URL not image URL image URL to delete we should set this image UR to delete from model. image like this H should we have it here or should we have it in here when we are saying that file to upload is not null then come here and upload that image and do this H I think we should have that here right save blog post tasing when we are actually uploading the new image and the uploading of New Image was done then I think we should have this logic let's cut this logic from here I'm just trying to think where it would make more sense so I have it here model ID is greater than zero edit mode image URL to delete image URL to delete is n there's no point of having it like this now so what we should check if model. ID is greater than zero and not string dot is null or wh space the model. image that means this is edit case and we already had some image in model do image and we are uploading a new image yes yes if that's the case let's add this image URL to delete add it here so this means we don't have to have it outside we can have it inside this only say blog post sync we can have it here okay H why I have it here I will delete this image when the save blog post was successful I'm going to have that logic here here I'll check if the image URL to delete is not null this means we changed the image for this existing blog post so let's remove the existing image from physical location okay image you to delete is not null unassigned yes let's set it H so now we are going to remove this and we should have it inside Tri cat we can skip this exception and here we'll say file dot delete this image to URL image URL to delete but now the point comes we should have the complete physical URL the way we are doing this in save file to dis casing right this complete directory path and this complete path we should have all these things here so it's better to extract a new method here we'll say private void delete existing image and here we'll get the image URL okay let's make it nullable we can have that condition here no let's let's do this in here we know this image URL is just this file name path and file name path is/ images SL post and then slash image name so this initial path this web host environment web root path this does not exist inside this right so what we need to do first thing we need to get the image path word image path equals from this image URL if you remember to make it URL we replaced backward slash to forward slash and to make it a path from URL we'll do the opposite and what is the opposite so we'll say here image URL do replace replace this slash to this slash okay now we have image path after that we'll get the complete folder path or maybe we can say full path like this so we'll say full path path. combine web root path and then this image path now this full path is the complete image path which we need to delete okay now we'll add a try catch here and we'll say file do delete delete this full path and for catch we are not concerned if this image did not get deleted we are okay with this save and we are good let's use this delete existing delete existing image method so inside this here we'll say this delete existing image and we will pass this image URL to delete like this now we should be good H let's try it out okay it's here let's go to manage blog post and let's modify the first one only add it and we have this image let's let's first do this announcing view3 updated okay I updated this title okay so let's save it and we see updated and we can see the same image that means this thing is working now let's try to change this image so choose file and now this time let's have this this image okay save it and we can see this updated image that means this thing is also working so addit blog post is also working so we are good all right so we have worked on manage categories manage blog post now for manage subscribers we need to have the list of the people who have subscribed to our blog post blogs this are application so for this we need to First work on the UI because when I say UI the public UI public facing the homepage category blog post blog uh blog post detail page for all those pages there I'll be having this subscribe box right so we'll work on the public Pages first after that we'll come back to this manage subscribers so we have achieved a lot let's continue with the public facing uh URLs before that let's fix the title of this page so it always says create a new blog post but that is not correct right so let's modify it so here I'm going to add a condition which will be if ID do has value and ID is greater than zero then we'll say update update update blog post if that's not the case we'll say create a new blog post like this so save it and we are good now okay now let's go to the public Pages now for public Pages we need to have one service right this blog post admin service this is just for admin so let's create that service first so add new class and we'll call it blog post service just blog post service okay and here we'll see what all uh methods we need so let's first check the template did I deleted these files maybe okay let's get this from our template and first let's see index index these 1 2 3 4 5 these first five blog posts these are featured blog post and without category basically so category does not matter just featured blog post after that we have popular blog post which are going to be uh order by descending view count of the blog post then we have this all story so here we are going to use latest or recent blog post okay so on home we need to have three uh Services three uh type of blog post featured popular and recent so let's create these three methods first so here I'll say public async task blog post post array and get featured blog post a sync okay after that I'm going to have let's copy this for two more times so after that I'm going to have get popular blog post the sync and then get recent or latest recent blog post okay and all of these three are going to have a count so how many posts we want from each category when I say category this category this featured popular recent count and end count okay okay okay let's open the template these are for homepage after after that if we go to category page this is detail page this is category page so we have this one featured so this is by category because this should be from this category only and on homepage we had featured uh without any category then we have popular and again this needs category ID and then latest so top top and from this category okay so that means for this page we can reuse all those methods by just adding an optional category ID category ID if we have provided category ID then it will be category page and if we have not provided category ID then these are going to be on homepage okay okay after that let's see what else we have so this is the detail page on detail page we need to have one by detail when I say detail means the blog post details and at the very bottom we have read next which are going to be uh we could say when we say you may like these uh blog post so these are going to be related to this current uh blog post that means these are going to be related to the current category ID we would say this whatever category this blog post FS into we will get five random uh blog post from that category only okay so for this we don't have to make any uh should we yes we should let's do this first we'll say public a sync task of blog post get blog post but this should be by slug because on detail page we are going to have slug not ID so here we'll say string Slug and after that we are going to have public sync task and we'll say blog post aray and this is going to be we'll say get uh uh related blog post sing something like this okay and we are going to have spring slug or how should we approach this instead of getting this from two different uh methods let's do this let's create one model and from which we'll return return both the details of this blog post and a list of related blog posts so let's go to our models and here let's say we will have one more record which is going to public record and here we'll say detail page model something like this blog details model detail page model okay and here we'll say blog post which is going to be blog post and uh blog post array where we'll say related post something like this okay let's use this in here so here we'll say detail page model cool save everything and I think we are good four uh methods as well what I can think right now let's go with the flow so let's Implement these the first thing we need to inject our DB context and we are using DB context Factory so DB context Factory application DB context application DB context it should be context Factory and we are going to use the similar approach we have been using for other services so we'll have a private a sync task of T result with let's say query on Conta text a sync with t result and here we are going to have one fun of task of T result and this fun would accept a application DB context context right okay cool so let's say query and here we'll say uh using your context equals context Factory dot create DB context and then we could say return a wait query context okay and let's use this let's use this so for feature blog post what we are going to do first thing we'll say return await query on DB context asnc quer context asnc and here we are going to get our context and then we'll add our Logic on this context okay so here first we would generate our query so we'll say construct our query so here we'll say query context dot blog course dot has no tracking we don't want to track any change here after that we'll say we need to have category and user both because we are displaying username and category name both so let's include both of those so we'll say say include then again include blog post b. user ID not user ID it should be user and this should be category cool now we'll check if we provided category ID or no category ID if category ID is greater than zero in that case let's modify this query so we'll say query equals quy dot where category ID I mean b goes to B do category ID equals equals this category ID okay and before everything we'll have a default condition which is going to be where B do is published is true okay because public Pages we will display blog post which are published only cool now we have it here now we need to return feature okay so with this is published we can add one more condition which will be his features cool now we have it so from here we are going to return our query dot now featured uh we can order by these by gu ID we want we want to randomize this okay what is the issue here and after this we need to take discount so we'll say take two array like this and we are good with this method oh sorry this should be a sync with a we like this and we are good with this method cool so we can copy this and let's go to popular and on popular we will remove this featured condition and this order by we would make it order by descending and we will will need b. view count okay so popular by view count great and after that recent blog post so we don't need featured this one we would say order by descending and we would say publish that so we we will say B goes to b. publish that and although publish St is nullable but we are sure that it will always have a value because we have this is published true this check we already have it okay cool now let's go to the final method which is this details so for this first we need to have our blog post so we'll say blog post equals a wait context. blockpost do as no tracking do include and we'll include both B do category and then we'll include B dot user and I'm going to break this to multiple lines include then we'll add our we condition or we could use P default asnc and here we'll say B do slug should be this slug okay okay remove this remove this now we are good we have this blog post and now we can get the related posts related to this for related post we could say uh context do block post dot dot as no tracking and same thing we'll include both of these let me move it to different lines okay okay and after this including we'll say order by we will randomize this but before that let let's add the condition of category ID condition so here we'll say where B do category ID equals blog post. category ID okay and after that we'll say order by and we'll make it randomized so we'll say gu id. new gu ID and then we are going to get we'll take how many we need four as per our UI design we need four and from here we can return new detail page model with blog post and related post after take we'll say do two array async and we'll add a weight here and we are good with this now okay now there is only one thing which we can fix so this blog post what if the slug was incorrect okay or okay and we missed one condition from both of these places yes we should add that condition that is going to be where B dot is published we'll take only published ones we can add here let me say B do category is this and B do is published we could move this condition to this is published as well so here we'll say slug and is published like this save so here if we could not find blog post in that case we will return return an empty model so for that we can what we can do we can simply come come here and we can create an Factory method here so we'll say public static and the same type and we'll say empty and this should be new Details page and we'll say default and empty like this now we can remove this we can say like this H okay and then maybe we can have one Boolean property here is empty this is just for R is so here we'll say if blog post is null which is default if this is null we will say it is empty okay let's use this so if that's the case here we'll check if blog post is null then we'll say return detail page model. mty with our methods great let's extract the interface for this we'll add to this current file only and let's register this interface in program.cs where we have all our services we'll inject this the same add transient add this add this like this I blost service we have registered it okay save everything and now we can go to our pages and we can start in injecting this service and fetching the data okay so let's go to our homepage first so Pages homepage okay and here first thing we'll inject our inject I blog post service we'll call it blog post service only page title we should fix page title for all pages okay we'll do this block service now let's add code section here and here we need to have three set of data right so we'll have private blog post array first first we will have featured with default value as blank array then we will have popular then we'll have recent okay then let's override on initialize the sync method override sync task on initialized a sync and we'll fetch these three data so these three set of data these do not depend on each other so instead of making synchronous calls three synchronous calls we will patch these three parallely for this what we'll do we'll say our post equals we'll say a task do when all okay then we'll say first blog post service. get featured blog post I think okay we need five then second we need popular which we need four as per our UI and then get recent again five okay now this post this is going to be an array of array with these three items so here what we can do we can have featured equals post Z okay and then popular post one and recent posts two like this now we have all these three set of data okay now we can use this data to display actual records for all these right so for blog post list featured blog post popular blog post we need to pass these data to these components but right now these components do not have that logic right so first let's fix these components so these are going to get properties of type blog post array okay let's call it posts only post and this is going to be parameter with editor required because this component needs to have this post assigned let's have a default value of blank array and now we can use this so let's see what we have here we have a row we have call lg6 call lg6 and in first call lg6 we have first item and then second col L6 we have D class mb3 mb3 mb3 okay so these three are three separate posts and then this one this is a separate post so we have these four posts so for this first one because we cannot add it inside a loop what we can do H H let's do this we have a blog post H let's have this let's have a variable here or no no not variable let's do this let's have a private blog post and we'll say first blog post okay default value this default then we'll use override on initialized and inside this we will set this first this should be underscore first underscore first equals post okay we'll check here if post dot length is greater than one or let's say greater than zero then only we will set the first from post. first like this I I have done this just so that we can directly use this here and this complete thing everything we are going to wrap it inside a condition where we say if post do length is greater than zero then only display all of this then this first call LG 6 this is going to be the first property so here first thing background image so let's have our background image this is going to be at theore first underscore first. image then this is going to be the title so we'll say underscore first. title then this is going to be introduction so first do introduction then here we are going to have the when it was published then how much time it will need uh to be read so for this we can skip this section for our particular case so what we can do just remove this and we will simply display when it was published so here we'll say first do published at now this thing we will need it at a lot of places so it's better to create a extension method for this so here what we'll do we'll say public static the string and we'll say to display something like this and here we'll say this date time this is going to be the label date time date time okay here we'll say date time dot two string and as for the design it was mmm DD and if this was this is not the case we'll simply return string. Mt now we can use this directly here so first display uh published at do2 display like this okay this is author name so here we'll say at theate first. user.name and we are not going to have this as a anchor tag so so we can directly have this text without anchor T like this everything is fine I guess yeah this one is okay let's work on this second section here we have these three items one two three so we can Loop through these items right so we'll say for each here we'll say word Post in posts or let's say b b is for blog and copy first one let's add it here first we will have image so here we could say B do image then we have this detail sorry title so B do title then this is the author name so we'll say B do user.name in LoveIt this is going to be category so here uh we should have an anchor tag for our category so we'll say HF whatever category URL we are going to have We'll add this and then we'll say B do category do name and then this is the same published at so here we'll say B do published at do2 display and then we can remove this now what we need to do first blog post we have shown in the first whole lg6 and here we should skip that first one so here what we'll say we'll say post do skip one so just skip the first one and then look through okay so I guess we are good with this one so so this is featured and it needs at least four blog post for our design so if I go to our homepage featured we got five let's fetch four only Okay cool so Fe blog post list this is now complaining about post property so we'll add it post and here we can pass our featured cool now comes this popular uh before that in featured we added this okay we cleaned this up right yes we cleaned it up cool now let's copy this post parameter go to the popular blog posts so inside this also we are going to have the same parameter and here we don't need to get that first out of here because this is simple o i just a list okay so we'll remove all just have one and here we are going to add our 4 each Loop post and then we could cut this add this Alli here and then we'll fix it so this is the title so B do title then this is B do user.name and then this is going to be category same a HF category and this is going to be B do category Dot name cool so let's go to homepage again we need to provide post for this as well so this is going to be popular then comes this blog post list this one let's fix this as well blog post list this one so here again we are going to have the same post list this and we'll same look through the records and we'll design uh display this so for each word be in post let's cut one of it add it here remove these two and let's make it Dynamic so first thing this is b. title then this is Introduction so B do introduction then this thing is the same category and author so let's copy it from here okay then this is the time so we'll say b. published at do2 display and then last one this is image at theate b. image cool save it and go to our homepage this is going to be post and here we are going to pass a recent post list cool so so far so good there is only one okay no no no what is this this is the main first okay this is going to be the first featured yeah this is the first featured item mhm okay so let's do this that means this featured we need to have five only four we will need that internal uh list but one we'll have here so here we'll do that similar thing first feature where is it featured blog post so this like this right so we will do the same thing on our homepage we will have one field here where we'll say first picted okay and here we'll say first featured equals underscore featured of zero the first one and then what we should do we should say featured equals underscore featured dot skip skip one and then two array so we simply skipped the this first item from this feature list which we passed to this featured blog post okay so now we have this underscore first feature we can use it here so before displaying this thing we will check if this feature is not null then only show this thing okay now let's bind it up so first thing this is the title at theate first feature. title this is description uh what I mean introduction so first featured do introduction then this is going to be detail page this is fine and image so here we'll say first featured do image we can remove these things from here and let's run it right or maybe before that okay before that for this underscore featured this featured get featured blog post so we need to have five it items so that our design that does not get distorted right because we need at least these five featured blog post but what if we don't have five what if we don't have any what if we don't have any or what if we just have one so then this section is going to be freak out so what we can do we are saying featured but we did not show anything that this should be featured so what we can do let's go to the get featured blog post and from here where is this get featured blog post we have count right so before returning it let's have this we'll say records let's check if we have these much of Records so here we'll say if the count is greater than records. count record length if that's the case that means we do not have five featured uh articles in this particular case right so here what we can do huh we can fetch the additional items let's say we got only two records here so we need three more so we will got get those three more from our blog post randomly okay so here what we can say additional records like this and here we'll say a wait query dot now what we should do we should remove this is featured from here because we don't want to repeat the same block post right so let's do this let's cut this each feature from here add it here query do where B goes to B do is featured orderby okay then just copy this section and here what we'll do we'll say where B do is featured negation of this so that we skip the records we which we already have in this record section so we'll skip those then again we are going to order by randomly then this time we will not take count we will take count minus record. length so whatever remaining items we have in this case it will return us three so we will have three items and then two aray Asing okay and now from from here we can modify this records to records and merge this additional records to this like this and then at the very bottom we can simply return these records so if you already got five then it will not do anything and it will directly return return the result okay so I think we are good now cool so now this design will always be perfect let's try it out let's run it and we have some errors it says null reference exception underscore first was null okay so what if post do length is greater than zero then the first should be there but it is not okay let's do this let's add a break point here continue I want to see what which case is this run do length is zero so is it initial case when post do length is zero maybe this is before the this parameter got set right okay so let's do this instead of setting it here we will overwrite other meod override on parameter set we will override this one okay and we'll move this condition to this method so now we will have it guaranteed do we have this condition in any other component no no okay let's run it on initialized execute first and then on parameter set gets executed and boom cool it looks nice okay this article we have have added this blog post we have image we have this title introduction and if we move we have these other name is correctly picked up everything is fine dates and name category which has a link all stories popular we have these four popular items then we have these recent items 1 2 3 4 5 and let's change this all stories to recent and on this page everything looking fine right everything looking great cool close this fix this all stories change this to recent and then we'll work on the category page so on homepage where is our homepage is here all story ined of this we'll say latest post like this okay now we can work on our category post so the URL for this we are going to have uh maybe something um first we'll get the dynamic section from slug something like let's make it Dynamic so we'll say category slug hyphen posts so if it's it's Blazer it will say Blazer hyphen post if it is asp.net core it will say ASP net ASP hyphen net hyphen core hyphen post like this okay so for this category slug let's have a parameter here so we'll have a string category slug this is going to be a parameter okay then we are going to have a list of posts so blog post array blog post uh no we need to have multiple first we have featured then we have latest then we have popular same three set of data actually so same like home let's copy this complete thing and come here and paste it like this okay let's inject our block Post Service go to the very top inject it and we have this so here first we need to get the category from this category slug right so in uninitialized but before that first feature we don't need this first feature different for this one here what we'll have we'll have an object for our category so we'll say private category uncore category okay then we'll fetch this category first before anything else so here we'll say category of weight and we need category service let's do this I category service we'll call it category service okay category service and we'll say AIT category service. get category by slug async here we'll say category slug like this what is the issue it could be null so okay let's handle this case as well so we'll say our category if category is null we are going to return from here so for that let's inject navigation manager at theate inject navigation manager navigation manager and we'll directly return to the homepage navigation manager. navigate to slash and we'll replace this URL because this URL is incorrect invalid so we'll say replace true and then we'll return from here we don't want to execute further cool now here if we came here we know that category is not n so so we will say category equals to this category okay now for get featured we'll say comma underscore category. ID we need category ID right for on this page we just need one we don't need more popular we can get maybe four or five items four is fine with category ID then recent again we need category ID save everything and now we are good first thing what we'll do we need to display this category name here okay so we'll say category do name then this one is featured blog post list this this is latest so let's bind these up first so pass recent which is latest and this is popular so pass popular _ popular like this and this same category name we need here popular in this category name cool now this one is featured let's fix this so this feature let's have it single only because this is going to be single it shouldn't be a label so here we'll say post zero DOT first uncore feature or we could say first first. default if we really want to handle everything so let's make it n lab in that case let's use this so for this section first section call md8 md5 this one right so for this what we can do we will add a condition if the feature is not null then only we are going to render this dat okay so let's add these things first image so underscore featured slash uh sorry do image then we have this title uncore featured. title then we have introduction feature do introduction then we have author name so featured. user.name and then the published at feature. published at. to display cool save everything and this page should also work fine now let's remove this and Main and this main HTML commands save everything and I think we should be good now so let's fix the URLs first okay let's go to homepage and we'll start fixing the URLs we need this Dynamic URL category slug hyph post let's go to home and let's check where we have read Moree this is going to be detail page we will skip it and on home we don't have anything let's go to these uh shared components so blog post list here we have this category right so let's add that URL here here we'll say category slug for category slug we can get it from B do category. slug then hyphen post and on this anchor tag let's add title so it makes sense so we'll say B do category dot name post okay and this is going to be detail page we'll fix it later let's copy this uh this HF and title let's copy both feature blog post here also we are going to have the same thing user display we don't have category in this section but we have category in here so let's use that same thing here cool let's go to this popular blog post list we have category here like this and then we have category on our layout right so let's go to our layout top NE here here we have these categories which is the C so let's use this so here instead of B do category we'll use c b do category we'll use c c do name and I think we are good with this now okay great save everything run it's here let's see what we have these links category links and it is working in aspnet core we have one featured popular items then we have latest for SQL Server we don't have any so all these sections are empty view we have two popular one featured two latest razor Pages we don't have anything C we have item so that means the category page is also working fine we can move from here as well go back T and everything is working great right category page is also done now let's work on the detail page okay and if you don't have any uh blog post for that particular category what we can do maybe we can simply display a message where we'll say we don't have any blog post for this particular category yeah okay let's do this so on category page category post page H here we should have some flag I'm going to say private wait so for this feature if we did not have anything we were patching that as per the category right so that means if we just check featured if this featured is empty then we are sure that both of these are going to be empty right so we'll simply check this feature so here okay so instead of having it like [Music] this uh okay let's have a private Bull in property here private bull has no post something like this so here we'll say featured is M okay then we can have this condition for all at all these places feature if not has no post or we'll say yeah if does not have any post then no no no it is is confusing right okay let's do this we know this featured subscribe box will be there for sure but on this H5 in this MD let's do this move this H5 inside this copy this H5 okay and then we'll add this section should also go inside this only no no no let me think let me think let me think what would make more sense it would make more sense if we completely skip this da but no I wanted to have less conditions but that is not going to work so let's do this okay we'll say if is featured is not null but the problem is it is semantically it is not making sense so let's go to that thing only so private bu uh has no post we'll do this only so feature is null here we'll SA featured is null then we are sure that there are no post in this category so and why so as we are patching the uh recent blog post if featured is null if there is no featured something like this if there is no featured post so that means we are sure that this is going to be n so we can use this has no post here we'll add this condition if no no no no has post let's do this okay comment is fine so let's stop it reload stop if has posts then only we are going to do this or maybe here if has post then only we'll render this popular section mhm okay and then in this first case here what we'll do feature is fine this is fine so this H5 for this H5 I actually wanted to display this H5 so what I can do inside this call MD 8 first thing I'll check if has post then display all of this and in that case we don't want this condition now we can remove this condition right and then if we do not have any post then we'll add a else condition and in that else condition we are going to have these two things H5 with we'll say category name posts and inside this I'm just going to have one P tag there are no blog post yet in this category or we'll say under this category name okay so mb0 let's have it this is fine mb5 this is mb5 so we'll say M5 and on this P we'll say P5 class P5 class P5 and text Center save everything and we should see what we are willing to see if there are no post in that particular category it should show that that second section it should show that section let's see how it looks okay so let's go to SP net core here we have all our post if you go to SQL SQL Server post there are no blog post under equal server yeah this looks fine right cool we can make it bigger so does Bo 4 has all those classes H1 no it does not have the okay okay let's do this we are here so here what we'll do we'll see say font font weight bold and then we let style font size 25 PX save it and check it cool there are no blog post here under SQL server and we are good cool let's work on the detail page so for this first let's fix the URL so blog post detail it was SL details so let's make it post slash and then slug so blog post slug okay and let's create a property for this in our code section we'll say prop string and this blog post Slug and we'll add parameter attribute to this then we are going to have complete blog post so we'll say blog post blog post and let's have new default value for this then we'll say override on initialized async and we need to inject our blog post service inject blog post I blog post service we'll call it blog post service and let's inject navigation manager as well inject navigation manager let's call it navigation manager only now we'll fetch the blog post from database from our service so here we'll say word result equals a wait blog post service blog post service dot uh get blog post by slug sing right and we need to pass slug so we'll say blog post slug cool now we'll check if result dot is empty if this is empty then we'll simply use navigation service and we'll that means this URL is not correct so we'll navigate user to the homepage slash and then same because this URL is invalid We'll add replace true and then we'll return from here we don't want it to execute further cool now it was not empty that means we have data so we can set our blog post to result do blog post and then we can have a collection so private blog post related posts with default array and for this related post we'll say related post equals result Dot related post like this okay cool okay now we are good we can use these two things in our markup here HTML design let's remove these HTML commments thing we'll render everything only if we have where is that that box a subscribe box where is it is it inside this we have article then we have subscriber okay so the first setion will inject sorry not inject if blog post. ID is greater than or let's do this only if blog post. ID is greater than zero let's render everything only in this case there's no point of render anything else okay then this feature block post list this means this is related post so here we can pass post related post save subscribe box and then let's work on this share this share this we not we are not using this share this third party library right at to any and all this so we can remove this section H let's remove this call LG2 lg8 md12 let's have sorry what I did H call md12 call lg8 let's remove this let's have it call md12 only okay now we have this article article post and we need to add everything inside this article right before that we have this main section okay let's add things here first so this is category name so it will be our blog post underscore blog post post. category. name and this is the HF for this so we have blog postore blog post do category do slug hyphen post this is the category URL right then this is the title blog post title so we'll say blog post. title then we have introduction this is the blog post introduction so we'll say atore blogpost do introduction then we have this Avatar user Avatar author name so underscore blogpost do uh usern dotame then published at so blog post dop published at. to display and then this image so underscore blogpost do image okay cool then in here inside this article okay when we're seeing article post here will be the complete article so that is going to be blog post dot content now this content is actually HTML content so we need to convert it to a markup string so that it can display the actual element uh actual HTML data right so for this we can convert it to markup string like this and use this directly like this BL blog post. content and now everything should work fine let's try it out save everything and let's run it we have it here homepage category page and article okay we need to fix the URLs as well okay let's fix the URLs first let me close everything close all tabs then we'll open our homepage category post blog details and blog post list feature and popular blog post all right so here this article. HTML this should be post SL b. slug right this is the URL for our blog post page right blog post list blog post detail post SL blog post detail save featured pin featured let's see Dave image this one title anchor tag details this should beore first do slug then we have this section here we have this video title next save it blog Post article here is it then blog log [Music] post detail page detail page is fine then comes this category page so here we have this uncore featured then author we don't want this right it should be just latest it will come from there only then we have there no blog post yet this is fine and cool I think no let's check on homepage do we have something on homepage yes we have this this is going to be first feature cool save everything and let's run it's here let's see detail is uh home is fine and detail page C heading image this thing we change this Avatar then we have this complete uh description complete content then we have this this box cool let's go to some other we we are here let's go to category from category let's open it yes from feature latest so everything is working fine right cool so we winded up everything just change this so for this Avatar I found one online service which is uh uiy avatar.com if I do this it gives us this so background random it will give initials with some random uh color and because I'm using the same let's say I change the name if I only provide one then it will use this so if the name is one character one letter or two words so it works for everything so we can use this directly because we did not have we do not have this uh user profile picture upload section in our app but you can try it I showed you the way how you can add additional fields to application user I showed you how you can implement the image upload we are using it on our uh creating a blog post page so you can uh use all that knowledge to implement this functionality this feature as well if you want for me let's go to blog post list uh sorry Details page here we have this image so here I'm going to have this URL with this name we'll make it Dynamic so we'll use this HTTP utility dot hand code URL and code and inside this we are going to pass our username so that is going to be blog post. user.name so save everything and let's see if it changed that and we can see this AP that means it got changed okay so I think we are good with all these things as well now there are two missing pieces first is this this section subscribe box this is not yet functional right and then second thing if I am on this category post page here what I'm displaying I'm displaying a featured one featured item four popular items and then couple of latest items but what if I want to see all the blog posts under this category we don't have that page yet right so we are going to create a new page to display all the category blog post and we'll Implement paging on that right because right now we are showing only one feature four popular and five latest not all from this category so first let's work on that all category post page then we'll fix this uh subscribe box okay okay so let's create a separate component for this so in Pages I'm going to create a new razor component and what should we call it these are category posts but we already have a category post page so let's let's call it paged category post something like this and let's add the URLs so first page it will start from the same category slug category slug iph post and let's say all now we are going to implement paging as well for this so let's do this let's add page hyphen and then page number so we'll say URI page number which is going to be int okay so if it is first page we'll use this first URL if this is any subsequent page page 2 3 4 5 the URL is going to be Blazer hyphen post / all/ page hyphen 2 something like this okay so now first thing let's add the properties for this category Slug and U page number so we'll have public string category Slug and then we'll have public intent URI page number both of these are going to decorated with parameter attribute okay H so save and in this also we are going to have private category uncore category and then we are going to have blog post list so for on this page what we'll do we'll display a list of popular blog post and then all blog post okay two sections so let's have two collections so first blog post array we will say let's say post only and then we'll have one more where we'll say popular okay H cool let's have private const or we can have it like private const in page size page per record let's have five right now save and now we'll override our own initialized async method and then we'll try to fetch the data for this first thing let's inject inject uh I blog post service blog post service save and then what we should do H let's go to category post and what we have on category posts let's copy this section first navigation manager let's inject navigation manager as well and we need to inject category Service as well so let's inject category Service as well now what's the issue categories PL on initialize okay post and popular right so recent remove this feature let's first use this as this post we'll fix this now what's the issue what what is he complaining about of wait okay okay so first thing we are getting the category as for this category slug if category is null that means this URL is incorrect we will navigate to the homepage and return from here if that is not correct we got the category we are setting the category to underscore category then we'll fetch the blog post now it is going to change so popular is fine we are fetching popular post for this one so let's get at patch five from there but what is this post zero first. default blog post to blog post of AR okay okay okay okay then we need category wise blog post and that to with paging okay so let's do this let's reverse the order first popular popular and it will be like this then post let's go here and create a new method where we'll say get uh what we should say let's say get blog post a sync like this only just instead of count we can have category ID although we know we are going to get it always but still let's have it optional for now there's no uh we can have it like this only and here we'll use int page number and Page size or maybe we can skip this page number to have that the similar logic that we had for the quick grid with page index H let's have it page index okay that means page number minus one so it will start from zero and let's implement this method so I'm going to implement this like this public and let me copy from any of these okay now H category ID category ID view count what is the issue with this one of wait we need a s okay now we need to think about it as's no tracking category user published category ID and view count with order by view count no we don't need this by view count we need it by published at and then before taking we will skip we are implementing paging here so we'll say page index multiplied by Page size page size and then we will take page size so save now if we see we have exact same logic in the these two methods right get blog post sing and get popular postac sing right we have the exact same logic the only difference is not popular uh recent the only difference is here we are taking this count and here we are skipping and then taking the page size right so what we can try we can extract this to a separate function separate method and we can reuse this from there how we'll achieve this we'll say private a sync task of blog post AR and we'll say let's say get post a sync and here we can say int skip int take and int category ID like this okay then we'll add this loog logic here skip We'll add Skip variable we parameter here we'll say take parameter category ID we are already using let's use this thing from here we'll say return get post async skip we know Skip logic is this one so we'll skip this then take his page size for the this one and category ID is category ID and we can remove that complete logic and simply return return a wa and because this is a single line we can simply use the Expression body like this great same thing we can go to this get recent blog post so here we'll do the same thing return of wait get post a sync then skip in this case we are skipping zero we are not skipping anything taking count and category ID okay let's do the same thing use the Expression body so arrow and then this and we are good okay now we can use this get blog post it s this method on our this page category blog post so here we'll say get popular is fine for this one we'll say this get blog post async and it needs page index page size category ID category ID we provided page index we need to have some let's have a private variable here private in page index underscore page index with the default value of one so let's use this page index then page size which we have this as a constant page size and then category ID okay so for the first page it will work because the default value for this page index is one so for the first page it will fetch five posts let's find up the uh uh the UI the HTML we'll get a subset of category post to this okay so for this let's go to category post page and this container row call md4 this [Music] section uh I think let's get let's copy this complete page and here what we'll do first let's remove this H post section the H post condition basically then this recent we don't need this recent or do we H we don't need this featured section here so we'll remove this featured okay so first thing H5 and here we'll say instead of featured we'll just say the category name and let's say post okay after this we are going to display all our blog posts so underscore post like this and I think we are good with this close da and then we'll have popular blog post on the right section right side of the this row okay looks fine I guess popular post subscribe box main post which is this okay now let's go to the category post page and here we are going to add a new link for this page which will navigate to this particular page okay so on category post after displaying all the posts inside this blog post so let's have an HR horizontal rule HR tag then we are going to have a Dave class uh is this inner class call md8 okay let's do this let's directly have a nav link with HF with this page and we we have a problem we cannot use nav link the problem is we cannot mix and match Dynamic and static portions for single attribute property using uh this uh razor Blazer component so we need to use anchor tag here and here what we'll do a then we'll have category slug so we already have category slug right we can directly use this so we can use this category slug hyph post slash all and then we can say let's say all post or we can add category name here as well category do name okay so it will display all Blazer post something like this then we'll have couple of classes here so BTN BTN SM BTN outline primary maybe and then we need to move it to the right so we can say Flo right save it and let's try it out how it looks okay it's here let's open C and C we have all C posts and this is a problem the problem is because this is float right so we need to fix it what we can do uh have add a span with class w 100 without any content save no we need to clear float HR HR w 100 and D BL block would it make sense no okay let's fix it another way so what we can do we can wrap this anchor tag to into our div save it and let's see did it come no [Music] refresh sometimes these small things take so much of time this floating is always tricky let me try to find how we can fix it let's try different different things so we'll say although this is a block label element but d block w 100 let me try to fix it there was some bootstrap class for Clear fix add it on this HR class clear fix no this class does not exist Clear RO okay let's add this explicitly so on this HR we can say class or not class style and here we'll say clear both left and right or we could say clear right because we have float right on the top so save it let's see it refresh and we have something right now let's [Music] see on first HR we have margin top and margin bottom then we have this Dave and then we have this HR then we have this Dave so on this we have this right style clear fix okay maybe we need to add that thing on this button this anchor tag or maybe the Quick Fix would be just remove this bottom HR I'm not a full-fledged designer so and CSS is always tricky so I can do most of the stuff but I'm not a full flash designer so please okay so we can remove this or maybe if I want to fix it I will try something maybe on this adding some margin bottom sh Marin bottom sometime P something like this margin bottom we could use the same thing one M right so this thing also we can try let's try it so on this anchor tag let's add a style with this okay save and let's see if it goes to that page all sisha post and we are here CA post all and it is able to pull the ca post and then we can see five popular uh blog post now we are here and we want to implement paging so let's add previous page and next page buttons here on this page so so let's go to page category post page here after displaying these blog posts we are going to do the same thing similar kind of thing copy this thing add it here and let's do not have that div oh no let's have that div and we'll not use float right or float left instead we'll use display Flex on this div so here we'll say d Flex justify justify content between so that we can have two buttons on the very left and on the very right so using this we don't need to have this clear right copy this so first button would be previous page previous page and this right button would be next page okay now we need to make these with page the the URLs basically so let's generate these URL think through about it so we have index page index which starts from one or from zero page index should start from zero because it is index or we could have page number here and when we are passing it to there we can have page number minus one okay now we have page number let's use it so for previous page when it should okay just disable or stop it so previous page should only be style margin bottom we don't need these Styles right H so previous page will only be there if the underscore page number number at theate if underscore page number is greater than one if it's greater than one then only display this previous page okay and the URL we could construct here prve page URL and we can have it something like first category slug category why it is not showing this category slug hyphen post hyph all okay then we can check if the page number if this is one or we could say if this is no no no no page number is greater than one then only we'll display this right so if page number equals equals 2 that means we need the previous page will navigate us to the page number one and on page number one we do not show this page hyphen page number okay so if it is greater than one it is two then we'll not display it and if it is not two if it is greater than two then we'll do this so we should have this like this and then we'll say pre page URL equals or let's say plus equals we are going to add slash page hyphen and then page number minus one right so if it was page number three then the URL it would be it would be the category slug SL hyphen post plug hyphen post hyphen all hyphen page hyphen 2 like this okay so then we can use this URL directly here like this okay now what if it is not greater than greater than one then what we can do because we have this dlex justify content between so let's have an empty span here so that our design is okay this is for previous page now let's work on next page so for next page when we should display next page if the HM we should display our next page if the posts we got do length is equals equals our page size right that means there could be a new page and if the post dot length is less than page size that means our page size was five and we only got four blog posts on this page that means there is no next page right so we'll do this here and here what we'll do we'll say category SEL post hyph all SL all/ page hyphen then here we could simply say page number + one so if page number is one it will be two I think we are good we are good now what if we accidentally added that page number one here it should automatically redirect to this page in that case so we need to handle that particular case Okay so for this what we can do on initialize a sync after getting uh C or maybe no before getting anything we will check if URI page number let's make it n La so if URI page number this has value and this URI page number is or maybe let's move inside this so if this has value and URI page number is greater than zero if it had some value greater than zero but it could be zero right we could provide zero if we provided zero then also it should navigate to the previous page where we have that all for any invalid okay let's do this here we'll say if it has some value and then we'll add a condition if URI page number is less than two it is going to handle all the cases right if it has some value and that is less than two so either that is one zero or any negative number we are going to redirect user navigation manager do navig get to the we could say category slug page so category slug hyphen post slash all this page and we'll use replace true because we don't this page is invalid so we don't want to have it in the history and then we'll simply return from here we don't want to execute fur if that's not the case that means Ur Page number had some value and this value was greater than one it was either equals to uh two or more than two what we'll do in that case in that case we'll set our page number to URI page number page number value okay so looks like we have everything set up now let's do one more thing so this underscore page number uh category post here we will check if this page number is greater than one then we'll display some additional stuff and that is going to be this page hyphen and then page p number underscore page number if that's not the case we'll have whatever we had earlier so for this to check let's reduce the page size let's have it two save it and run it now it should handle all the cases it's here let's see detail page category page and we say all and we are here on all 1 2 3 4 it is still displaying four but it should have displayed two only right 1 2 3 4 let's see what the issue is page number is one page size is two page size we are passing page size get blog post okay and the problem is we are using post zero it should be one right because zero is for popular and this one is for one so save it and let's run it net is coming okay aset core all and we have two blog posts and we have this next page which will navigate us to page number two and now we can say we can see the page two in url page two on this main heading and we have previous page and we have next page so on previous page if you see the URL can you see it let me try to do something if I can um I don't know how I can show you but okay I can just show you this this is the previous URL so which is without any page and the title adding is also without any page hyphen that next page then if you go to next page now we have we are on page three and this is the case where we don't know if we have any further item if you want you can hand handle it by passing the total number of Records then you can use that but I think we are good with this approach right now so from here if you press previous it will go to page number two then page number one and we are good so that means this paging is also working let's use C all C posts next page next page and right now we don't have any next item so next page button is not here but previous page is here and we can tap on previous page it will go to page number two then page number one and we are good Okay cool so that means this page is also done now we can go to we can work on this subscribe box if uh I don't know if you are paying attention all these Pages these pages are statically server side rendered there is no interactivity these are are not interactive server web assembly interactive or to nothing if you check the source you are going to see everything in in this uh body section everything is rendered on server so now the problem with this is interactivity does not work we cannot handle these things subscribe nothing is going to happen and we cannot do much here so we need to work with forms and Blazer gives us enhanced forms and that is a very cool feature we are going to experience it so first let me push the code all right so let's go to our uh subscribe box this one and in here did we created subscribe entity data entity subscriber yes we have subscriber entity okay so here what we are going to do we are going to have a private subscriber subscriber entity let's say model get set with the default value of this default model okay okay and now we are going to wrap this section in a addit form so edit form and for edit form we'll provide our model which is going to be this model only this object and inside this we'll use our data annotation validator okay after that we have first name last name but in our subscriber model we have name and email so we are going to use these two so first one we'll use name and second one email and these should be input text so input text and we'll use bind value it will be model. name okay then classes so class and placeholder let's use these only form control class and placeholders name okay and then here we are going to use validation message for model. name like this with a class of text danger like this okay let's copy this and here we'll say model. email placeholder email and validation message for email and on this one we will set type equals email okay so this is button type submit subscribe this is fine okay now let's have uh let's create a meth method so private async task we'll say subscribe async okay and on this we'll say on valid submit we'll call this subscribe sync method now we need to create a subscribe service where we are going to uh add user to our subscriber list okay so for that let's go to our services services and let's create a new class let's call it subscribe service let's inject idb context Factory of type application DB context application DB be context context Factory and here we'll have one method public async task and we'll say subscribe a sync and it will get a parameter of type subscriber okay and here we'll create our context using context equals context Factory dot create D context we have only one method so uh we are not adding it to a separate method here we will check if this uh email already exist in our subscribed database that means this user is already subscribed so here we'll say is already subscribed so we'll check if uh sorry await context do subscribers do as no tracking do N Sync s. email equals equals subscriber. email okay let me break it down to multiple lines if this is the case is already subscribed then we'll return uh let's say let's have a return type of string n Lael string so we'll return return one string here where will say you are already subscribed okay now if that's not the case we will add subscriber do subscribed on we'll set current date time date time. UTC now and then we'll say a wait context. subscriber. add async and then this subscriber model and then we'll say await context. save changes as sync and after that we'll return return null that means everything was successful cool let's create extract an interface uh H add to current file let's register this in a program.cs file at transient I subscribe service subscribe service okay okay cool let's go to our subscribe box component and let's inject this I subscribed service so inject I subscribed service we'll say subscribe service and here we could use this word result or let's say word error message because we know if it return return something it will be error message a wait subscribe service dot subscribe async and we'll pass our model to this okay then we'll check if error message is null if it's null that means there was some sorry if it's null that means everything was successful so we'll say if it is not null if this is not null then we know there was some error so we need to display that error we need to show that error here so here we'll say private string uh n string message okay if there was some error we'll display the error here message equals this error message and if that wasn't the case then we'll say message equals to uh successfully subscribed or let's say thank you for subscribing thank you for subscribing after saying this we will reset the model and I think we are good cool now there is one problem in this and the problem is we have this message right so let's do this when we are ENT entering into this let's say we will say subscribing dot dot dot something is happening okay now let's display this subscribe right before this call we will not have any uh margin and here we'll display this only if we have this message is not null or empty so string dot is null or Whit space underscore message if this is not null or wh space that means we have something in this message then we are going to Simply display this pcore message and on this P let's have a class uh m0 and P0 no margin uh no margin no padding at all now this box this thing this uh component this is being rendered as statically server side rendered on server side rendered pages that means we are not going to have any interactivity on this what that mean is this form and everything all this is not going to directly work but on the edit forms it will be actually when we will submit this this complete form is going to be sent to the server to basically there is going to be complete page reload complete page post then come back so for that just I got now first thing we will add a method post after that we don't want this complete page to be reload right we don't want this complete page to go to the server and reconstruct and come back so we could use enhanced navigation enhanced form submission for this so this edit form gives us this enhance which is a short form for enhance equals to true this thing which we can use directly now what it is going to do instead of uh submitting the complete page it will simply use JavaScript ax fetch request to submit this form okay so now there is not going to be page reload but now we will have one problem and that problem is going to be this message uh I can show you this thing let's run it or maybe I can show you that enhance as well let's do this let me stop this let me remove this enhance save it and uh yeah one more thing whenever we have added form in statically service side rendered Pages we should provide a form name the reason is we could have multiple form submissions for this page so in order to because this component is going to render for this time when we are seeing it but when we submit it then the this request goes to a server from there it again executes everything so it needs to know that which form is it so the name is up to us we'll say subscribe form so it will know that okay this form is being submitted I'm running it I have not that I have not added that enhance so we'll see how it behaves right now it came and let's go to some category page we have this name email let me inspect go to network I'm going to say preserve log now I'll simply going to use something let's say temp and temp gmail.com okay now I have selected this all so I'm subscribing you see complete page reload and we say the form uh name field is required email field is required that we'll just check so first thing complete page was reload that is not what we want we provided this model name email but still it says the name field is required email field is required and that's because when this form send gets sent to the server for this model we need to tell that from where you are going to get the values for this model so initially when we are typing it it is on client we have everything but we when we say submit everything went to there but at server side this component is going to be rendered again and when it is being rendered there it will come here it will check that model equals new that means new instance of this model and at that time it will going to check data annotation validator so we we did not provide name and value name and email because we are saying Slash new uh sorry equals to new new object so in order to tell Blazer when the form is being post on the post server side that you should get the this news default value but from where you will get these values it is Supply parameter from form so when we submit this and when this component is going to rendered on server after submission then it will check okay this model the default value is this but we are saying that get this values for this model get values from form the submitted form which we just saw in that inspect there was name and email for values being sent so it will check those values and fill out those values here so save it run it okay it is here category let's see again Network okay I'll use the same values tempt gmail.com subscribe you see complete page reload and it says thank you for subscribing that means values sent to the server it did it part then rendered it again on the server and it return subscribing is done this is done but this complete form uh reload this is not what we want there's no point of re refreshing the complete page so for this we have this enhance form submission for this we can add this enhance now let me re run the app and this time we'll see does the complete form getting submitted or just this form using JavaScript fetch JavaScript objects basically so we have it here the same page and now again everything is same now I'll provide let's say t one and T 1@gmail.com now in subscribing you see the complete form was not sent to the server and we have thanks for subscribing now we do this we have this name field is required email field is required without sending this complete uh without reloading the complete page uh complete page basically so this thing is working there is only one thing temp 2 let's say temp 2@gmail.com subscribe and it directly goes to thank you for subscribing what I mean is let's add some delay here here I'm saying a wait task. delay of let's say 2.5 seconds okay after setting it I'm setting a delay of 2.5 seconds now let's see how it behaves it is here go to some category page and let's check it temp4 temp 4@gmail.com subscribe and nothing is happening and after 2.5 seconds we see that thank you for subscribing but in between we should have known what the status is so that is because that is not coming here that's because this page is service rended we do not have any interactivity we just submit the form it goes to the server it performs its operation and the response comes back but we have one feature which Blazer provides us for this SSR that is streaming rendering so what that is we will add an attribute here we will say stream Rend ing what it does when we are posting the when we say when we are posting this form first so request went to server where after that if there is any change in the state it will open a response connection then it will simply keep on sending the messages on that particular section uh connection only so how it is going to work when we are doing subscribe Bing we are setting this sub Max message equals to subscribing it will return its state we will see this message and it is still working on this thing it will make this request it will do this and after that when we'll come here it will again get the response and it will send the next update which is message equals to error message and this is not any server interactivity or web assembly interactivity this is streaming rendering on the same open connection so let's see it in action I'm stopping it save everything and run it now we should see this uh subscribing in between okay Pages here I'll use some this one for example let's use temp 5 temp 5@gmail.com subscribe you see subscribing and after 2.5 seconds we'll see thank you for subscribing and this got removed let's try it out for the same thing this time it should show that error that you are already subscribed right so let's do this it is saying subscribing and after 2.5 seconds it says you are already subscribed and these values are not getting cleared okay so that means this subscribe functionality is also working as we expected with all new blazer streaming rendering and enhanced form navigation and enhance form submission everything cool so now next thing is we have this subscribed data in our database now we need to display this data on this manage subscribers page we will create this page and we'll use the quick grid to show the data of the subscribed users okay let's go so let let's remove this 2.5 delay let's have 1 second delay so that at least we can see this and after this let's go to Pages admin and we'll create our manage subscribers page manage subscribers let's add the page which will be admin SL manage subscribers okay cool and inside this I'm going to have a collection no not collection we are going to use our uh quick grid so for that what we'll do here we will have a private quick grid item provider or what quick grid provider grid item provider grid item provider of type subscribe subscriber subscriber subscriber okay so this will say subscribers provider okay now we'll do the same thing we'll say private const in page size let's have five for now we will have uh pagination in this so for that let's have private pagination State underscore pagination State equals new pagination state with items per page with this page size page size like this and we are good okay now let's go to override on initialized async and inside this before that let's go to our subscriber service and create one more method to fetch the list of subscribers so here we'll say public BNC task subscriber array and we'll say get subscriber snc and we will have int page index or in start index then int page size these two things here we are going to say using word context equals uh context Factory do create DB context then we will simply return a wait context. subscribers. asot tracking do order by descending s do subscribed on dot skip start index dot take uh page size do 2 array Isn like this let's break it to multiple lines okay skip take and this and we are good let's add this method to interface and we are good to use this so here what we'll do on this subscriber provider we'll provide body for this which is going to be that async request and from here we need to return uh gr provider result right GD item provider result Dot from H and then collection okay we need to have total count as well from here let's return paged result paged result of type subscriber subscriber okay that means we cannot directly have this so we'll cut this we'll say word query equals this section then we'll have total count we'll say total count equals a wait query do count I Inc and then we will have records as a wait query do skip take and to racing then from here we are going to return new page to result of subscriber first is records then second is total count like this okay let's change the type in uh interface as well okay now let's go here and here we can get result equals a wait subscribe service we need to inject our subscriber service so we'll say inject I subscribe service subscribe service and from this subscribe service we can get subscribers I sync then start index is going to be request do start index and the page size is going to be request Dot count or if that is null we will use our page size okay and after that we'll provide this result dot records and then total count will be result dot total count we are good so our subscriber provider is working is fine okay it looks great let's add our loader as well so here we'll say private bu is loading then we'll have that private string uh we don't need to have loader text explicitly because we are not going to change that right so here first thing is we will check if is loading is true if it's loading is true we'll render our loader with loader text as fetching subscribers like this okay if we are not loading after that we'll use our quick grid so quick grid on this quick grid first thing we'll use our items provider which will be this subscriber items provider then we'll have our pagination on this which will be underscore pagination State okay and after that let's add couple of bootstrap classes same table table border and table well stri cool table strip okay now let's add columns so property column and property is going to be property it is going to be C do name and then c. email and then C do subscribe done on this property columns we could have format parameter as well so this is date time so we can format it we will say mmm DD y y y y HH mm and SS the actual date and time and everything and let's change its title to subscribed on I think we are good let's add the paging so for this we'll use paginator with State as pagination state and I guess everything is fine let's add header so add domain header with the title as manage subscriber subscribers like this we don't need to have any button on this so I think we are good now what is the issue here okay we could use the sync version void on initialized and let's use this as this a label and we are good now okay let's try but before that we are not using this is loading right so what we'll do we'll say is loading to true and then we'll use state has changed because we saw from this it does not update the state it does not uh rerender and after after fetching the data we'll say is loading to false and again state has changed and there is one more thing which we need to do on this page which is we don't want it to pre-render on server so what we will do we'll add render mode on this page as new interactive server render mode with pre- render false okay let's try it out we should see all the uh temp 1 temp two temp three all those data okay it's here we'll go go here manage subscribers and we see this data cool 1 2 3 4 5 because we have a paging of five let's use paging of let's say two items so that we can say see three different pages okay so three pages and something happened stop debugging run and it's coming this format also got applied right man subscribers and yes you see we have paging everything is working fine cool so with this we have completed our application I learned a lot when when I was building this project in this video you might have also not might have if you are following me since the beginning of this video it is going to be very long video and I learned a lot there is so many things and I'm sure you will also learn so many things do let me know in the comment how uh what do you think about this video did you learn something new did you find this project useful and yeah so I think that's all for this uh there is one more feature which we are missing right that page title right now if you see this page title which is in this browser we have not set this page title accordingly we should set this let's do this and on this D dashboard I cannot think of what we can what I can uh add on this dashboard so I'll move this content to the center and let's have that welcome message only you're free you can do whatever you want with this dashboard you can add whatever functionality of feature whatever thing you want to add on this dashboard so for me let's first fix the titles then I'll move this content to the center of the the screen so let's start first thing for titles Let's uh close all pages first close all tabs stop the application and then what I'm going to do I will open all the routable pages so first we have an account Pages login after that we have in Pages admin dashboard manage blog post manage categories manage subscribers save blog post after that we have blog post detail category posts homepage page category posts all right let's add the page title component so page title this is paged category page right so this should be the same the this thing what we have right here in the uh this heading so what I'm going to do I'll simply cut this thing and I'll add a property here so private string I'll call it page title and I'll add this condition here like this with the this thing this thing category name post and [Music] then this until the very end after that this thing okay and then I'm going to use this underscore page title at both of these places so insert page title and for this heading save let's go to home on home we have home which is fine or we could have blazing blog V2 or let's do this H H let's do this let's create an utility method I'm going to add it in extension i s only or U my should not be in extension although it is going to be an utility method let's do this let's create a new class file we'll call it utils which is utilities this is going to be static class with public static string get page title with string title okay so what I want here is first I'm going to add the title after that I'll add pipe and then the name of the application which is blazing blog V2 okay then I'm going to use this get page title to add page title so here for our page title I'll say get page title uh utils doget page title utils doget page title and I'll provide this underscore page title cool so let's do the same thing for home here what I'm going to do I'll say utils dog page title and I'll pass home it will say home pipe blazing blog V2 category post so we have this featured in this category name so we'll use this category name post so here what I'll do same page title utils dot get page title and here I'll say this category name plus posts so Blazer post p placing blog V2 like this then let's go to Details page so here I'm going to use page title with the UTS do get page title and this time I'm going to have blog post. title just block post. title if it for now we'll have blank then come save blog post so on this we can have page title and this condition this header update blog post or create a new blog post this is dynamic so what we can do let's have this thing as uh property so here I'll say private string page [Music] title okay because this is property this should be page title like this naming convention should be like this and here uh where is this this thing it should be page title like this and on this page title we'll say utils do get page title page title we had this somewhere else also right uh this thing this should be page title not underscore page title because this is not a class level variable this is a property so let's fix this let's fix this we are good home is fine category blog post is fine blog post detail is fine find save blog postage also find now manage subscribers so here we can say page title utils dog page title and manage subscribers save manage categories let's copy this thing here we are manage categories so let's say manage categories categories then this is manage blog post so let's say manage blog posts then we have dashboard so here we'll say just dashboard dashboard then login we have page title login so we'll change it to have like this login and we are good save everything and let's run it so we'll see the updated page titles everywhere after that we'll add the text to our uh dashboard okay this is here so you see here home blazing blog V2 move to some category so ASP netcore post and this category now if I go to all then this is same and if I go to next page then it should have page two you see then let's open up some details so this is the details after that this go to dashboard dashboard blazing blog manage categories manage category it did not set on manage categories manage blog post no manage subscribers no on all of these Pages it is not setting why so dashboard it got set but not on manage category manage blog post and manage subscribers if I refresh it nothing what is the issue here dashboard is fine manage blog post past title page title page title this is fine right page title we have page title so manage categories manage subscribers and what if uh do we have it on login log out login yes on login also we have it category Pages we have login login home dashboard manage categories let's see what the issue is manage blog post add new blog post add new blog post also we have everything and if I edited update blog post we have the updated title but for these Pages we don't have it let me see what the issue is okay so the issue is I think this is a bug uh the problem is if I come here this page is fine home page is fine category page is fine detail page is also fine login page is fine dashboard page is also fine but manage categories manage blog post and manage subscriber for these three pages and then if I go to add new block post then also the title page title is getting saved if I edit any existing block post then also it is working fine so I got suspicious that what is special about these three pages so the special thing about these three pages is these have pre-rendering false so pre-render false uh the page title is not getting uh used for pre-rendering false if I made it pre-render true this is many subscriber page I save it and now we see man subscribers refresh we need to rerun it manage subscribers so it's here many subscribers you see many subscribers so the thing is if the page has interactivity with pre-rendering false the page title is not getting saved so okay but in our case we are good but this is a bug for sure we need to raise maybe get a issue so that it should be fixed but because these are admin pages so we are okay with if this is not getting saved but we have added the functionality so everything is fine let's go to dashboard on dashboard I wanted to set something so let's use authorized view first inside this we'll use authorized inside this I'm going to use a div class text Center and then I'm going to use a P with a class P5 a lot of padding and then I'm going to see say H2 hello and the context do user doget username okay then let's use a line break and then H3 with welcome to the admin dashboard admin dashboard save it let's run it let's see if we can see this text on the page okay it is coming let's go here and hello AB Prince welcome to the admin dashboard so that mean this is fine manage categories so all the functionalities everything is working as we demoed and as we expected everything works fine everything works great cool now all the features are done now let's clean the project up right whatever things we are not using we are going to clean most of the things are from Identity so let's remove all those things so first accounts Pages this manage uh manage folder let's delete it completely we are not using this inside paging we are just using login so move all other Pages all other Pages delete these then we have shared account layout we are not using this layout right so let's I think we're using status message component status message yes we are using status message component on login page apart from this let's on login what is the layout Imports layout is account layout do we have anything in account layout we have something navigation refresh okay we'll leave this account layout here and Status message apart from that delete everything then we have identity components route Builder inside this we are going to clean this file up so here perform login external login we are not using it delete this we'll have log out in this after this manage we are not using this manage group so let's uh delete this logger Factory manage group no we are not using manage group so remove this and remove this as well fine we are just using account log out so let's leave this and let's let's clean all these unused name spaces okay after that identity no Emil sender this is being used defaultly although this is not actually being used but we can leave it and all these we leave all these here only after that we'll come to layout in layout we are using admin layout we created footer main layout but nav menu we are not using this nav menu so let's delete this nav menu we have created our own top na bar so we are using this one then in Pages admin we have created it we'll use this au. eraser we are not using it delete then counter we are not using delete error let's have it intact then we have weather do razor we are not using it delete this share we created this imports. razor this is fine app Razer routes. RoR razor let's leave these a data we are using everything model we created Services we created template we added I think yeah that's all we wanted to clean then go to login page so components account page is login on login page we had that method which has this thing so let's remove all this thing and now this is login Asing so we are using perform login async this is direct single line so let's do this let's go to the form edit form and let's use this instead of login user let's use perform login async and then we can directly remove this login async method cool so I guess we cleaned everything up let's check if we have something in program.cs no everything looks fine let's try to build it if everything is fine or did we break something so let's try to rebuild rebuild success let's try to run it okay we have home page we have category page we have we have category all pages we have next page previous page detail page login profile dashboard manage categories manage blog post manage subscribers manage blog post and this functionality also working manage categories working add new category working everything is still working log out and let's see the subscribe this one temp 7 temp 7 at gmail.com subscribing and thank you for subscribing that means everything all the functionality everything is working same as before we just cleaned the project okay after this there is only one thing which is missing right now on our components Pages admin manage blog post here when the blog post is published we have this anchor tag which has this incorrect URL / details let's fix this so this should be slash post Slash atate context. Slug save and let's let's let's run it so that we can see that this is correct okay it's here login manage blog post and we have this announcing view3 and this Got Loaded that means this functionality is also working fine cool okay so so I think that's pretty much it for this video for this project this project is completed now please like this video share this video subscribe my channel and please let me know in the comment what next what you want me to work on next any project suggestions project ideas I will see and I will work on your ideas okay so I'll be back soon with some other cool project till then bye-bye
Info
Channel: Abhay Prince
Views: 7,761
Rating: undefined out of 5
Keywords:
Id: bqlYviq4J4o
Channel Id: undefined
Length: 591min 14sec (35474 seconds)
Published: Sat Nov 25 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.