Creating a .NET 6 minimal API from scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so hello everybody and welcome back to the code wrinkles channel 4 of first live streaming i guess four months and the reason why i was running a little bit late is because well i got a little bit rusty with all this live streaming stuff and uh yeah i had to reset up some things so fortunately everything's okay right now please let me know if you can hear me well enough or if i should tune down a little bit the background music or things like that just just let me know please okay just uh looking at some stuff here but it should be fine i guess okay so dotnet six is about to be shipped in um i guess three weeks or four weeks something like that and i have played a little bit with uh the new very very hyped feature which is the minimal api dot n6 and what i want to do today is well start working on um let's say a real api or almost real api that um this uses this.net 6 uh minimal api hosting model let's say but of course we want to start from a blank solution so pro we'll also have to build a few domain classes but what i want to do here is uh we'll also look into the minimal api but my first opinion on it is that it actually is less opinionated than the full mvc uh let's say type of architectural pattern and this allows us to do things a little bit different uh it it gives us a lot more freedom in the way that we design our end points and our overall our overall application and that's why i think that this is a very very good point to also uh start building out apis with the vertical slices architecture that jimmy bogart uh talks about for some years already but that was also possible of course with the regular asp.net core web api but you still had to follow some standards and it was very easy to actually get distracted from what actually vertical slices mean and we really want to isolate each type of feature into a self-contained thing that knows everything about itself and it doesn't really care about anything else that happens outside of it and this is actually something very very interesting because my opinion is that it also allows us to basically get rid of two layers in that we usually have in our applications which is the services layer or the use cases layer if you prefer the clean terminology and the repositories because my opinion is when we use handlers for uh for each command and query that are really searched contained a certain feature it really is that it really doesn't make sense to use a repository because because you just get there in the handler all the data that you actually need but let's get actually started i would say so uh first of all let's let's be let's build out the project structure so i would add an existing project and by the way this code will be live on github i will show you the link afterwards and uh if you can you can then just a fork or clone it and play around with it afterwards if you if there's somebody that wants to build a ui for that then well be my guest i would be more than happy i'm really not very very big ui fan even though of course i work with also with angular also with react the regular razer views and things like that so let's start we need a class library first and we call our platform ah by the way we want to build like the api for a blogging platform and what i have in mind is actually medium where well we have a site where where somebody can create a blog and then can write articles on that blog and things similar to that so this is actually what we will try to model right now and then expose of course via an api of course right now or at the beginning we will have very few end points but my plan is to also continue this series and build out this api uh well step by step also feel free to open issues on on the github repository to actually uh well request new features or things or suggest things that might that we might need to add to the api and and things like that okay so uh first uh the the application is called thoughtful so let's create our domain so this would be thoughtful domain and we'll have um the class library.net 6 preview of course because we need dot net 6 in this case and we'll also have to be careful when we install nuget packages to also include pre-release versions so that we can actually let's delete this class so that we can actually use all the the new things in dot n6 and everything that that comes around with it like entity framework 6 and and similar good so this would be in our domain what we will still need is a data access layer of course so let's also add a project for that it would be still a class library and then we call it dal from data access layer and that should do it and last but not least let's create uh our api and they said i guess that these layers are the only layers that we actually need of course if we want to send email notifications when we will then maybe create also a logging system and the logging abstraction we might also add some uh a new layer for the infrastructure but basically that's it we don't have any repositories and we won't have any services that we usually have so in this case uh let's choose asp.net core web api this case let's name it dot api and here we'll have to choose for instance here you see this checkbox here use controllers so if you want to use the minimal api you didn't just have to actually uncheck this because otherwise you will use the regular controller based uh hosting version of of asp.net core web api in dot n6 so in our case we want to use the minimal approach so we will uncheck this and uh yeah then we can click on create i guess everything should be fine right now so let's let's take a look first here in this api uh because what you see here is that we actually have only one file so we we have only this program.cs file so we don't have the startup.cs anymore it's actually something that that we actually don't need and let me get rid of all these comments and one problem that i already see i guess is but we'll we'll see how we can actually can work around with that i'm using visual studio 2022 preview version of course the community edition so the idea here is uh that we we it's actually very very simple you see that we don't have any namespace definition here or class definition uh this is because this is using that uh the top level statements where you don't have to provide a class so in the class that is the entry point to a program you don't have to provide anything else you can just write some code and it will work so you could just work you can just write a console.writeline and it will print out something on the console but that's actually a feature that's already in c sharp uh eight i guess so or nine nine sorry so it's it's not really new to this dot net six it's uh actually it was already there with dot net five but the idea is here that we have this builder and we create here a web application and everything that we used to do in the startup class we actually do here because here on the builder we have the services which is the service collection and this is where we add our services exactly like we did in the startup configure services but in this case of course as as we can see here is uh well it's it's it's here in the program.cs file then we actually build the app so we get an app so after we get the app this is actually what we did previously in a startup configure method so here is where we actually register our middleware here we have these two middleware registered and this one and then we have already as you can see here this map get this is very similar i would say to uh to express we provide the point and we can then here just provide lambda in which we perform an action and this means that when we make a request for this endpoint then actually this method will be executed and uh that's actually it then we run the application and that's pretty much it for the minimal api so let's let's run it okay we have a problem here um it's the approach without okay sorry of course yeah let's go here to this and make our api as the startup sorry for that let's apply it okay and right now we can run it swagger is here added by default so we can already use swagger but we'll see that uh actually defining metadata for for swagger is a little bit different here than in the other versions of the api so here is the window on the other screen and that's actually it let's actually also put a break point let's uh let's have a break point here and then let's uh let's try this out and we see that uh actually we hit the breakpoint and we actually execute everything that we have here in this case we just generate some forecasts now based on random numbers and then we just return them and that's it so no uh you don't need any you don't need any method like that returns an i action result or things like that you can just execute a function or a method here and that's it by the way minimal api it doesn't mean and we will see later that it's simple or that um well it's it's it's too easy let's say but it just means that you don't have to add or write a lot of boilerplate coding in order to run it so that's actually the whole idea of this minimal api so the thing that i see about this file is that this program.cs file would be would get very crowded very very fast so after we define our domain classes i guess one of the first thing that we will do we look into a way in which we can refactor a little bit this uh this program.cs file so that it has um as few code as possible because the idea is if you'll be or while you're building a real api you would probably have to register here a lot of services and probably also middleware and things like that so this would get very very crowded and especially if you want to add configurations uh to follow the eye options pattern for example then you will have to also use a lot of stuff then a lot of the services that we add also require some further configuration like for instance if you add authentication and authorization so we will definitely have to move a lot of these things in some other files and keep keep everything here as simple as possible so yeah but let's uh let's actually start to build our out our domain and let's add here a folder so i i really won't concentrate on this domain or on building out the domain model however one thing that we would have to take into consideration is here since we won't have any service classes anymore uh this means that we will have to build out the rich domain models so a lot of things that that usually happen in the services will will need to be in or directly built in into our entities and this is actually i would say a very good thing to do although in most projects i usually see very anemic domain model and not a rich domain model so we'll definitely have a rich one so let uh let me let me then just start out um let's create the first class i guess let's start with an author let's also make this public now what uh what properties should authors have i'll probably let's have let's make it or let's have an id actually you see that it's it's actually very easy in visual studio 2022 uh because you can you get a lot of suggestions actually here you see that you also get a name but what i want to do here is i want a public string of first name but of course i also have to okay then we'll have your public spin here one thing that you notice probably is that that you get this um this green underlines here and this is actually because yeah we we use here uh non nullable or yeah non-nullable reference types by default which is actually a very nice feature on the one hand but on the other hand actually well it's something that that we get a lot of warnings for of course we can suppress these warnings but for now i guess we we don't want to bother with it what we could do to just simply get rid of it let's we can make it explicit that uh these strings might be nullabout or might contain not of course we know that the default value for a string is null but the whole point of of nullable reference types and the whole use here is that we have a little bit more predictability whether something will be not will be null or not and it kind of like obliges us to also uh like from the class itself from the constructor to make sure that uh either we mark explicitly a certain uh reference type is nullable or uh that we maybe should uh actually initialize it in the constructor or or something like that so in the end it's it's not really a bad thing i would say but uh yeah of course it could be a little bit uh annoying i get here a question on twitch do you plan maybe a series where we appear for for total news actually yes um and i guess i'll start next week if you know if you follow my youtube channel i have there a training series which is not ready yet but i will finish it soon which is called c-sharp for total noobs and in that one actually we take everything from zero so people who never did programming before can can start to take the training and it's it's literally from zero so it start from really the beginning of programming with the idea of what the data type is and and things like that uh so i will start next week on asp.net core4 for total knobs which will start from scratch with an asp.net core api at first and then we'll go also into the views part of asp.net core but my idea was to make those sessions as live sessions so yeah just uh feel free to to follow my youtube channel i will post with one or two days beforehand when i will do the first lesson because i'm not sure yet but i'll definitely do it so thank you very much for for asking okay good so uh what what else could we have here uh maybe we can have here a full name although i'm not sure if that is something that we would need here and let's make this also nullable full name and this would be equal to let's make it a first name plus we'll make it very easy right now string concatenation i i know it's not the best way to to you know catch any strings but uh they said we just want to get started with this okay what's uh what's all the problem with this oh sorry i forgot to mention the data type here and this is the problem and also have a typo here i don't want to capitalize you and i'm still having apples okay right now everything is okay now dates time uh we need a date of birth maybe public uh date time date of birth now the idea here is in c sharp pen we have actually new data types we have the date only data type and we have the time only data type and that's actually very very cool and the first thing that i want you to do here is for instance you can say here for instance date only and that would be only the date part of the date which is very very cool from my point of view so that that's really something that we could use a lot however when i played around with it i noticed that ef6 doesn't still support date only and time only data types when it comes to to persisting them to sql so unfortunately i'm not sure exactly when this will be supported but i guess it will be and until then i just use a regular date time here but actually i'm very excited about this these data types this structs date only and time only because there is plenty of times or i guess most of the times you just you just need the date part for for most of the things and then still you would have to to have the entire date and time and then look only at the date part and do similar stuff so the date only and time only surely make will make things easier and let's add here another string let's call this bio or something like of a description for the author and uh that it's also optional so let's also make this nullable or explicitly make this nullable we have an error here uh where oh my god i have put this in front of or after the public oh my god i'm not sure so maybe friday evening is not a good day for for live sessions but then when is a good day or which evening is good for that so uh yeah that that's actually for our author uh let's actually then go to our blog and we'll try to actually build it out so a blog is actually when you go on medium you can create for yourself a blog which will have a name we might have a description and then you can write articles that will actually belong to this specific blog so that's that's actually what what we will try to model here so here let's add this class which will be called blog let's also make this public because we will need this good uh public we get the id here we we will need a name because the blog will need a name a public uh ring description okay so uh here the name and the description will be required so i i don't want to to mark them as nullable uh then probably we would also like to know when that blog was creating well created public date time created date that's okay but i don't want to use the date time now and then we have somebody that actually owns it so here we will have to configure a relationship uh between a blog and and and an author because an author would uh well and one author could could be maybe or could have several different blogs but the blog could be held only by one author or owner so yeah let's uh let's try to model this relationship here and we'll take um we'll take advantage of conventions in ef for now so we will have here an end it will be a author id hit set and then of course we'll need the author itself and the property will be called owner in this case and uh but a blog could have also different other contributors that actually write articles on on that blog and those contributors are actually also authors so here we need to model another relationship and here is a one-to-many relationship because one blow could have different contributors um but also a contributor could uh or an author could contribute to several blogs uh but we won't think a lot about the relationship right now so for now it's important for us that uh well one blog could have several different contributors so let's uh make here an eye collection public my collection of author it would be in this case contributors get set okay and then we will also need articles in the blog and um actually for the author let's make this uh really one too many um let's uh let's create here a public a collection of blog in starting with ef5 it's actually very cool that you don't have or or that uh many too many relationships are are also modeled by convention so that's that's kind of cool i guess you don't have to go in the model builder and build out the entire relationship except you want to customize it or to override the the convention so right now we are on the author and here we have an eye collection of blog and uh let's say here contributes uh or how should we call this property blog contributions something like that i guess similar to the github contributions but then we would also need uh the article so let's uh basically create here an article okay and let's also make this public okay just let me check if everything's all right so i guess uh yeah i guess you're still seeing me and hearing me okay good so uh where are we we want to start to build out our article of course we need the id i actually like visual studio 2022 very very much uh and then oh this suggestion that's actually very cool yeah i want a title for that uh let's see does it give me another suggestion no what i would say is we could have also a subtitle one article and then we would definitely have a body and i would don't want to mark those as nullable because i really want to have um i really want to have some uh a title a subtitle and although the subtitle is not mandatory but the title and the body now those should be mandatory now uh of course we for each article we need also the author of the article and it's not necessarily the owner because it could be one of the contributors of that so let's model this relationship public and authority okay and then we will need the author itself public author and it's the author of the article so that should actually uh be okay now what we also need to hold here as an information is the date created creating and last updated because you might want to do updates to your article so public date time okay and then public the time last updated okay um then maybe we will have some other properties public inc number of likes and then number of shares whatever probably in later um later sessions we can build this model out be more rich than that but there is only one thing that i still want to have like a blog or an article uh usually also belongs to a certain uh category uh so or it it could belong to several different uh categories based on what the author chooses actually to to have a category so in this case we would also need another class for a category so let's add a new one category let's make it public once again now for the category i guess it should uh should be actually something very very simple we would need an id first uh then uh would probably need a name for the category and we'll need an optional description for that if somebody wants to provide the ring description and then of course we have to model one once again a many-to-many relationship because an article could have uh several uh categories but a category could also belong to several different articles so in this case uh public i collection of article and here will hold the articles that belong to this category then of course in article would have an eye collection of category public knight collection of angry get set of course i guess we forgot to give a name here and uh here let's uh categories it should be like this okay and then i guess one other thing that i would like to do here is um go once again through all these classes and also let's use a default constructor for now for most of them because what i want i want to initialize the things that it really need at least not the collection so here we'll have categories new list of article but it's not article category it's newly and here we are uh category okay and uh the properties that actually are not um although we actually won't use the constructors because when we go for a rich domain model we usually use factory methods uh to create instances so yeah we'll we'll look into that maybe a little bit later for now let's um let's just make sure that we have the collections that we need even if they are empty at the beginning and here we have these blog contributions new list of blog would be sorry okay that should be here and then i guess that's the only collection that we have here so let's go here here we have this uh i collection of contributors so let's add this but it's not a list of contributor is a list of author and i guess we don't have anything else right now this one okay so i see here a question so that's great can't wait um time to release it thank you for this preview now so i'm going to turn out okay yeah i'm i'm great uh i'm getting i'm great or i'm very happy that uh that you think that this is great but uh we'll we'll go just a few minutes over to the api and we'll do only the api and you'll see that it's even greater i would say uh there's only one other thing that we would have to do here is then just to create a db context but for that we'll go in the data access layer and then we'll go over to the api itself so here we have these articles new list of article and uh that should do it good okay so let's now go here in the data access layer and uh let's actually first install management packages so here i'll have to use this new guide and i would have to use the include pre-releases because i would look for pre-releases for entity framework in this case microsoft dot entity framework core here we have this latest p release which is this one rc2 i guess that should be okay except then what we also need is the microsoft entity we need a sql server also let's install this pre-release version so i accept good and then i guess we'll also need the tools okay also the pre-release seems to be okay okay good so let's go then here we can just just remove this class i would like to create a new one from scratch and that would be here um thoughtful mdb context or let's call it context or db context to make sure that it that we refer to the db context not to add other type of contexts that we might have the public class dot full db context uh and of course this should then inherit uh db context and of course we'll need to add using here using microsoft entity framework or of course that should be it let's uh create a constructor and here we're taking it's a regular db context db context options and here we pass this to the base and it's actually it and let's just create db sets for our entities and i guess we would be good to go so let's have here uh public db set of which is the first one article let's we'll have probably two and uh add the reference to total domain in this case that's okay um i i have recently created a video about how to to build up a project structure for a standard and layer application um the most common of of project structure that you will see and then there i pointed out and i just wanted to emphasize it all also here uh when we think about the layers the domain layer is the only one that should not depend on any other uh projects here this should be really that's the core of the application uh okay so we have articles get set okay then we have public [Music] db set of category i kind of actually like visual studio 20 20 22 now it doesn't give me another suggestion because it gave me the suggestion for the category i want the author uh though would be authors get set and then i would have one db set of blog i guess that would be called blogs okay so we have the context so we we're kind of actually set up with that so we can actually move here to our api because we want to do a migration and in order to do migration we actually need uh we need to configure here the connection string uh so let's uh connection strings and let's have one now default and i have the connection string here somewhere because i have created a database previously it's a regular database in equal server express that comes with visual studio so nothing fancy with that so in this case we have this let's then uh maybe go here to our program.cs and we need to add 2db context and as said here in the minimal api kind of on this builder we have the services and here is where we would actually do that so uh yeah here's where we would actually do this and let's make here builder then and but we have to add the packages here also we have to add our packages here because otherwise that that won't work okay so what we would need here is um and this is management get packages once again pre-release microsoft entity framework of core i guess we need here only the entity framework core and the tools i guess okay let's install that i guess we also need the sql server because we have this use sql server so uh let's let's install also the sql server for that this would be this one let's see if there are any other questions no seems that not okay okay i'm just looking right now at the stream if everything is okay but it seems it is and yeah it seems uh you're still here so thank you very much for that good let's let's click on accept here okay and this should actually do it for which package is already in the updates no packages found or maybe the swashbuckle which one actually needs update this one okay uh let's let's keep this version for now because we're i'm fairly sure that this version works so right now when we are in a pre pre-release phase versions are are a lot of times fairly messed up so if you know a version that works then just just use that okay and here uh sorry here we would have that xdb context method uh sorry on services okay i forgot about the services of course and here why don't i see okay let's um let's try it using microsoft dot entity framework still not there but that uh ah actually it's underlined because we need to provide of course the options for that of course uh okay and the db context of course this is generic so it would be how it's called db context here i would probably need to add another package reference correct which is okay yeah and now that's a total different thing and now of course we need to take here the options and um let's go on another line here and have uh options.use sql server and here you know that in the startup file you you pro you you have that that field which is the configuration and that that has actually the configuration that you can use to to read for instance from the app settings file now here we don't have this uh this property but this builder let's see here uh if we click builder so we see that it contains actual a lot of information or a lot of points that we can actually use or configure further so we have we have the services which is the iservice collection but we also have the configuration so we can just uh actually access the configuration directly from the builder and in this case we can see uh configuration dot and it should have get the connection string i guess yep it should have it and it should be the default because that is how we have called and that's it we have actually added our db context right now so from this point of view everything should be okay so let's run a migration to make sure that we have everything in place just need another drink okay so um yeah let's add migration initial fingers crossed that i don't get any errors from entity framework i would hate to do some troubleshooting on entity framework right now and of course things couldn't be that easy unable to me relationship represents the navigation author blow contributions of type i collection of blog either mainly configure the relationship or ignore this property okay let's look once again so we have here an author which has an i collection of blog which is the blog contributions and then on blog we have an eye collection of author which is contributors okay but i'm not sure exactly why this happens but radically it should entity entity framework should be able to determine that it actually needs to create a many-to-many relationship because here we have uh because we have here one of them and then here we have this one uh okay you know let's let's not concentrate on this right now let's just assume that uh well that's it once you are a contributor to one blog that's actually it okay and then we don't need this list anymore and let's run it again yeah it happens always live uh okay your third thoughtful domain doesn't of course yeah of course let's try it once again yep now it created the migration for us to be honest i won't look exactly what what's what we have here is let's just update the database update database i said here in this session i'm i'm more worried or i want to look more at the at the api itself so that's it done we have the database we have added it to our minimal api so i guess from this point of view we are actually good to go right now okay so what's actually next that we would like to do actually um interesting thing that we have here is the global using statements as a feature of of the leg range so let's add uh here what we have in properties we have this launch setting stop json i wonder if i would like to put that in in properties let's let's create just here um at this level you know plus and we'll name this class global usings and the cool thing about this class is because you don't have to actually need any namespace here you can define global using for the entire project and that's actually cool because if you have packages that you know that you will use a lot then you can just add them in in that global using and by or do it doing this doing it this way you you actually make sure that you get that you don't have a lot of usings at the top of each page then or of each class so let's uh using uh system and let's have using microsoft.asp.net core dependency where is it it's on extensions no no did i do a typo here is this package not by default here it's vlogger microsoft asp.net core app okay but what do we have here let me let me check once again here in this program uh services this is okay you know what let's let's do it like this let's take this entity framework from here and let's move it into the global usings okay and the cool thing is okay it should have worked i don't want to have uh let me go here uh sorry i forgot the one very important thing we have to mark those as global of course global using and uh global using and yet it's already white so this means that if we go back here you see that uh everything still works once again with global usings you can define using that used throughout your entire applications and then you don't have to add them in in your code classes anymore the only one thing is is that that works for installed packages so it doesn't work for package references so we still need to have to to keep here a reference to our total data access layer and we can't simply move it into the let's i don't let's try so last last time i played with it it did that this was not possible so let's try it once again and it's still not possible of course we still have this error here so uh yeah so if you have uh references to other packages then putting them in the global usings actually won't help a lot so yeah in this case that's actually it so we have right now this global usings which is very cool i would say uh could i have a brief description of what happened till now uh so yeah we actually want to build a minimal api in which we model a very very basic blogging platform until now we just we we have just uh well modeled our domain with with four different uh entities a very very basic data access layer with a db context and right now we are actually trying uh to actually uh create the end points that we want for this minimal api and we have added the db context to the minimal api and the random migration and updated the database so that's actually what what we did till now good um okay so right now we have here this map get which actually and let's let's try to refactor this so uh when we have an app get for api authors what i want to do here is we can actually we can actually uh make this async and we can actually inject here uh things that we need and here what we would need is the thoughtful db context uh thought will maybe context let's call it context so this is injected via dependency injection so it's exactly the same way that you can inject in the constructor of your controllers you can actually inject actually here in this lambda now that you provide in this map get method and that's actually very very cool and of course right now this has an underline because we have marked this as async but we don't have an await for now so let's make this very easy return wait um context of this should be for authors and pastor two list async okay this should be it good and let's also add another end point here map post in this case uh but then we'll see that this would be a little bit more complicated and this is also the reason why we will go into the refactorings and go to the vertical slices architecture and move everything out of this um of this program.cs class so we would have an uh endpoint api authors but with the post method and then uh here it's exactly the same we can mark this as an async here we can for instance have um once again thoughtful db context context and one more thing that we can inject here actually is you know in controllers for instance for posts you can just uh you can just define a parameter for your action and it will actually map to the body of the post request kind of automatically so this is exactly what we can do here but uh what is the problem here with all those errors uh type or name specification and okay i'm not exactly sure uh so i guess i guess we are missing no we are not missing anything because it's exactly let's let's give it all with oh it doesn't um okay that serve the ht4 http post request uh and here we'll have to specify the pattern and to delegate and that's exactly what we try to do here so this is the pattern and that's actually that should be exactly the delegate i guess it's because of this one no no still red okay so uh why is this still red only assignment call let's also delete this one ah okay so it was just of case of of of having the comma here okay good so um yeah thank you very much mohammed it was the comma indeed thank you very much good so i said here we would need to map to something um the vta i wanted to add this week name and we'll get into why we need to to add this type of of descriptions uh just in a minute but it it should also work without it but of course the wheat was uh was not completed so this was one of the reasons but we also need said to map here to something that comes from the body and here as said we want uh let's have here also for now an internal uh record uh let's call it author dto and here we can simply say um for the author what do we actually need we need a string first name string last name uh string uh string bio what what else do we have for the author uh the full name is something that we will calculate [Music] uh the date of birth but here date of birth that's a typo so first name last name bio and date of birth that's actually everything that we need so we just use a record for that so here we have then um date time date of [Music] birth okay so in this case we can just say here that uh map the body actually in our author dto and this is the author so here then in the body of this uh anonymous function of this lambda or this delegate we can just perform our action so we have to transform this author uh detail in an author but we'll use automob automapper for that just in in in a matter of minutes but for now let's just see if this actually works so let's have here of our um author let's make this detail because we'll have a clash new author but it's not author video is author of course we would have to add the reference or domain for that which is cool and okay and expected and then we can just simply assign properties uh author dot uh id should be uh author dto dot uh first name okay then uh author dot last name okay author dot bio equals authority dot bio and then uh author dot date of word equals alternate dot date of birth and this should be okay uh for date of birth we could use date only data type yes and i have talked actually about the the date only and the table and the time only struck in c sharp 10. however the problem is that entity framework uh is not yet able to support them even if i use the ef6 versions that are in pre-in pre-release right now i actually tried to do this uh well actually when i worked on on on playing with this one week ago and in fact uh i have also found an official statement that date only and time only are not yet supported but they will probably be supported with the release so yeah i guess we will we'll have to wait for that but the reason why i have chosen here a day time is in order to be supported with the ef because dates only and time only unfortunately didn't work but yeah i said back when we talked about this date only structs and time when instructed i think that these are some very very cool features uh or some very cool news trucks in in c-sharp because most of the times in my projects personally where i use date times most of the times i'm actually interested only in the dave part and this actually makes it easier for us to just work with the date part or a time part and maybe also calculate spawns and things like that so yeah that this is true but unfortunately it doesn't work for now with ef hopefully it will soon good so right now so that we have this author we can just uh simply then say uh context dot authors add and we add the author then await context save changes async and that's okay and for now i will see that we can also return different response types but let's uh let's just return uh the author for now now that's it so let's see if that if this actually works so we have a endpoint for getting the authors and we have another endpoint for creating an author so i guess we could test both of this right now let's uh let's run that okay so we have here the post let's try it out here is first name let's make here john doe bio and let's have this date time right now so execute and hopefully we don't get any errors uh we got an error okay i never occurred by saving the entity change you see the inner exception uh every column name date of birth okay but why ah okay okay because i have changed it property name uh let's add a new migration for that i have changed the property name so we have add the integration correct dob typo because this needs to be upgraded to the database right now it has see we have renamed column which is actually correct uh and update database will started okay done good let's run it once again and i would expect it right now to work okay so let's try it again try it out let's have a john let's have a dough here while whatever and the date from today execute let's hope for a better luck right now and indeed we have a 200 and we see that that should be here let's try also the get endpoint right now try it out execute so right now we should have one author and this is indeed the case so as we see for or as a basic proof of concept this minimal api is just working and the only thing that we have done is actually is in this um sorry let's close this migration we have actually have done everything here in this program file so if you are familiar with node.js that's really very very similar on how you would do everything in express you can have everything here in the entry point of the application and it actually works dependency injection works configures configuring services works directly on the builder on the service provider we can even add the middleware as we have seen we can bind or inject or this is actually not an injection but we can actually bind a post body here directly to a record which is fairly cool i like records a lot by the way now for working with this type of details uh they are actually great for my point of view records that's everything that you have to write and uh everything else is actually taken care of uh one thing that i want to do here is let's get rid of this weather forecast thingy that we still have here we also don't need this anymore and uh yeah we have these authors and we have this post and it actually works good so what i would like to do right now is i will i would need a small break um so uh i will go on a very very short break for 10 minutes and then we will come back and i hope that you would still be here because after the break what we will do is actually very very interesting right now we have a minimum viable working api in dotnet 6 minimal api but what we want to do already this file has a lot of code and you can imagine how messy this could actually get so afterwards what we will do is we will go into moving everything out of this file and we'll go into the concept of how you can create feature modules actually uh in this dotnet 6 and each module should be actually self-contained then we will also have some way to automatically register modules in the application uh without the need to register each services one at a time we can just discover modules and register them with everything that those modules actually need and we'll also go on uh through automapper and mediator because i said we want to go for this vertical slices architecture in which everything is a command a query and is handled by a handler so we will use mediator also and of course we'll use automapper to map from details to our domain models uh so yeah that's that's what we want to do we want to actually move everything out of this file and do some proper refactoring of this api in a vertical slices architecture so uh yeah that's uh that's actually what uh there is this question could you let me know what line 25 which name is edit for we'll go into that because we'll talk a little bit about swagger and we'll see that we have there uh different other things but very very uh shortly this is one way to describe for swagger uh what information it should actually look for when it would create the documentation because here we can simply use data annotations attributes that are specific for swagger but we can specify them here we have then a produces method and things like that we will go into that when we move our endpoints into dedicated files and then we can configure uh each endpoint with with all the features that it actually needs so we'll we'll go also into that after the break so yeah 10 minutes break i can promise you it won't be longer than that and then we can we can continue to refactor this with a more i would say production-ready architecture from my point of view okay i'm back again so you're still here thank you very much let me just check if everything is okay with the stream it seems like it is okay let's um let's move then a little bit forward good so let's start by by cleaning a little bit up here so what i want to do right now is to actually move everything away from here if possible and if we are looking a little bit onto how we can move move things around here is we see that we have this common uh service registrations that are actually well something that we can extract in one single extension method for instance and then we have all these type of middleware registrations that we can extract uh in another extension method on the web application so an extension to the web application class then we will have these two endpoints that will move actually in an author's module and here then we have this dto that we will also kind of move in the same module and we'll organize uh our our project so when it comes to the folder structures based on features uh something very similar to what we usually do in front-end frameworks like angular and react but that's actually what uh what this whole idea of vertical slices means so let's uh let's start with it let's add a new extent of folder here this will be called extensions and here actually we'll put some extensions that are i would say general purpose uh so what we could do here is let's have here a class where is it class and let's name this uh service collection extensions so we will need for this aesthetic class for extensions methods and for now actually i guess we'll have only one is public uh static it will return the iservice collection of course and let's call it here um add application services and of course uh we'll need here this dot [Music] i service collection sorry without a doubt and let's call this services okay and then we'll return our services but then what we can actually do here is we can go uh here in the program file and actually move all these type of services out of here into our class but here we also need the web application builder so uh we will need yeah that's no problem i would say web application uh builder and let's call it builder now everything should be fine of course here we will need another uh using to our data access layer and this should be good to go then and here in this program uh yeah we still need the data access layer because we need those here but instead of having a lot of different services we can just just do builder dot services dot add application services and we pass in the builder do it and using total api extension and that's it so and right now what we can do is actually that each time we will need to register a service instead of doing this directly in this program file will do this here so this is how or the first step how we will keep everything clean in the program.cs class here so we got rid of all the services which is a good thing to do and now we have to get rid of all these middleware registrations that we have and for that one we'll create the web applications extension so let's add a new class so and actually the refactoring that we are doing right now is something that you could also use on regular asp.net project because the problem in regular asp.net projects is that for real applications the configure services method in the startup.cs class gets very very very very big and what i like to do when when i well on the applications that i work on usually you register services from a lot of different layers from the infrastructure and from the domain service layer or use cases layer so in this case what i would like to do is to have simply or that each layer exposes such an extension method that registers the services in the configuration that it needs so in the startup.cs class in that case instead of registering each service you just call the extensions of each layer that will do the service registration and this is a way to to also keep the startup.cs class clean in regular asp.net core projects but also let's make this class static and here uh what we'll actually need is uh yeah is uh another one public that you can will return a web application and here uh let's call this configure application and here i said this would be on this web application an extension of the application and then we can just here uh return the app after we have configured it and theoretically what we could do uh sorry of course we need a variable name for that um what we could do right at the beginning right so right now is actually you can see that this map get and map post they are also on this app so what we can do right now is that we can move everything here actually in this extension method so let's just uh take it out from here let's move it into here and everything should actually continue to work of course we need here a reference the data access layer and a guess we still have an error somewhere ah we have here we need using to our domain okay and uh yeah if we go back to the program.cs you see now that we can actually get rid of those two not needed anymore and you see that uh how messy our program.cs file was and uh how clean it is actually right now we can actually even move this one uh from here although i guess uh that wouldn't be that easy because we would have to mark it also as but it should still work we don't have any errors and right now our program class we have just nine lines of code right now in our program.cs i would say say that this is a pretty successful refactoring now how messy it was before and how clean it is right now but of course we would also hear um app dot how was this method called configure application and that's it so if we run the application right now it should work exactly the same way that it worked previously so let's let's run it by the way whenever you have questions or you want to say something just feel free to use the chat i am really excited when when we get a conversation going so yeah we have this vlogger let's test only one of the end points to make sure that everything works but it should work oh or okay it just took a little bit longer execute and we see that we get this author that we have created previously so it works so we have done a successful refactoring now the next step is say we have here you know we really want to get this uh i said fully into vertical slices and so we have features and each feature should be self-contained it should contain a module that should register all the services that it needs it should uh i don't know register uh or all all middleware that it needs all end points and things like that and this idea of working with models is it actually comes not out of the box but as you will see it's actually very very easy to implement the idea of modules so and we'll even try to build a mechanism that would automatically scan for modules and register them and we'll see how how this would work uh so let's let's start to set this this up first so we'll need a new folder here and it would be abstractions and it's directly into the project because this is something that relates to the entire application not only to a subset of features so it's it it's actually something that that actually belongs to the entire application so let's add a new class here actually an interface and let's call it i module public interface i module and here we'll have actually two two methods so we wanted each module when we want to to register it we want that it would be able to actually register all the services that it needs to map the end points that it needs and of course to also register if needed any application middleware so in this case i would say we can expose two methods here web application builder okay and let's call this register module and it will get and web application of builder so this method should then simply return the builder after it configures it that the way that it uh it actually needs and then we need to map the end points and here we have uh end points in the minimal api are exposed uh to the interface i endpoint route builder map endpoints and then we would return the same okay so that's uh that should mostly do it now we have defined this interface for what actually a module should do now one other thing that we could do here is uh we could write some extension methods uh to register the modules in our applications so let's go back here to this um folder of extensions and uh sorry but i don't want a new folder i want to class here sorry for that so let's go back here by the way can you still hear me is everything okay seems to be okay i guess good so uh let's create here a new class then and let's call this class and we'll see that we would need to make this class uh static because we would have extension methods in it and uh first of all here what we would need is a private field that would hold the list of the entire modules or the the list of all modules that we discover in our application so let's have here pub a private static uh read only that's what we want but then i want to have a list of i module and we can just simply initialize it to a new list so that we don't have an empty list here uh but no not like this i want to do this with the using okay but why is here no okay let's see if we can add this to the global using so it would be a global using will be uh extensions now i guess you can add only packages to the global usings okay so let's go back to the module extensions and let's try to edit manually because i'm not sure why intellisense doesn't uh allow me how to do this using [Music] portfolio api extensions okay but it's not extensions it's abstractions solely sorry okay good so it it works now and this would be new list of my module so that would be for the private build good um thinking right now uh of course we need to give a name to this field oh my god uh let's call it modules okay so uh let's try once again to move this to a global using to see if if it works it works we are here on the module extensions yeah it works but that's kind of cool we can keep everything clean isn't a global extension it should be like total api extensions uh yeah but it should be not in the extensions it should be in in abstractions because the interface is in abstractions the class is in extension so it was uh yeah i i wasn't uh careful enough but it kind of works with the global usings right now so that it's kind of cool okay then what i want to do here is first add the private method here that would actually discover the modules and put them in this field here one by one so let's have here a private and it would return an i innumerable of i module okay we don't need anything here first we need to give it a name this uh cover modules okay so uh in this case we will do some magic here we'll use some of we'll use reflection to actually look or scan this assembly for classes that implements the imodule interface and then we can create instance uh of of those classes using uh the activator in reflection and then of course we can cast that one a module and add uh it to the list uh so what we'll do here is let's say return um and let's um type off i module and on the assembly i want to get types and then i want aware cool that you actually can combine the power of link or link you with abstractions and here for instance i'm looking for a module uh where module is class and very very important is that module is assignable to an eye module so this is how we actually uh check which classes implement this imodule interface okay good uh and then we can run a select and use the activator uh to create an instance on each of them and last but not least we can cast them on i module and this should work right now uh okay good so right now what's the problem this government cannot uh declare instance members of course we need to it to be static because we are in a static class because it holds extension methods and uh yeah that should be that should be it now let's have here let's implement in these two extension methods that we need so the first one would be public uh web application builder because it will return the builder register modules this dot web sorry it's not dot it's web application builder and we'll just return the builder at the end but until we return the builder we actually need uh modules equals discover modules right now we have a list of modules okay what is the problem here uh is not not here okay but why is this red okay doesn't match target type list of eye module okay so we have here uh hmm yeah but i i would like to call it list because list is already unenumerable so we return here an innumerable of my module and the list is already an innumerable so the problem here is with something with a nullability check somewhere so let's look into it nullability of reference types in value of type i innumerable i model doesn't match target type of i module okay um but if we make this nullable it doesn't really change anything in this case um in my opinion that's purely a problem with some nullable reference types here um module is not not here yeah and i want static read only field cannot be assigned to except in a static constructor or a variable initializer okay but this method is also static so that's kind of like a strange thing oh so list of i module and this returns an unknown variable will this maybe change something still no so the idea with the list here with adds range yeah but theoretically this already returns the innumerable so we are actually not iterating through it hmm let's see so we get the type we check if it is a class and if it is assignable to i module and then we create an instance for that and we cast this to an eye module so remove redo oh my god oh my god yes i'm so accustomed to use read only that uh yeah can't simply convert from type i number i numberable of my module two at least but okay but once again let's add the cost here but theoretically this shouldn't be needed okay what's the problem here here this should be static of course and if it is static okay and it still doesn't work um okay here i guess if if i do it to list still doesn't work uh so we have here a list of i module innumerable of api abstractions i module to system collections generic still the same okay let's let's use the explicit cast and let's see if that works because i i'm really not sure exactly yeah i i used to list but um that actually uh didn't change a lot so let's uh let's actually try to work this further so let's have here of for each and here for each module in modules we know from the imodule interface that each module has this register module and this map endpoints method and will simply invoke those methods that's uh actually the whole point of that so we have here a module dot uh register module and we'll have to pass in the builder in order for this to be registered and then um you know what i know what the problem is i guess i'm too tired oh um the idea here is uh that we here actually return an i innumerable so we can iterate through it afterwards but then actually when we do the for each we we actually execute it um but that's actually uh yeah i i didn't want to change it to a list i i wanted to keep it as an eye enumerable to to adhere to this certain interface but list is actually it implements the innumerable interface so now that should should have um or yeah it should have been possible for that but uh yeah let's let's try to make it uh like you suggested we have but in this case uh we have to call this this to list and here modules equals discover modules and in this case module is a list of my module and yeah that should actually that should actually work um good and then we return the builder and then what we could also do is uh we need another method for the endpoints um yeah i list or at least yeah i list would be the interface list is the implementation that uh it wouldn't really change a lot uh public uh let's add also the other one a public static um this one would return a web application let's call it map endpoints and this would be on an extension method on web application not on the builder and it would be then let's call it app and here what we can do is once again for each module in modules we can just use module dot map endpoints um my module let's yeah we should pluralize that because it's it's several different uh end points that we could use uh so module.map endpoints there is no argument of course because we have to provide the app that's why we have this and then we have here return app so everything should be okay right now right now what we do here here in this register modules we should actually discover all the modules and then we should uh run the register method for them and then for all the modules we should actually also map the endpoints and that should be okay so what we could do here then afterwards we can go back to our startup class sorry in this case it's you see how um how customed i am with the startup placement asp.net core in this case it's uh it's the program class and what we could do here is uh simply we could do here builder dot register modules and of course we need to okay that should be it and when we have the application what we could do here is after the configure application we can simply say app dot um how did we call a map endpoint so we have mapped everything and this theoretically should register the services for our modules and then also map the endpoints for that so this should be the setup uh in map endpoint don't we need to initialize module discover modules critically no because as this is a static class which means that we have theoretically uh well globally accessible variables of for this class theoretically we call this method first and as we give value to these modules this should have the exact same values or the models when we call this method afterwards because it's it's static actually it doesn't get disposed um that's actually the whole idea of statics so that's at least the theory let's let's try to implement an author module and see if if it actually works but i guess it should work so my guess is that it should work since everything is static here okay so let's uh create a new folder here and let's call this features and here we will have another subfolder it will be called author now for the author what we will do here is we will actually first start up with a module for the author so uh let's create a new class here and this would be a outdoor module just to make sure that it is really a module it will also implement a module which is actually very very interesting so what we actually do here is we need to also provide an implementation for those two methods implement interface now um what exactly we should do here is well in map end points of course we have to map the end points that we actually want and then uh what we want to do for a register module is add services that are specific for this module or even actually resolve services that we might need in this module so right now i guess we don't need any exact service here except maybe but that one we already have it's it's the the thoughtful db context so in this case in the map endpoints is what we can move from here so this app map get and uh map post so actually that's what we can move from here so let's uh where where does it okay so we need we don't need a return right now we just need these two ones so let's simply remove them from here because we don't need them and let's go to our author module and in map endpoints let's uh let's add them here let's then also return uh how did we call it not f but amp endpoints okay so in this case we have to change this because and here we need a thoughtful db context as using uh here we will also need endpoints uh then we also need the author dto here so let's uh let's go here and just move it but you know what this could actually be in a dedicated class so the whole idea is that when we have a feature everything that belongs to the teacher should be actually in that specific folder so in this case we can just simply add here a new class and let's call it uh author uh dto and of course it won't be actually a class but it won't it will be our record oh sorry not this one uh so where are we here okay so let's go to our author detail and just move this here could even be oh private not in this case but if we would add a nested class to the author module we could even make this uh is private so then we have the author module we have the author dto which is okay right now and then uh we have what is your problem here okay so what is can be simplified yeah but i have an error here okay they want me to use to use an object initializer but why do they give me this as an error i guess i'm not sure why intellisense here it's also um a preview visual studio 2022 uh full domain models so i'm not sure exactly still not that's strange hmm needs to be public what exactly needs to be public i guess maybe that question was maybe for a different topic that that we discussed uh but i'm still not getting exactly why do they throw me an error here his name space but i guess there is a typo somewhere here from my side author record yes the record we have we have it here and it is internal because it's only used internally to this uh assembly it actually doesn't need to be public and actually if i look here in this author module the problem is is not with dto it actually it points out to the correct one so it's it's uh you see that it's moved to features and the uh author folder so this one is correct but this is actually my domain model is a namespace but it's used like a type how could this be a namespace oh my god i guess i know i know ah that's so bad that's so bad um let's call this author picture this name space and then of course the author dto author picture yes it's exactly it's the namespace that has the same name as the class that was the problem uh yeah sorry for that um and right now it should work here correctly so right now we have mapped these endpoints and we have done this here now okay uh here right now in register module here is where we would um add configurations that we would need to add uh to the web application builder or register services that are specific for for this module and unfortunately here right now we don't have anything to to do but we'll do here something uh just in a few minutes when we will add uh the auto mapper and mediator but for right now actually it works so let let's run the application but let me put some break points first because what i want to see here i want a breakpoint here i want a breakpoint here and i want a breakpoint here it it was the same name as the class because the namespaces are actually generated automatically after the folder and the folder is named author and our model is also named author so it kind of didn't know exactly what to do with it but right now we have changed the name of namespace to be a author feature so yeah that's um that's how we solved it so let's run the application once again and see if we hit those end points here that we have defined so okay so we are here in this first one and modules count one so it actually worked because you see that we have our module here so that's actually cool and for each of our module we call the register module and that's it okay then let's move configure application service map endpoints we also get into this method which is okay and you see that everything worked fine and this is exactly because we have that as a static field so once it it gets those modules it's it's like a global variable this is how static works and this is why we have to avoid static but when we work with extension methods then we have to define them in a static in aesthetic class and use static methods and things like that so yeah but this is actually why we we should avoid use use static a lot so uh on the other screen i have right now this end point uh but swagger but i just want to execute it and in fact yes i can see that we have arrived here so it's actually still working fine good and okay so we have uh we have the authors list and click on continue and yeah so everything works after this refactoring so uh right now we have managed to see here is the result so we have managed actually to refactor everything just a little bit more and actually bring in this whole concept of modules uh and where is it so basically this means that each time we'll create a new uh a new class that will inherit from imodule we'll of course need to implement those two methods but this means that they will automatically be registered uh for the services and then the end points with these two lines of code so no matter how many modules you would have in this application you don't have to add any other lines of code here in the program.cs file so this is how once again we could leverage this idea of of using modules and automatically registering them to keep this program.cs file clean because right now as said once again no matter how many modules i have in my applications i will always or these two lines of code will always be sufficient so i won't need anything more than that and yeah i guess that's uh if there are any questions or thoughts or or ideas i don't know just feel free to uh to go ahead with them and then i said that we want to actually do some further refactoring on this author module actually and what i want to do is uh to move them towards this idea of of using uh mediator and the crs pattern so working with commands and with queries but unfortunately uh nature calls and they have to to take another small break and i will be back here as soon as possible to continue with implementing uh implementing mediator and mapper and uh wiring everything up together and then going through uh through all the other endpoints and i guess that this stream will will be fairly long because i just want to cover a lot of other stuff here like for for the blog as you might uh as you might already see from this structure that we we have here in our domain model we would have a lot of nested resources and then inside a module because the cool thing about this uh this using the this idea of modules is that do you have very simple modules like the uh author model where we would have a simple crowd then you can just simply add a very few files you can basically even add everything in this one author module file but if you have some more complex modules like we will have for the blog then you could actually also introduce the concept of end points and then have all end points auto register themselves so yeah we'll look into that but as i said i have really to take a break and i will be back i guess in 10 minutes at most and then we can continue to uh to work with that so i hope to to still see you then after the break so i'm back again sorry for this interruption hope you can see still see my screen and everything is okay um yeah let's see how we move further let's just make check if everything seems to be okay with the stream and well it seems it is [Music] okay yeah seems to be fine i guess good so as i said what we want to do here is first of all move towards mediator and auto member so that's exactly what we will do right now and i guess we'll try to implement uh this mediator or cqrs uh style here for authors and probably that would be it for today but we'll continue um then uh with uh with this series of course because there are plenty a lot of other things that i would like to show you how we could use them uh maybe methods and not lambda functions and um and the other similar stuff and how we can actually describe better to swagger to swagger what it should display so uh yeah i'm sure that we will have at least one more stream in this series uh good so let's get started so we would add for this some new nougat packages so we would need a mediator uh okay why okay it just was a little bit slow now here we just install the latest version so this at least for now this doesn't um have a direct dependency on the version of net that we're using so that should be fine and let's also add automapper um but we can add actually autumn auto mapper extensions microsoft dependency injection which will automatically also add the auto mapper package so let's just install that and that should be fine good so now what we have to do is of course add the mediator and auto mapper services and for that we have of course a global we have this global um not global this service collection extensions so this is where we will add those so what we need here is builder dot services and here let's uh add a med d it r should be okay then of course we need to import uh let's um let's do this in the global using actually global uh using mediator okay and here of course uh is that we need to provide an assembly or an array of assemblies in which uh made in in which mediator would actually scan for uh for classes that implements the i request uh interface and the eye handler uh uh interface it's actually how how it works and then uh you just see here uh say here that type of um program so we we give here this program.cs class uh but why do we still have okay probably okay um i don't want to add this uh maybe not sure do i have a typo here um that's actually strange because i'm not sure why this is not happening here let's also end here let's try also with the auto mapper okay this one it sees and auto mapper in here once again we have to provide an assembly and it it would actually um look in into the entire uh assembly where this uh class is for classes that actually implement everything so why did ed automapper work and add mediator not work um let's let's check the packages because i knew that when we installed the automapper dependency injection package it would automatically install also mediator yeah it installed it but i guess we need this auto mapper extensions the global usings i guess that is the problem so let's um let me go back to the global usings uh was it uh mediator no not pipeline i was the package named once again packages auto mapper extensions but this is for auto member not for mediator i guess we need also for mediator uh a dependency injection okay sorry for that uh sorry for that need to download the mediator from yeah i have already downloaded mediator but what we actually need to do is it should probably have also a package for dependency injection because the blank mediator probably doesn't have that uh yeah you know mediator extensions microsoft dependency injection it's exactly this one and if i would have installed it this one like exactly the same way that i did for auto mapper then it would automatically install also the mediator package and everything would have worked correctly but once again i was not careful enough so i was careful for for auto mapper but i was not careful for um for mediator uh and let's uh let's go back here to this where okay add mediator and what is the problem right now using mediator yeah correct so let's uh let's make let's bring that to the global usings global using mediator and this time it should work yeah no error anymore so good so that's actually what we have done here but then i guess we don't have to add anything else so that's actually everything that uh that we would need now let's uh try to move uh to this idea of um we have here this uh author detail and i guess what we want to do here is to well to make a distinction between this author uh dto that is uh actually for post and let's create another one which would be an alter get detail although i guess we we don't need this in this case because for now let's just look in into the author class so for the get we actually want to return all the information that we have here and we want to return it exactly in the format that it is right now uh so in this case i guess we can just return it the reason is for gets you usually also return the id because of course that single page applications will rely on this information to then get information about this specific uh author only or use it as a query param or things like that so forgets we really really want to to also give that id but for posts uh what we have here in this author detail we actually don't need to do that so yeah that should actually be okay but what we would need to do here is let's create a profile for automapper for author because we want to map from author dto to an author so yeah this is why we need to create this profile so let's add a new class this is a very standard configuration for uh auto mapper and let's click the let's name this author or profile and it would inherit from profile and here it doesn't see it uh let's add also automapper to the global usings global using automapper i'm not sure that it's okay to add everything here to the global using but i really like this feature so this is why i tend to add uh everything that i can here in this global using because i i find this cool okay so uh where is the profile here is the profile and uh here what we actually need is a constructor and in the constructor we need this create map and here we have to specify the source and the destination so we want uh from the source it the source would be the author dto because this is what we want to do is transform this author dto into an author to api features okay this is where on the dto resides and this uh [Music] once again i guess i have to edit manually using helpful domain model okay but it's the same problem as previously we have to rename this namespace uh and so we have created the map and right now we don't need to do any special configurations because in auto detail we have first name last name bio and date of birth and in the author we have first name last name now we have also full name but then auto member will skip that uh date of birth and bio so i guess that's um it's okay but that's actually what uh what we also we don't need to further configure this uh which is actually good but let's also use a reverse map if we ever would like to map on the reverse way so from author to the author dto but for now i guess that's fairly unlikely uh and yeah this is how we created the uh auto mapper profile and that's it it's really nothing more to it we can jump we can now just simply use that now uh right now in order to be able to use uh this mapper and the handler what we need to do is actually we need to inject them uh one way or the other in our in our module so let's go to the module and here what we will have here we we will need two fields for them but in this case they won't be read only because we cannot inject here in the constructor uh so we have an eye mediator which will be the mediator and we have an eye mapper which is actually uh where is it mapper and where we can actually do that is in this method that we have register module because here we have the builder and from the builder we can get the service provider and from the service provider we can resolve the services that we actually want so uh let's go back here and um yeah for our provider equals builder services build service provider so this is how we get the provider and then uh i said we can just uh request the services and then it would be the mediator and this would be equals to provider get required service and we use the generic version of this method so in this case for the mediator i want service of type mediator and then for the mapper provider dot uh get required services and here i want an i mapper so right now i have this uh this mediator and the mapper so okay what is the problem with this of course sorry it's not here but it's generic do you want eye mapper of that good so right now we have those two services in our module so if you want to uh to get some services from the from the dependency injection container here in your module this is one way that you can do it so yeah that's that's pretty straightforward i would say uh just uh please here be attentive that at least in this setup right now and um once again when it comes to this idea of modules this is something uh that's that's very very easy uh right now but it's not something that it's uh totally uh let's say a future proof in real applications because one problem that i would say and uh or a problem that i would see here and that i haven't handled uh yet but probably will do this in another stream is that if you need scope services here scope services actually the problem is that they want this be disposed after the first use because this um these extensions since they are static here you would then register the services but you would register them in a certain scope you would have to use the i-service code factory and get the scope and this means that as soon as you actually finished with that scope and you have resolved the services then it means that well in that meantime basically after that the services will be disposed so those would be back to null wherever we then want to use them so yeah injecting scope services here is actually not something that uh that would totally work i guess uh but we can uh we can inject for instance scope services here in each in each method but uh yeah i said this is a point that uh that i still have to to figure out what would be the best way to to handle it but transient services and and uh and singleton services you could uh add without problems uh using this way good so let's let's see now how we can move uh to use mediator uh let's start with the create so for that one we actually need a command so in this case we need to create a create user command so let's click add class create user command and this is well very specific to uh how mediator works uh actually we have an interface this which is the i request and it's an i request of author because this request uh will return an author author feature let's rename the namespace again and in this case we can then just add the using and then here will actually in in this comment uh we can actually just set properties for everything that we need in order to process this this command in uh in a handler but for now what we actually need is just the author dto okay and then let's call it author get and set okay what's the problem with you uh okay declare is nullable but why would i want necessary it to be nullable or why doesn't okay let's uh let's look a little bit what is the problem here but uh ah okay author auto dto is less accessible than uh create user command because this is public and that one is internal uh so yeah we could uh we could also make this internal but i'm not sure if how how um a mediator would handle that so in this case we can just uh make this public also and then the problem should be yeah indeed okay and then the next step is that what we need is to create a handler for that so and basically everything that should happen here in this um in this uh handler now uh here we can just add a new class for the handler where is it class here and let's name it create author of command handler and here to make it a handler it actually need to implement i request handler and here actually oh sorry this this is also a generic one and we have to specify that this one is a handler for what class in this case it's a handler for create uh author command and the return type so it would return an author okay now uh here in this one we can actually use dependency injection so in this case we can use private read only [Music] out full db context context okay and we can also we will also need maybe the eye mapper here uh probably we need the imaper here and and not the in the module itself no in this case private read only my mapper member so the idea is for for the scope services uh from my point of view here in the module itself you should require as less services as possible because all the services that you actually need for processing the request should be in the handler and in that case you can simply inject via dependency injection which is okay so yeah let's let's go back to this command handler and yeah we have this this automapper what is the problem here cannot be used as a type parameter uh for t request in the generic type of method okay there is no implicit reference okay from create auto command handler to mediator request thoughtful api features author uh okay because author feature once again the problem with the namespace mostly i guess in this case it's just just lazy okay and here is the let's let's also inject everything and um what will they be context context and my mapper mapper so yeah let's assign to the fields okay that would be it for the dependency injection and then i'll implement interface so this would be the handle but once again i still have this error create auto command handler cannot be used as type parameter oh my god okay because here we have to specify the command that we have and the command would also be it's in the author feature which is okay so we actually need is there a typo somewhere oh i named this create user why did i do this and you didn't say anything about that um okay so yeah let's uh let's rename this create author yes rename everything and then go to the command handler then this is okay i request handler of create auto command and author what is the pro does not implement the interface okay so let's um let's remove this and let's try to implement it again okay and now it should work good so we have here this uh this handler and here actually what we need to do is uh move all the logic actually that we have here in the module for the post there is the post here we have actually to move it in our handler so let's go to the handler and the logic would be uh slightly different so here what we will have the idea is that in the comment we would have all the information that we need to process this is the whole idea of working with commons and with queries you you can put here really all the information that that you need for this handler in order to handle uh this this certain command so what we have here is a var uh to add so which user we should add and we can use a mapper already to map to an author of our domain model and we can do this from my request dot author because there is the author detail uh so why is the problem here with this mapper mapper of course mapper dot map i guess i'm too tired okay good and right now what we could do here is then simply on the context on authors dot add and we uh to add okay and then what we could do is simply await context.save changes async then we have to return an author as part of the interface and right now if we return this author uh to add so if we return this author it would also have the id right now uh because when we save it it would get the id from uh from ef core actually from the database and uh yeah we should have all the information there so this is the common handler and it is implemented so we can go hop over here to the module and here uh in order uh here we have uh the mediator and the mapper we actually don't need the mapper here but uh yeah for now or not we'll keep it i guess uh okay so in this case what we would do here is that we would uh still use those two but here in the body we actually don't have any type of other logic we just use we just have to create the command um bar command equals new create author command and then here we can just uh use an object initializer i guess and the author would be equal to the author dto that we get from the body so that would be okay and then the only thing that uh we need to do here is uh var edit equals um mediator dot send and we send the comment and that's it uh from now on mediator knows uh to find the handler actually to execute or to handle that command and everything should be fine it should return the user and then what we could do here is return return edit and it should be it actually to make it simple and to actually not allocate a special variable as we know that this returns exactly what we need we can just return that and that's it so basically we we have actually made our our function here that maps to this endpoint actually containing only two lines of code actually which is fairly cool so before we test things out let's also implement a query so here it would be a class so we have we get all all the authors so uh get all authors let's use also the query that we know that it is a query uh however it's still it's it is it still should uh just uh implement or use the interface that i request off and it would actually return a list of author i would say and it's exactly the same thing let's name this once again to author feature and then we'll be able to add the using at the top and in fact for this query we actually don't need to pass any information to it so we can have it empty but the idea is that the handler should know what to do here you could pass in for instance some filtering options that you take from query params like i don't know um if you want only certain authors filter by first name or if you want to order them or if you want paging so all this information would need to be written here in in this query as properties so that we would have everything available in in the handler to handle uh that specific uh query now in this case it's just very simple because we just return the list of all authors for now so we just we don't actually need to implement anything here but what we would need to do here is implement the handler for this and get all authors handler and let's rename also the namespace here once again we make this as um handler by uh specifying that it is a i request handler and they said this is generic first we have to specify what type of of a command or query we handle and this case is get all authors query and then what should be the response type for it so it should be a list of author okay what is the problem here right now just did something like that um but uh let's go to the commander guess something but it's i request handler what did i uh do wrong here i guess what i did wrong is let's uh let's go to the query once again so get all authors query it's an i request of list of author which is okay that's strange once again because that's not from the data services and mediator it should already have that so what am i doing actually wrong here it's really strange um let's go in the comment handler once again it's exactly the same thing request handler it's in mediator mediator is already added as a global uh using this is the query which is an i request of list of authors of what it should actually return it's exactly the same that we had here so let's check in the chat maybe you have some ideas but no i don't have oh my god yes thank you very much yeah i'm definitely too tired but i guess we just need to implement that and uh then we try it out and um but here once again uh we'll need to use dependency injection thank you very much wolfgang that was actually yeah i was looking at it but i was not seeing it good so uh yeah what we need here is a private uh read only it's not an i what do i need here is the thoughtful db context we need to end the using for that and um i guess it's actually everything that we would actually need here in this one we don't need anything else like the mapper because we don't need to map anything uh good so let's also inject this here and assign it okay and actually here that's very easy we just have to return weight context.authors sorry uh dot to list async and that should uh be it so that's that's okay so now if we go in our module itself we can actually replace this with uh return we just uh yeah mediator send and as we don't need to pass any type of properties to the query we can just say new uh get all author query and that's actually it so it sends it and it returns the result which should actually be okay for now good so right now we have implemented this whole concept of of mediator let's run our api again and see if if it works if it still works i guess it should work do we still have breakpoint somewhere no it just started a little bit slow but well the first thing is that we still see those end points here which is okay so okay um it seems that i should have theoretically some problems with uh with the stream so let me please let me know if you can still hear me correctly uh okay let's uh let's first run again because that should already work okay what what what's happening here we have an exception no we don't so what what happens here my swagger got uh straight refresh that okay so something happened here let's let's run it again that was not a good sign so let's just try again then and hope for the best now it's still still freezies and i really don't get exactly why we don't have any exceptions here so from this point of view everything seems to work fine uh we maybe have a breakpoint somewhere that we have forget to remove so we don't have a breakpoint here we don't have a breakpoint here anymore we also don't have a breakpoint here so yeah i really i'm not sure what uh it's just freezing so i'm not sure what exactly happened with uh uh add async in front of panda implementation uh is that it was that not added by the okay i know what you mean oh my god that is the problem because mediator is async and actually all our handlers are acing thank you very much good catch we were just waiting and waiting and waiting and we were just returning a task to swagger of course that um that was not funny at all okay one more try at least it gets further try it out execute and we get the author so this one worked correctly now let's also try the post let's um write out let's make this time jane though a public async task handle yeah the handlers were already async the problem is that we were not awaiting them uh in our endpoint methods that was actually the the problem the handler methods are already async so we have created the author and we see that it's jane doe which is correct with id2 and let's also run this list again and we see that right now we have two authors so uh gabriel let's uh let's look into this so the handlers were already acing and we were already awaiting the context so at least for this command but also for for this one we were already waiting here so the handle was already async so that was not the problem the problem was that we also had to await this here so we need to await this before we return because otherwise we would just we we were just returning a task to swagger and it basically we never know when when the test completed and and things like that so the problem was that we need to to add the await keyword here because when we run me mediator send that's actually here and asynchronously send a request it to a single handler so the problem was this awaits that that was actually missing in all the handlers everything was okay good so now i guess that's uh we should call it a day for today but we'll surely continue this live stream as soon as possible now not sure uh probably sunday evening would be something or or monday but uh i'll try to do it for sunday evening because there's plenty a lot of things that i want to do i want to look at endpoint metadata i want to look at replacing actually this here uh with methods so that we can just run a method here not right here the entire anonymous method and then we would also have to look into how we can handle a more complex module like the blog module in which we would have also to introduce the idea of endpoints so for each endpoint we would have a different class that would automatically register the uh all the end points that it actually needs like for instance this map get and map post this won't be part of of the module itself but it would actually be deferred to the end point to do to do the registration so our module would kind of like be something like a dispatcher and say to each endpoint in the module hey please uh please register your your endpoints here and uh yeah and we'll move the entire logic then in each uh endpoint implementation we'll use then we'll look into well how we can describe better with with how we can describe better each and end point with metadata that actually swagger can use in order to um to um to draw the ui uh so yeah i guess that's uh that's plenty of things that uh that we still want to do here with this api and look also at how we handle nested resources and and similar stuff but one other thing so or as a summary once again the most important thing when working with minimal api just always try to clean this program.cs file as clean as possible so you see that even after all this code that we have written our program.ts has still 11 lines of code and no matter how many modules we will add here in our applications it will still have 11 lines of code which is from my point of view very very very important and try to to move code into as many classes as possible to keep every uh to keep everything clean readable and easy to to maintain but that's the whole idea of this of these vertical slices like author in this case is a vertical slice so we in this one we contain all the the classes that we need we have the dto we have the mapper profile we have the the queries the commands and the handlers so whenever you might have a bug for instance that i don't know something doesn't return right then you can actually simply just come here and to know that the problem should be here somewhere but it's actually very very easy to to pinpoint or to to troubleshoot or debug problems with this type of architecture and by moving a lot of of of of the logic that we have for for processing the data in the handlers we actually what we have achieved is that we can get rid of actually two layers like the repositories we don't need repositories anymore here for for this one and the service is there we don't need services anymore because what a service does here is actually only here in this handler uh basically if we wouldn't have this handler all this method here and uh this method here would actually be in an author service and we would end up having an author service class with thousand lines of code when we implement everything where it would be very difficult to find uh something if needed but in this case in in each handler we actually execute only the logic that we need each handler can then evolve independently it doesn't depend on anything else we don't depend anymore on on a lot of abstractions which uh which is actually something good i i know that uh theoretically and also practically in in the normal layered architecture abstractions are very very important but using this type of of setup with vertical slices you actually don't depend on on things the only thing that you depend is is the database and then probably your your domain layer and that's it and everything you put in the domain layer can easily be unit tested so you don't have to run uh integration tests on that so of course then you would also don't need to use a lot of different type of of uh abstractions between layers so overall it it gets it gets really more simple from my point of view and it is easier to understand and of course to to maintain everything because if if you have big services the problem is that at a certain point you have methods that actually service several different controllers and then in a certain controller you need a change then if you do a change to the method in the service then all the other controllers break for instance so in that case you then just add another method in the service which does mostly exactly the same thing as the previous one except that it has one less parameter for instance so it really gets uh gets messy with with the service layer but in this case everything that we need is encapsulated in only one handler so you don't depend on other methods of from services you have everything that you need here in this only one handler and this is a very important thing from my point of view okay then uh thank you very very very much for watching it's been a three hour stream so uh yeah i'm glad that you were here um also then uh please subscribe to the channel if you didn't do this already uh so to just keep track when we'll do uh the next live stream and continue uh to build this dot n6 api thank you once again very much and i really wish you a very good evening or day depending or where you are so see you next time
Info
Channel: Codewrinkles
Views: 925
Rating: undefined out of 5
Keywords:
Id: U06SgUkIdEU
Channel Id: undefined
Length: 188min 43sec (11323 seconds)
Published: Fri Oct 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.