Clean Architecture with ASP.NET Core by Steve Smith | BRDNUG June 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello let's see is this working is this thing on all right hey everyone welcome to our june that's right june baton rouge.net user group so looks like we have some new faces in the crowd i really appreciate all of y'all joining us if you don't know who i am my name is brian mccoy i've been running or helping out with the user group for the past couple of years we have slowly transitioned into streaming so i think all of our our user group members who have followed us here so let's see tonight we have a very awesome guest for you i am excited to hear and speak but before that we'll do we'll do some typical uh house cleaning again my name is brian mccoy i'm also joined tonight with jeremy cronin he's been helping out with the group for a while um you may have recognized the name jeremy this week is jeremy cronin typically jeremy knight is my producer behind the scenes you may also notice the new layout so we are actually making the switch to to streamlabs so hopefully it helps to eliminate some of the some of the issues that we've had in the past so we'll continue to try to make the stream better for you as best we can so for tonight please utilize the twitch track um we also have a discord channel if you want to join us in there we will be monitoring both for questions so myself or jeremy will relay those to our speaker um yeah if you're looking for ways to get in touch with us you can always follow us on twitter or facebook the links will be below in our social our social media um section you can follow us on twitter at brdnug um please you know reach out to us if you ever want to come on stream if you ever have something that you want to present this is a community channel we would really love to have you on speaking of being a community channel this sunday morning we will have another sunday short uh two weeks ago i was joined by a good friend of mine named jake we did some f-sharp stuff it was really entertaining and a lot of fun if you watched that stream or the vod on youtube let me know he would be happy to come back i think we're going to do some more f-sharp stuff in the future we had a lot of good feedback about that stream so that may be something we're looking to do so let us know let's see what else again we ship all of our vods uh from twitch to youtube you can find all of our past streams there be sure to go like subscribe you know whatever you do on youtube um let's see jeremy is so kindly posting links in the chat so i appreciate that we have a facebook group uh like i said twitter twitch youtube discord we're everywhere that you can find us let's see what else do we have oh teals so teal's organization is has come to louisiana and i believe they they may still be looking for volunteers if nothing else i would really like to extend my thanks to the community um lucia has had very nice things to say about the people in the baton rouge.net user group i believe a third of their volunteers have come from either just direct volunteers from our user group or our user group spreading um information about teals coming to louisiana so we have a lot of good support for the teals organization coming directly from this community i really appreciate that that's what we really want to be here for so thank you so much for that let's see i don't know if we have anything else um it looks like our viewer account is slowly growing so this is exciting uh i bet it has something to do with our speaker but that's okay because that's why we brought him here but i would like to introduce to you our dallas so our steve smith uh how would you like to be referred to you sir so i respond to either it's fine okay awesome awesome so what are you showing us tonight we are going to be talking about uh clean architecture with asp.net core awesome i really appreciate it favorite topic of mine it's it's actually a favorite topic of mine i've actually been using it for a few years now um so i really appreciate the info you put out there for us and without further ado i'll let you uh take the stage awesome um thanks a lot i'm glad to be here it's not quite the same as traveling around and seeing people in person um but we're almost there um so maybe maybe soon i'll be able to come down and visit y'all in in person um for tonight my my plan is to talk about clean architecture with asp.net core as i said as you can read if you don't know who i am my name is steve smith if you don't know me you probably know someone else named steve smith because there are like thousands of us um and so i go by our dallas online uh mostly so that i can actually have a username that's consistent across different places and uh people can actually find me in a sea of other steve smiths uh so if you're looking for any more information on me afterward um you can find me on twitter github ourdallas.com etc all all under that name um let's go ahead and get started i've got a few uh resources i want to share with you before we get into the the actual topic so forgive me for a little bit of uh of self promotion here um but hopefully some of these things you'll find useful uh most of them are free so i i have a bunch of stuff on pluralsight uh and so probably easiest i got tired of updating the slide um with like the most recent courses let me just throw this up here if you have a pluralsight subscription you can get access to all this stuff obviously if you don't you can sign up for like a 10-day trial with your email and watch stuff or if you want to email me um i can usually get you like a 30 day pass even if you've used a trial before so if you really just want to watch one of the courses that i'm sharing here with you just reach out and i'll try and hook you up my latest course was actually just last friday which is a c-sharp generics best practices course and and that was a a ton of work to get done because i didn't start it until after i'd shipped this ddd fundamentals update with julie lerman and that was may 13th so in the span of about three weeks i got this whole thing done which which was crazy um but hopefully it still turned out well because i didn't try to sacrifice quality on the way um if you're interested in learning more about the principles and things we're going to talk about tonight with clean architecture then the ddd course is is the place for you it's all been redone i had a course with julie that we did way back in 2014 here that's now been retired you can still watch it um but that one is for net4 uh you know net core didn't exist back then um and so you know it's samples and everything are a little bit dated at this point so the new one i totally rebuild all the samples there everything's using docker everything's using dot net five um and so you can kind of see all these principles and practices in place uh in a real world sort of sample application it's actually several applications that communicate with one another um so so definitely check those out if you're interested um this ebook i've had for a few years out out there now it's it's getting updated with each new release of net um so it's currently on.net five i think this one says.net core three one but it's really.net five now um and so it's a book it's about 100 pages long pdf totally free uh goes along with the eshop on web sample app which if we have some time tonight maybe i'll show you um and and that's you know basically a reference application using asp.net core that kind of shows how to build applications that follow solid principles and good architectural principles um if you do need help with any of that with your team whether you're porting stuff to.net core or net five um or you just want some training up on domain driven design or architectural stuff um hit me up for some mentoring or training and if you as an individual would like to accelerate your career as a developer uh and you're interested whether it's climbing the corporate ladder or going independent and and starting your own business uh you know those are things that we talk about regularly in my group coaching program that i have at dev better i have so i have a podcast and i also stream on twitch uh as our dallas um the podcast has been a little bit slow this year but i'll try and add some more episodes over the summer um and that's that's enough about me so let's let's get into the topic so um as we go uh please do ask questions um you can you know ask them in twitch in the comments and i'll pause every now and then and they'll uh read the the questions to me uh so so i can make sure i'm answering them as i go um so if you have any questions even now as we're getting ready to get started throw them out there right if you've already you know seen some of the stuff that i've shared or or you are you know read you know a book about clean architecture or whatever it might be feel free to toss those questions out there now um usually when i give these presentations in person everybody is too shy to actually have any questions or they don't know what they should ask because they haven't heard my talk yet and so i use this trick where i just kind of seed the talk with some questions up front and so some of the questions that we're going to answer tonight are things like why do we bother to separate our applications into multiple projects like why don't we just make everything one giant project and maybe sometimes that's appropriate right and if we do want to split things up what are some principles that we could follow that we could apply that would tell us what the best way is to break things up and where where should the seams be what belongs in in this or that project and why when we make those decisions when we split things up what kind of impact does that have on coupling in the solution uh you're going to have to have some coupling for your application to work but we'd always rather have loose coupling than tight coupling because it makes it easier for us to make changes in the future and if we kind of make the wrong decisions what are some of the problems that we can get ourselves into and so some of the pitfalls that we're going to try and avoid then we'll talk about clean architecture and and see kind of how it fits into all of this it's not a panacea it doesn't fix every problem but it does have a lot of i think positive trade-offs overall so um that's what uh i'm mostly going to be talking about here is my experience with it and why i think it fits a lot of solutions that are being built especially if you're using uh things like test driven development uh or domain driven development or things like that all right so before we jump into the architecture uh itself let's let's first john jump into uh some principles all right so these are going to kind of guide us when we when we are evaluating or assessing whether or not this or that architectural decision makes sense because everything in software architecture and really in programming in general is just trade-offs right if if i say that this is always the right way to do it you know i'm lying partly that's because i'm a consultant and so my my motto is it depends um but but just the fact of it is that every decision we make is a decision optimized for a at the expense of b um and so you know we're gonna use these principles to kind of guide us but that's because these principles you know generally are leading us toward things that we care more about for example separation of concerns is is a widely held principle in software development that suggests that we would like to keep you know different parts of our application separate from one another so they don't pollute each other right we don't want to have low level plumbing code just intermingled with our business logic and and maybe our user interface logic as well that's going to make it harder for us to split those things apart or make changes to them or make them more modular if it's just a bunch of spaghetti code and everything's mixed together and so if you take a look at this refrigerator hopefully this isn't what your refrigerator looks like at your home but you can see there's some things in here that maybe that's not the right place to put them in your kitchen and so right away you know we'd like to keep plumbing concerns out of the other concerns in our system and not let it kind of pollute um that that stuff so you know mix mixing these responsibilities in the same place is something we strive to avoid using separation of concerns and the big three that we're most concerned with are going to be things like data access business logic and your domain model and your user interface concerns now working very closely with separation of concerns is another principle called single responsibility and single responsibility principle is one of the solid principles um and it basically says that your classes should only have a single reason to change uh and so if you have you know different stakeholders or different things that your code needs to do in different ways any given class should ideally only need to be changed or swapped out in response to one axis of change so you know if you have something that needs to generate reports and it's got some software for how it builds the report and some software for how it gets the data and some you know algorithms for how it formats the data and and things like that right you would want to put all that in one place if you could help it because it's possible that you'd want to swap out each one of those independently from one another okay another very common principle that we like to follow in software development is don't repeat yourself for the dry principle and the dry principle is sometimes overused sometimes you eliminate duplication and introduce coupling where where you shouldn't um but more often than not the problem is that there's too much duplication and you have different concepts or literally the same code just copy paste it in you know n different places within your application and so you want to find a way to have a single canonical place for any given decision or concept to live in your code all right so when you follow the don't repeat yourself principle this is going to help us sort of organize our system because we're going to take repetitive code we're going to organize that into functions or methods and then to make it easier for us to locate and work with these functions we're going to group them into cohesive classes and then we'll further group those up typically into folders and namespaces using whatever makes sense to the team right generally things like what their responsibilities are or how abstract they might be whether they're low level or high level and things like that and we can take this even further and eventually group these things into projects and the whole idea of you know grouping things in taking smaller pieces and grouping them up is one of the ways we organize complexity in our systems and that's what domain driven design is all about is tackling complexity in software uh and so it takes these different kind of standard ways of organizing c-sharp code and it actually adds a few additional uh containers to to the mix at different levels of granularity that you don't see here so we're not going to get into ddd in tonight's topic but ddd has two patterns that it uses heavily one is aggregates which is a way to group different entities together that change together and another one is bounded context which is a way for you to have uh different uh ubiquitous languages and and models uh in different parts of a large system or organization and then have them communicate with each other through explicit interfaces instead of through some type of global state mechanism and then not terribly necessarily related to ddd's features a lot of teams find that it's helpful to organize code in vertical slices by feature as a way to to kind of keep things uh modular and and organized in one place so these are some other options that you have when you're thinking about how to split things up and splitting things up the right way is is all about what architecture is and what clean architecture is is trying to tackle um and that's why these are relevant for us today all right then another principle is the the other end of the solid principles is the dependency inversion principle and dependency inversion sounds like dependency injection and actually they they go together uh quite quite well dependency inversion is all about making it so that your low level code that knows how to talk to infrastructure concerns um depends on your abstractions and not the other way around right and at your uh your high level code that knows like at a high level what the business concerns are that it doesn't depend on that low level code and so that's why we're inverting it because usually that's the typical way it works and so if you think about the interface of your power outlet on your wall right it supports an interface which is the shape of you know the prongs that are going to fit into it for a u.s standard appliance and the two sides have both agreed to that interface right the wall it supports one interface and the lamp or other appliance also has a plug that fits that interface and so it's literally a plug and play you know architecture at that point and if you go off to europe or some other country that uses a different interface you can use an adapter to make it so you can still plug in and we have a software design pattern called adapter that does exactly that right and so using this is something that we do in the real world we can take those same principles and apply them to our software to get better results all right so the idea with dependency inversion is slidell move there we go is that both your high level classes and implementation low level detail classes should depend on abstractions and when we're talking abstractions in c sharp we're usually talking about interfaces sometimes abstract based classes but most of the time we mean interfaces all right the other thing is another principle you maybe haven't heard of because because i made it up but i do have some some articles and stuff out there about it uh classes should follow the explicit dependencies principle so what is that well a few years ago i wrote a series of articles that were all about hidden dependencies and and things that would bite you when you went to try and use a service or class and it looked like it would work just fine but as you were starting to work with it at runtime somewhere it would just blow up and tell you that it needed some some resource something that you hadn't given it and so i talked about those as being hidden dependencies that were just cause an unpleasant surprise to developers who are trying to use them and so if you follow the explicit dependencies principle you never run into that because your services are going to request everything they need through their constructor and that allows you to use dependency injection in fact the best type of dependency injection which is constructor injection um and it it basically self documents all your classes it says this is exactly what i need to do what i need to do um and if you give me those things and they're valid right you don't pass in a bunch of nulls or whatever then you can expect that i'm going to do my job properly and so this makes it so your classes are honest about what they need and not deceptive they're not going to surprise you halfway through with with something that they actually didn't tell you they needed recently i was talking about this i think at another user group or a client and it came to me that this is basically your classes are like a recipe right if you ever read a recipe you know the first thing it lists is the ingredients says i need this this this this and you first thing if you're thinking about making it you're in your head you're saying i got that i got that i got that yeah okay good this sounds good i'm going to make this recipe so you grab the things and you start and you often times you don't read the whole recipe right you just you know you have the stuff you know you're a competent cook so you know you go from there and so it would really annoy you if you got halfway through the recipe and it was like okay now add the uh two pounds of pomegranate and you're like what that that's not in the ingredients i don't have two pounds of pomegranate what that's crazy like that's what we're trying to avoid right say everything you need at the top of your class in the constructor and avoid all that frustration with surprising folks with things that they didn't know that they needed all right so when we're talking about dependency inversion and we're saying that these dependencies need to depend on the abstractions or interfaces there's a corollary here that says where in our solution in our project are we going to put those interfaces and they have to be accessible to the low-level implementation services and the high-level business services and then you need to have some composition route where you're going to wire those things up if you're using a dependency inversion container like net has built-in or fact or any of those types of things you have this composition route usually somewhere close to where the app starts up in asp.net core it's going to be in startup.cs and so the user interface entry point also needs that access to those interfaces so basically everything needs to be able to get to those interfaces and that's going to play an important role on where we decide to put them in our architecture all right so wrapping up with dependency inversion principle let me show you these two different images the first one here is if you don't follow the principle you don't have any abstractions and you just build a system where every time you need some functionality you new up a new class and you call a method on it so on the left at compile time you know the compiler checks and says okay yes this this class can new up this other class call the method it moves up this other class calls a method okay so you have a that references b that references c and on the right when you run it if you have an exception or set a breakpoint in class c and you look at the stack trace it's going to look identical it's going to be you know class a called into something in class b that called into something in class c and for a lot of developers this is the only way they know how to write code this is true for me for a long time early in my career i didn't know how to do it any other way it wasn't until i hit some problems where i was really blocked trying to figure out how to test some stuff in isolation that i i finally realized like the role of interfaces in this whole thing and so with interfaces you can break that you can make it so your compile time dependency chain is completely different from your runtime dependency chain and that's the the big epiphany that dependency inversion principle and dependency injection yields for you is that you suddenly get this lego-like ability to swap in implementations inside your code and that makes it really powerful because you're able to change out functionality without actually having to edit the code in a class right if there's a class and you want to do something else write a new class and swap it in right that's way less likely to break things than if you have to go in and add one more else statement to a ginormous method with you know 5000 lines in it that's already got way too many if statements to follow um you know adding new code to new classes is a great way to extend legacy systems in a in a safer way all right so i covered a whole lot of stuff with principles there um let me let me grab a quick drink and see did anybody have any questions because i promised i'd stop along the way for questions and i've been talking nonstop so far no we have some npm comments but that's okay we welcome those here but all right so far no questions all right cool um so a couple last things here before we get into uh how to actually structure your code the whole thing with this is that we want to make it so based on how we organize our system our our solution our application we want to make the right thing easy and the wrong thing hard so that we kind of force developers who admit it are kind of lazy you know we've got deadlines to hit we want to just get things done and follow the path of least resistance we want that path of least resistance to lead you into the pit of success we don't want to make it so you know doing the easy thing is totally wrong and you have to go read all these documentation and always remember this checklist of things to do to do it the right way right um that will lead you into the pit of despair which which is not a good place to be so to make the right thing easy and the wrong thing hard how can we structure the solution so that we don't have our user interface classes directly depending on the infrastructure stuff how can we make it so that the domain classes the business logic doesn't directly depend on infrastructure stuff like like the database like the file system like you know email how can we make it so repetition is hard to do or or not as easy to do as leveraging some shared policy right and that's a hard one to beat right because copy paste is really easy so making something easier than copy paste is a challenge but that's what we want to strive to do we want to make it just automatic that certain policies and certain you know things are enforced in our design even easier than just having developers copy paste logic all over okay so let's first talk about this sort of classic interior architecture that was the best practice uh he said in air quotes um for for many years uh in fact my very first conference presentation uh one of one of my talks was on this topic uh and and i had this diagram in it from 2001 uh which was you know from microsoft it was you know right off their msdn website that's that's no longer with us and on the left was how a lot of software was built at the time and and probably still is where basically everything was together whether you're writing it in like vb6 or or asp or what have you you know all the business logic all the ui code was just all intermingled in the same file and it made it difficult to do things like split up teams and and have specialists and you know work on large solutions um with multiple teams and things like that so breaking it up into these different tiers or layers allowed for code reuse allowed for team segmentation and specialization it gave us a lot of benefits at the time however if you look at how the dependency tree was structured right the data access layer was tightly coupled to the database right it was ado.net typically or ado even before that it would just talk directly to sql server or oracle or whatever your database was and it couldn't do anything else right that's what it did it just talked to the database and then the business layer would talk to the data access layer to do everything it needed typically without any abstractions right so it depended on the data access layer which meant that it transitively depended on the database and the ui layer just talked directly to the business layer if you were lucky it didn't do an end run and talk to the data access layer directly but sometimes that happened too but you know no matter what it depended on the database by you know transitivity as well so everything depended on the database now even 20 years ago when i gave that talk we knew that automation was a good thing right continuous integration while still new um was something that a lot of folks had been trying uh even in the 90s and and lots of folks were seeing success with it and it was certainly better than working on something in isolation for a year and then spending months trying to you know make it all talk to each other and actually ship the thing and so trying to integrate stuff more frequently trying to write automated tests that verified it worked um were things that were gaining hold you know test driven development was a book written by ken beck and that was published in the in the 90s um so these things you know existed but trying to use this architecture and then follow those types of practices was incredibly painful i know because i did it and i tried to write a lot of tests that went through this architecture and it just sucks the life away from you because every time you're trying to add another test you've got this big script of all your test data and schema for the database and everything depends on the database you have to run that before every test and as you keep adding more tests you know they just keep getting slower and slower and slower and it didn't take very many tests at all before you know it would take 10 minutes for you to run your test run um and it was really difficult to you know let that give you that fast feedback that you want when you have to wait 10 minutes every time you add another test or want to run your test um so it just it was painful all right so the main centric design is is an alternative approach to that anterior layer and it has a bunch of different names we'll talk about in just a second domain centric design is is one of them that's sort of descriptive of what it is not not the pattern itself and clean architecture is just one of those things so if you look at this diagram instead of it being a bunch of boxes stacked on top of each other it's concentric circles and the idea is that in the core of your application in the central circle you put your business logic in a way that has no dependencies on anything else except maybe you know your underlying framework like net and then everything else is outside of there and your dependencies always point inward uh is the way to think about this all right so in your domain model you're going to have your business logic but also you know if you're following domain driven design you're going to have a model of the problem space and it's going to have certain things in it certain patterns and types of uh you know types like uh interfaces for example um that you use to create a model of the complexity of the software what the business rules are and the behavior should be those interfaces work with the main objects so other parts of your system other services things in your infrastructure layer things in your ui layer they're all going to use those interfaces in order to work with your domain model and everything else in your system including data access including all that stuff that's tightly coupled to the database is going to depend on this core domain model and its abstractions its interfaces all right so clean architecture you may also have heard called onion architecture which my friend jeffrey palermo coined that term about i don't know it's been like 12 years now it was 2009 um you know a series of blog posts but even before that it was known as hexagonal architecture or ports and adapters it's not exactly new it's been something that folks have written about and been using for for quite a long time here's another diagram a little more detailed than the first one i showed you it's using onion architecture style of concentric circles and at the very center you've got your domain entities around that you've got these repository interfaces that you use to access the domain entities around that you've got you know application services or domain services that that work with those as well and then everything else is in the purple region where you know these are different projects so you've got test projects you've got user interface projects you've got infrastructure projects that all depend inward on that core domain so those inner three circles are usually one project maybe two and everything else depends on those looking at it from hexagonal or ports and adapters um it's kind of funny that they would name it hexagonal architecture just because somebody decided to use uh hexagons on a slide like this but that's how the world works um so in here you've got your domain layer again at the center and those purple ports are interfaces right and the implementations of those interfaces are the adapters that are all around the outside and the orange and the blue right so if we look at the top right you've got this internal persistence port that is basically how it's going to save and retrieve data to some data store and it can either plug in a remote database management system like sql server or oracle or it could use an in-memory store and it could just swap out which one of those it wants to use now a lot of folks over the years and even today i'm sure will say hey how likely is it that we're really going to ever change our database and the answer is actually pretty likely not necessarily that in production you're going to you know trash sql server and go start using oracle but in different environments it's often very handy to be able to switch out which database provider you're using right what you use on localhost versus in your dev environment your test environment your stage environment your production environment those can all be different you can plug in different adapters to that make sense at those levels and as you move into the cloud and you have different uh pricing based on which cloud product you're using it might be really nice that you could just plug in a docker container with a you know a free version of sql server and use that instead of cosmos db or something that's going to charge you a lot more which you use in production and yes you know there's some tests that you're going to want to use the real data adapter for but you can do a lot of automation and testing for your system using a stand in for how the real persistence works if you architect your system correctly okay so that's fortson adapters hexagonal onion all different names for clean architecture clean architecture uncle bob martin's got a book with the same name he talks about it there but it's basically the latest name for the same type of uh architecture so quick question yeah yes real quick um let's see if i got this right uh let's see dan spark asked are service interfaces part of their core domain i believe you brought this question up when you were talking here yep um yes some some will be and we'll talk about this there's going to be services probably at many different layers in your system um but you typically have domain services that are part of your domain layer your domain model and so that's usually what this would be but sometimes you'll also have another layer of application services and and those might live in a different project and so we'll we'll talk about that and so depending on how many separations you find valuable for your application which will largely depend on how large and complex it might be you might have services that are spanning different projects but you'll almost always have some at the domain model level and some at other levels in your system so that's a good question do we have time for one more um i'm not going to get this right but what is a good indicator to start building your projects clean in terms of pain driven development what are the pains that make you decide to start breaking things into these layers i love that this person is using pain driven development because i usually talk about that in a lot of my talks so maybe you heard it from me i didn't invent the term but i do love it uh yeah so why would you bother starting out with all of this overhead if you don't know if you're going to need it i think is is really the the question there and it's it's a good one um if i'm building something that is going to be for a client that's paying me money that wants to build this thing as something that's core to their business that their business is betting on and they're gonna be making money on then i'm gonna probably pick this architecture nine times out of ten now part of that is because of a survivorship bias if you will where you know because of the things i talk about and the courses that i do on pluralsight and the reputation i have folks come to me when they have the type of problem that i'm good at solving right so if i were building a simple crud application i probably would not use this structure right but that's not typically the type of applications folks ask me for help with um so so the delineator that i would suggest is is basically the same calculus you would use on whether you want to apply domain driven design and with domain driven design the biggest thing is is there sufficient business complexity to warrant the effort of all the abstractions and layers and things that domain driven design brings to the table for this application or is it just a matter of pushing data in and out of a database and letting users manage it with some you know simple uh forms or something is it just a forms over data crud app and usually the way you can tell that is by how many uh if statements you've got inside the code right when i when i want to see how complex uh a domain model is i i calculate its you know conditional complexity um and start looking at all the all the if statements and the rules that's where you need to write a lot of tests that's where you need to verify that all that conditional stuff works correctly if you have a system where your domain entities if you will your tables that you're referencing in c sharp as some type of object if they are nothing but properties and they have no validation logic they have no events that fire off they have no when this happens that should happen right they don't have any behavior all you do is fetch them from the database change some things and save them and that's it or that's 99 of it then you probably don't need domain driven design or clean architecture right build a file new project asp.net core maybe maybe do it with some kind of code generator like codesmith or something like that that can just look at your database schema and build out the app for you or go in and right click and use visual studio to code gen a bunch of controllers or razer pages with views that will do all the crud for you and you can have your app like you know 60 70 done uh in in less than an hour just by using codegen for that type of app and not have to spend all this time on on architecture and principles and everything else that'll get you a lot of the way there for crud type apps and if you don't know crud crud stands for create read update delete so the the four standard data access uh things you do with a piece of data in a database all right so great great question um all right so let's talk about the rules of clean architecture so the first rule of clean architecture and i do a few movie references in here is that you don't talk about clean no that's that's not right that's not the right one um the first rule is that the application core is the place that contains your domain model now if you're not doing ddd then that just means it's the place where your business objects live right just everywhere i say domain model you think business logic business objects put it in there the next rule is that all of your dependencies point toward the domain model they point toward that core project all right and then another rule that we've kind of already covered is that all your interfaces have to be implemented in the inner projects right and the outer projects implement them and reference them sometimes you'll have implementations in the same project but because of the way the dependencies work you have to have the interface defined in an inner project for an outer project be able to get to it because the outer projects depend on the inner projects all right next you want to avoid directly depending on the infrastructure project of all the projects you have um the infrastructure project and and sometimes you'll you'll have more than one uh maybe you split them out and you have one that's just for data access and another one that's for everything else or or for messaging or something like that but usually at least to start you're fine to put them all in one project um and and that infrastructure project that's how your system talks to things that aren't in memory right that's how it talks to a database or file or something on a network and so we put all that stuff in its own project and then we try not to really depend on that project any more than necessary because anything that depends on that becomes more difficult to test and more difficult to change and so we try and keep all the dependency going through interfaces so that they're loosely coupled and not tightly coupled all right so what are some of the the features of clean architecture well it's framework independent so it works whether you're doing it with asp.net core or python or java or anything else it's database independent it doesn't even care if you have a database you can write an application and add a database like at the very very end and the whole rest of the way that you've been building it you're just building it with an in-memory data provider or a file system or whatever right the database is uh just implementation detail right it's just a place to store things in between requests it's not that big a deal and when you move to the cloud it's good to have a database agnostic approach because you don't want to be coupled to this one you know super important sql server database you want to be open to options because that lets you do things like have distributed data which gives you more scalability options um and so you know it fits in nicely with with cloud native application design and of course it's ui dependent right it works whether you're building a worker service or a console app or a web forms app or wpf or whatever it might be all right the other thing that i really like about it is that it is very testable i think that it's a crime to manually test your code at the rates that you're probably charging or uh whether your salary or consulting as a software developer in the current you know industry um you know your time is very valuable and so if you're manually testing code on on the clock right you're stealing from your client because you could have written tests in a fraction of that time that would run every single time you you check in your code or every time you say net test at the command line and in you know less than a few seconds it's tested everything right in the time it would take you to hit f5 and start debugging into the app one time it's already tested all of the all the things that you know how to test and yeah you've got to spend some time writing those tests and maybe you're not that fast at it to start but you will get faster and and once you write them they're a investment that keeps on giving right there's a very long tail on the value you get from those automated tests so using a testable architecture pays big dividends especially if you're trying to have organizational agility in the future and you want to be able to refactor or redesign the application to work in a different way later on down the line speaking of refactoring if you have an existing app and you want to shift it from its current architecture to clean architecture the easiest way is to start from a system that is already laid out properly a solution template um i have a solution template that is laid out properly and you can get it for free at github here and there's even a net new template you can install and then you just say net new clean arch and it will create it for you and give you the proper name spaces and everything so that's the easiest way to start next best is if you have an application that's just one project because the dependencies there are usually easier to tease apart and start breaking things up into like core and infrastructure projects the hardest is when you already have a bunch of projects and their dependencies all go the wrong direction right so if you're already using that classic end tier style and the ui depends on the business layer and that depends on the data layer then that's where it's going to be a lot tougher for you to reorganize it because you basically have to flip the whole thing um and that that may take a lot more work and sometimes you want some external help from folks that know how to do that okay so now let's talk about what goes where in clean architecture and this is usually the the most valuable part of the talk so inside the core project you want to have your interfaces all your abstractions you want to have the components that make up your domain model or your business layer so this will be entities value objects aggregates in ddd aggregates is just a group of entities that change together if you don't know that pattern domain services live here domain services are services that work with your domain model so they um are just things that their interface their their methods their parameters their return types are all in the form of entities or value objects or aggregates or things here right and if they have dependencies they don't take hard-coded dependencies on you know sql server or azure they have an interface right so they have some abstraction for that dependency that they need you might have custom exceptions inside your core uh i encourage you to use custom exceptions for business level uh things that go wrong so let's say you've got a checkout method and there's an order and it should never ever happen in the system that you would ever try and check out an order that had no items in it right that should just you know the system has all kinds of checks to make sure that doesn't happen but if it does right instead of throwing a null reference exception or an index out of range exception when you try and iterate over the array of order items or whatever it would be much much nicer if you had an exception that said very clearly you know order contains no items exception or something like that that'll make it much easier for someone to track down what the problem is if it ever happens right so use higher level exceptions for business uh rules that should never be validated inside your domain model your domain events would live here and uh oftentimes the domain event handlers sometimes you'll have handlers in other layers too but frequently um you will have them in the domain model so if you're not using domain events domain events basically are a way that you can capture as a class something that happens that's interesting in your domain like i just gave an example of someone checking out an order you could have an order checked out domain event what might happen when an order is checked out well all kinds of things we might want to charge their card we might want to ship the item we might want to verify we have inventory we might want to send an email to the user all kinds of stuff might happen when this event occurs and by using an event it makes it so those things can be loosely coupled we don't have to have a checkout method and a service somewhere that just gets bigger and bigger and bigger and bigger because it does everything right it's much more flexible to use events for that type of thing and as a way to communicate with other applications or other bounded contacts we can take those domain events and if it makes sense we can translate them into integration events that go out to other systems alright and then specifications are another thing that frequently will live in your core in your domain model a specification is a class that represents a query and so you can use these to make it so that your data access is a lot more flexible and and doesn't make it so that if you're using a repository pattern if you've ever run into that scenario where you keep having to add additional methods to your repository because you need to query things different ways you need to pull back different amounts of data with every query and so you start out with a really simple repository and then later on it's like list customers list customers by country list customers by last name list customers by last name and country with orders right and it just gets crazy with with more and more methods specification totally fixes that um you put the query logic into your model you can test it independently from the database and you just plug it into your repository you pass the specification to a repository method and it executes the specification entity framework works with it right it translates it all into a sql for you and then you get back your results just like you normally would but now instead of having a bunch of lambda expressions and link in your ui and in your infrastructure and all over your all over the place all of that stuff is just a new specification so it's really good at encapsulating all that query logic in one place and putting it in a place that's very testable uh in your system all right so that's that's the core project that's it that's what goes there um now let's talk about the actually now let's take a quick second see if anybody has any questions so we had one um i think you touched on it or maybe covered it but we'll bring up to make sure how do you view dependency diagrams of the existing project and identify the parts needing restructuring or refactoring um if if it's a lot of projects that can be challenging there are some tools in visual studio that will do that for you you can create a different different diagrams depending on which version of visual studio you have even the the lowliest version of visual studio you can go to any project and it'll show you which other project references and so you can kind of you know draw out a diagram that says this one depends on that one depends on the other one and kind of see what that dependency structure is uh so you know that's that's usually where i start you know most most of the time you only have like three or four projects that are really part of the app for a simple app uh for for legacy apps sometimes i see things i have 100 projects and you know sometimes they're you know 100 projects that we only use half of for for a given app but but still it can take time to kind of figure out that whole hierarchy but there's tooling in visual studio and i can show you that when i get to the demo part if you like i think we have one more i think you're going to cover this in your next set of slides but should i be accessing the database uh via repository or specifications on the domain layer or should it be delegated to the application layer yeah you're going to abstract your data access here and and some of these interfaces in the core project might be for data access like an i repository or an i customer repository or something like that that would be in the core the actual way you do it um is going to be inside of your infrastructure layout that we'll get to next all right they keep coming and see one more oh yep jeremy and i are stuffing each other's toes i'm currently observing there's a tendency to create microservice per entity i think this might be the entity service anti-pattern how can we avoid this i have not seen that microservice per entity seems like taking it a little too far that's going to have nano services at that point um yeah at the at the most it should be per aggregate right so so if you have like some tree uh structure where you've got an order with order items or an invoice with invoice items or customer with addresses or whatever right that might be an aggregate that maybe makes sense to have a microservice for um but usually your microservices should maybe be a little bigger than that in my experience how can you detect that or avoid it well you'll detect it if if your micro services are very tightly coupled together so let's say that we literally did it per entity right and so i have an order entity and i have an order item entity now i would generally make those be an aggregate but let's say that we decided to make them separate micro services how can i do anything with the order entity that isn't going to have to query the order item entity uh microservice rather all the time to get you know the state of itself right to get its own order items it would have to talk to this other micro servers i can't ever deploy these things independently from one another and that's microservices are meant to be uh independently deployable so that'll be a big red flag when you see how tightly coupled they are you want to be able to draw a line around your microservices and say this is its responsibility these are the things it does this is the interface it presents to the rest of the world and if it goes down most of the rest of the system should still be able to work right and if i if i need to deploy a new version of it i can just do that and the rest of the system just drives on and and yeah maybe there's some message cues that accumulate a few extra items in them while the system's coming up um but the system doesn't just explode because one microservice is out of the picture for a moment that's the ideal right you can't always get there but that should be what you're striving for and so if you are building a system that has a bunch of of microservices that all have to have real-time immediate uh synchronous communication with one another all you're doing is making a distributed system that is basically a distributed monolith uh and you're not getting the benefits of microservices in my opinion would you create a new solution for each microsoft sorry i should let you ask these oh no you're good go ahead but yeah i love the uh i love the ui you've got for popping these up that makes it easy um yeah i probably would that's typically how i would do it so each microservice generally gets its own solution we'll talk about how you can share code between them um here in just a second but but ideally you'd want each one to be self-contained it should have its own model it should have its own uh solution you know your solutions don't need to be huge right for a micro service especially like remember the micro part of the name um your solution is going to be maybe three projects um a couple of new get references and some tests like that's it you know if you're in double digit projects for a micro service then you're probably starting to get a little bit more in there than than i would typically want um you know i see sometimes they have like 10 or 12 and that's that's that's getting pretty high i think and if definitely if you've got like 20 plus projects in a micro service um i think you're you need to rethink the name of that uh it's no longer micro all right well i guess that's it for now so thank you all right um let's talk about the infrastructure project so the infrastructure project is where you put all the things that know the low-level details about how something gets done right so your abstractions your interfaces they are saying what they're saying what needs to happen and how you do it is is in the implementation of those interfaces and if that how uh needs to talk out of process needs to talk to something other than your code then you put it in the infrastructure project and so things that go in here are repository implementations and the other things that they need to work so if you're writing a repository and it talks to ef core or dbcontext then that needs to go infrastructure with it if it needs to talk to dapper right then there's going to be a nuget reference to dapper in here if it needs to talk to an azure sdk to communicate with cosmos db that azure sdk is a reference from the infrastructure project and nowhere else is how this should work uh if you have you know caching on your repositories it's a common uh thing you can do with a decorator that would go in here as well typically because it's relying on a cache that's gonna be out of process whether it's using redis or an in-memory cache or whatever and usually you write that in such a way you can swap out whether it's a redis cache or an in-memory cache or what have you all right if you need to talk to other things over uh web apis or grpc or whatever you know your clients would go here so you're your web api client for talking to uh the github api the twitter api the send grid api whatever things you need to act as a client to um those would all go here anything that talks to the file system things that are logging adapters might go here i'm talking specifically about logging adapters that have a dependency on external infrastructure so you know you have a logger that knows how to uh write directly to azure app insights or azure monitor that would go here or one that writes directly to a file that would go here you might have a logger that you use in your domain model like say ceralog that does not have an intrinsic dependency on infrastructure and that you can still write unit tests for and it doesn't blow up because some you know connection string or file doesn't exist right that's okay right that's that's purely in memory at that point um and a lot of loggers have interfaces that you can use as well uh to make it so you don't have that tight coupling um but things that do need to talk to infrastructure should go here in infrastructure sending emails or other messages would go here talking to the system clock it's very frequently that you'll have uh implementation here it's a really simple implementation it's usually like one line of code but if you've got conditional logic you've got business logic that depends on the date or the time of day or things like that then you're not gonna be able to write tests that work 24 7. right you're going to have tests that only work at certain hours of the day and then they break at other hours of the day and so those are much easier to write if you can use an abstraction like an i date time or an i clock or whatever interface and then implement that inside of infrastructure and you may have other services here so there was a question earlier about you know which services would go where um if you have services that depend on this infrastructure and and work with it directly and you can look at the the method signatures or the constructor dependencies on this service and see that they are not domain level um level of abstraction but they're talking about how stuff is actually being done then they would go here right so if you have some service that you know takes in uh i don't know an azure data source and it returns back a sql data reader um and you don't have any way to wrap that in some other interface um then that service would have to live here because it's its signature it's its uh definition depends on infrastructure concerns and that has to be kept inside this project otherwise those dependencies will leak out into the rest of your application and sort of infect them so you don't want to have that and by that same note you may have some interfaces in here this should be fairly rare but if you do have these types of services that have a signature that have methods or return types or constructor arguments that are themselves infrastructure dependencies then if you have interfaces that represent those classes you know and you've got an interface that returns back an azure db connection and takes in a you know something something specific to azure um that interface would have to live here too for the same reason right because the sdk where all that stuff is defined um is a dependency of the infrastructure project and not your core domain model that shouldn't know anything about azure because next week you might run it on pure docker and the week after that you might move it over to aws right and it doesn't care about your host it just cares about the business logic all right so that's it for the infrastructure project any any questions on that uh i believe we got we got one is dbcontext sometimes a sufficient abstraction or you always introduce a repository interface the dbcontext is not an abstraction at all right it's it's a db context it's an implementation it's a how it says i'm going to you know track entities and you know check for changes and then give you a way to save them and manage all that and translate link into sql and all that it's it's totally implementation that's the whole thing it does have some interfaces but they're not your interfaces right they ship with the product and so you can't you know map those to be exactly what you need the interface segregation principle says that clients should not depend on methods they don't use right and if you look at something like an idb context or an idb set there's a lot of stuff on there and i'll bet you're probably not using all of it on any given you know controller or domain service or something that might need it so um so no i would never if i'm following this approach i would never have direct dependency on a db context personally because of that that direct dependency on that implementation detail now other folks might disagree with me um and there are some folks that think well you don't really need a repository if you have a db set you know it basically implements repository and so you know you've checked the block you're using that pattern everything's great and i think i think tony hardy knows how i feel about this when he asks that so he's just like teeing it up for me um but but the thing about the repository pattern um is that it's the interface is the essence of the pattern right the fact that there is an abstraction that you own that's part of your domain model is what gives that that pattern any benefits at all yeah the fact that other things implement that pattern is an implementation detail that's not giving you any benefit um and so if you don't have the abstraction then you aren't using the pattern right you know you don't you don't really have any benefit there um and so that's you know the the thing a lot of folks overlook um you can just use the db context for everything um but now you're tightly coupled to the db context and that's you know that's fine for many applications but it's not using the repository pattern um one of the things that makes that harder by the way uh is for instance doing a decorator that does a cache repository that's trivial to do if you've got your own repository interface it's it's certainly harder to do not impossible harder to do uh in a flexible loosely coupled way with using a decorator if you're using a dbcontext directly okay all right so one more uh would background job processing such as hang fire would that be included in here um i don't know maybe i have hosted services that do that type of thing in a lot of my systems and i usually put the hosted service either as a standalone project that could be deployed separately in its own container or as its own app service or something or i run it on a different thread in the ui project itself right asp.net core makes that really easy so in the pluralsight demo we just have the hosted services that they need just running they fire off inside of startup.cs uh so they don't have any scheduling stuff though right they just they just run and they just are checking event queues and stuff constantly so if i had hang fire and i wanted to put in scheduling rules and stuff where would that live uh i haven't used hang fire in forever i don't remember if it gives me any dependencies that would be hard to test and that would be the the biggest factor for me if if i put hang fire in my domain model in core um does it make it so i have this dependency that's now difficult for to allow me to test my domain model um does it introduce any dependencies on any kind of infrastructure like uh well for hang fire to work you've got to have this config file and things like that and i don't think it does right so i think you probably could put that wherever you needed to but the the big guideline for for that library or any other library would be does it pull in any dependencies with it that are outside of your process that are outside of your code um so that now you're depending on a database a file system a network call et cetera et cetera if it's not then then you could probably pull that in as far up into the model as you're comfortable with right and so it'll be fine to have an infrastructure i'm sure there'd never be a problem with it there um it could be in ui and it could even possibly be in your domain model if it was like a core part of how you did things and like everything about your domain was about scheduling and how stuff worked okay um speaking of domains can the infrastructure layer react to domain events yeah it can i use that frequently it it may be that you want your event handlers to be in your domain model and use interfaces like let's say when an order is shipped we want to send a confirmation email to the user okay well that is going to be you know the order is going to be an entity in the domain model and when we ship it maybe that's a method on an entity or more likely it's probably like a domain service or something that that runs and says we should the thing okay so this event fires off um and so we have a handler somewhere that says okay given this order id or this order entity um i need to send an email to the to the user um and let them know that this package is on the way okay so the the event itself maybe it doesn't have all the details that that handler needs to do its job right it just says order id 123 shipped right that's what you know so in the handler you need to be able to go to the database and look up that order then you need to go and look up that customer then you need to look up their email maybe you need to go look up their profile and see if they opted into notifications then you need to build the email which maybe just do with some string logic right there um and and send the email right well to send an email needs an email sending thing right whether you're using smtp or sendgrid or whatever right now that whole handler could live in your domain model which would be nice because then you could test it really easily but all those other things it needs to do data access email sending checking policies for for you know customer whatever those are going to use repositories and db contacts and email centers that are defined with implementations in the infrastructure project but i would i would put as much as i was able to i'd put the handler logic in in the domain and then use dependency injection to plug in implementations of those interfaces from the infrastructure project now does that mean i never put handlers in here no sometimes you can't because you know maybe you've got one of these one of these interfaces you need to work with that is tightly coupled to the azure sdk or something like that and you have to use it right in that case sure put the handler here sometimes i'll put handlers in the ui which we'll see in a second in the ui project mostly when i want to do notifications back to the client using signalr and blazer and things like that so in those situations it makes sense sometimes to put handlers in the ui project but the general rule is if you can put the functionality in the core project and not break the other rules like not depending on infrastructure then you should do that right put as much stuff in core as you can as long as you don't break the rules and cause it to depend on stuff it shouldn't also well thank you all right so that leaves us with the web project there's only three projects here it's a pretty simple architecture um and so in the web project you're gonna put all your asp.net core stuff right and so depending on which flavor of asp.net core you're using you're gonna have controllers and views or you can have razor pages or you're just going to have apis or api endpoints if you're if you're just building a backend for a mobile app or a single page application react angular blazer or whatever you like you're going to have any type of dtos that you need to use with these things so these are going to be your view models your api models your binding models whatever you want to call them they're the things that you either bind to the ui or send over the wire as json or xml and then also receive back in the form of posts and puts and other things via your api or your controllers other asp.net core and mvc feature types are all going to live here so your filters your model binders your tag helpers your html helpers those will all be in the web project as well and if you have a lot of web projects and you want to share these between them then they could certainly go into new get packages and then uh have the nuget package be referenced by the web product that's fine but to the extent that you're going to have custom classes to do these things in this project they should be in the web project they shouldn't be in core because core shouldn't know anything about asp.net core or you know whatever else it's using right it should be agnostic of your user interface decision you might have other services here you might have other interfaces here these follow the same rules as the infrastructure ones right the reason why you would have services in the web layer and not in the domain layer you know the core project or the infrastructure project is because their parameters or their return types use anything else you see on this slide right so if you have a service that returns back a view model and the view model is defined in the web project then the service has to be in the web project right that's that's just how it has to work now occasionally it will it'll make sense to take you know dtos and pull them up into core um so that you could pull those services up higher and make them easier to test or easier to reuse um and that's that's the decision you can make sometimes i i'm certainly guilty of doing that occasionally for just for pure pragmatism um but but generally i would rather keep ui specific concerns including dtos out of my core domain model and and try and keep them in the web project just to give me that better separation okay so any questions about this one before i move on this one's pretty straightforward um yeah we actually well let's see we do have a question though all right how do you model your entity so that you avoid cross avoid cross aggregate or is cross aggregate a good thing not sure what he means by cross aggregate cythelo 7 um you avoid cross aggregate i'm guessing he means like this this aggregate and this aggregate both like have dependencies on each other's stuff i don't know what i'm getting so i can imagine a scenario where like i've got an order and an order has some order items and you know i've got a customer and a customer has a bunch of addresses and order needs to ship to an address right and you know so how does how do we do that now that the order now depends on the addresses stuff and your address is part of the customer like i think maybe that's what he means and he can clarify if he if he wants but let's assume that's what he means the answer is you can always use id references for things between aggregates and then you can go and get that id through the root aggregate so if i needed to have an order that depended on an address that lived under customer first of all i would make sure i copied all that address detail to the order because once i shipped the order that that address that i shipped it to is is you know not changing anymore so if the customer deletes their their favorite address or changes their preferred shipping address to something else that should not change what i just sent that order to right so so there shouldn't be that that persistent reference but even in terms of like uh you know when i'm creating the order grabbing that address it shouldn't be an entity relationship it shouldn't be a navigation property but it could be an id right it could be that you know this is order number one two three and it is for customer number four five six and it is using their address number seven eight nine right and so now i can build the order from that and when i go to ship it i can pull the details of address 789 and i can say i ship this order to street one street to city state zip country um and and now i know exactly where it went um and that's you know locked in place for that order and no longer dependent in any way on that customer all right well if if you have anything else feel free to clarify or drop more questions in the comments and i'll relay them all right okay so what if you have other things that you want to share between solutions and so in domain driven design you have this this concept called a shared kernel and it's basically the way you do that it's the way you take things that should be reused between different applications or bounded contexts or solutions and and put them uh in a place where they can be shared right now these follow all the same rules as the core projects but even more so like you should be even stricter about this in terms of referencing dependencies um like like infrastructure concerns um ideally these should be distributed as nuget packages uh if you don't already have an internal nuget feed for your organization i would encourage you to check it out um github supports it azure devops supports it a file share will act as one uh in a pinch if you need one it's really pretty easy to set up an internal nougat feed and once you do then it makes the perfect place to put this type of thing what goes in the shared kernel you might have common base types for all these different uh patterns that you might be following so base entities based domain events based specifications you might have common exceptions or interfaces that you use uh you might have authentication maybe how you do dependency injection you want to put in here like helpers or libraries or things like that if you're using consistent logging everywhere that could go here if you have common guard clauses for common business concerns that every application or every microservice needs to know about um they could go here so you know maybe your whole system only works for members or subscribers or something like that right so you have some guard clause that all over the place you're checking is this a valid subscriber right that guard clause could live in a shared kernel so that you're not having to copy it and duplicate it across every solution if you don't know what a guard clause is well here's here's a bad example of something that does not use a guard clause where you have a fairly simple method and it does what it should and it checks its inputs before it performs its operation and so it says hey if the order's not null and if the customer's not null then go ahead and process the order otherwise say that the customer was null otherwise say that the order was null right and so this is a big long convoluted way of doing defensive programming and verifying things are good right but it's not very readable because the actual work is is here hidden inside of all this conditional complexity and so what you would prefer is to fail fast right do the checks up front like this and say hey if this is null throw if that is an all throw and then from here on down i've checked right so i don't need any if statements after that i don't have any else clauses at all everything it just just works at that point because you've done all the checks up front and if you see that you're doing a lot of that and it's a lot of duplicate logic and maybe it's not always consistent and sometimes you change the exception and you don't throw it the same way or you don't give the name of the thing the same way you can use a nuget package like i have a free one out there on on new get called our dallas guard clauses has a bunch of these things built in um and it'll let you do this uh pretty easily as well all right so um check that out if you're if you're interested if you see that pain in your applications now all right so with that with all those four projects that we're talking about we haven't gotten a test yet but we will in a second you basically have three main projects for your system you have your web project which is your ui you have your infrastructure project which is everything that talks to other things outside of your code you know out of process out of out of memory out of out of your code while it's running and then you have your core project which is where as much of your stuff should go as you can get in there as long as you follow those rules it doesn't take a dependency now on some infrastructure all right then core depends on shared kernel which should be mostly abstractions it should be mostly base types interfaces things like that definitely not depending on infrastructure concerns now if you look at the arrows here the arrows all represent dependency um mostly uh compile time dependency right and then at runtime you need to somehow tell the web project where all the implementation details are for the infrastructure and so you need to at least at runtime make sure that you pass in the infrastructure dll to the web project so it can stitch all that together with its dependency injection tooling now you can just have a compile time reference on infrastructure and usually that's what you do just makes your life easier but i just want to point out that that's optional right you don't have to have a project reference on infrastructure in your solution you can literally when you when you build you can tell visual studio as a post build action um copy the dll from infrastructure's bin folder into the web bin folder and then everything works right as long as you tell your dependency injection to load that that assembly um and so you know that would make it so that it's very difficult for someone to accidentally uh you know take a dependency on a db context or something in the middle of a controller when you know they shouldn't be right so it makes it really easy uh to keep developers from doing the wrong thing it helps them you know fall into the pit of success makes the wrong thing hard the right thing easy all that good stuff um all right then you might have some tests you might have unit tests for core right core is designed to be incredibly easy to unit test because it has no dependencies and the thing that makes unit tests really painful and difficult is when they have dependencies on the user interface or on the database or on the network if you don't have any of that stuff it turns out that code is usually pretty easy to muni-test and they run really fast and you can write lots of them really easily and that is all good things you're going to have some functional tests which are a special type of integration test that you can run against your web system and in asp.net core this is incredibly easy especially if you're building apis there is no excuse for you not to be writing these types of functional tests because they're like four lines of code and and they can test everything about the the endpoint right they test the routing they test the exception healing that's the model validation all the stuff about mvc and asp.net core gets verified in these tests as well as all the logic inside your application um so they're they're really nice and and will save you a lot of uh problems from being shipped and then integration tests you know that are more like low level that are like hey can i take this entity can i send it to my data persistence and then can i fetch it back out those type of tests would live mostly targeting infrastructure now you might also have integration tests that hit other things you might have unit tests for other things too but this is mainly how your tests are going to work out with this architecture okay so that's that's the whole picture right that's basically seven projects that you need for a given solution one of which is shared so it's it would be in its own separate solution that's the shared kernel so six projects is what you would need per application or per microservice if you're following this this architecture um you know in a folder structure it might look something like this so you've got your you know your source folders this is borrowed from how.net core itself organizes its source code so typically they have a source folder with all the real code and then they have a test folder where all the test code lives and so inside of source you have your three projects core infrastructure web and in a test folder you've got your various types of tests any questions about this before i move on nope looks like we're good to move on all right and apologies if this is going longer than uh than typical but uh i figure it's virtual and if if you lose interest you can always take off and this will be on youtube later so um i figured i'd rather give you too much content than cut you short all right so let's talk for a brief moment about how we organize the stuff that happens inside the individual actions or or handlers or whatever you want to call them inside your asp.net core app because this also ties into how you want to organize your code alright so age in general an action in an mvc app or a handler in a razor page uh needs to accept some type right needs to validate it and make sure it's good right so it can use model validation maybe it does that with a filter which is automatic if you're using the api controller filter and asp.net core then it does whatever it's going to do which is the part we're going to talk about then it creates some kind of an object often for the response if it needs one and it sends it right with a response type whether it's a view or a page or an okay or whatever it might be right and so that's generally every single endpoint in your app is going to look like this and so when we look at that do work step in the middle you've already done model validation you've got whatever they sent you there's a few different ways you can do that work and they they operate at different levels of abstraction and none of them are necessarily right or wrong they all have trade-offs right and so the simplest one if you're if you're following clean architecture and if you're not just hard-coding against the db context the simplest one is to inject in an interface for a repository and and then work with your entities directly right and so this is great for simple operations it's perfect for crud work where you're just you know grabbing something changing its state and then saving it or deleting a record or creating a new record and there's not a lot of business logic around all that um it does require mapping between web models and the domain model inside the controller because you don't want to be sending your your domain model types over the wire or accepting them over the wire as a post or put and so you do need to do that that dto translation inside the controller with this approach okay so here um is an example of what this might look like in this case we're going to go fetch an item from a repository and we're going to call a method on that item because we don't have an anemic domain we actually have methods on our entities that we call to do things and so we call the mark complete method that's actually going to change the state but also maybe do other things maybe it raises an event you know maybe it has other logic and then after we've made that change to that entity state we're going to update its state in persistence using that repository again to save it and then we return okay everything works now this is missing a few little bits like maybe if we don't find the thing we want to return a 404 or something like that so there could be additional logic here but just to keep this really simple this is what this could look like now if it gets more complicated than this if it's working with several entities and they're doing different things and they have to interact in some way then it might make sense to introduce a service so that your controller doesn't have a lot of low level logic pretty much if your controller has a bunch of if logic inside the actions that's telling you that it's doing too much right you're better off to get that stuff out of the controller you want your controller actions to be tiny like you know like a couple lines of code at most right and so this is about as much complexity as you want inside an individual controller action so option two which will help pull some of that logic out of the controller is to introduce a service i usually call it an application service this is going to be in in my model so typically live in the web project because it's going to be accepting and returning types that are api models or view models or other types that are defined in the web project right so you pass an api model to the service it does whatever it's going to do and then it returns a model back to the controller which in turn returns a result all right so that is better for more complicated things it does a good job of keeping your controller lightweight and it can make it so your controller has fewer dependencies right so if the controller had to do stuff that dealt with multiple different entities working together it might have to have multiple different repositories to do that work if you introduce an application service maybe the application service has multiple repository dependencies but the controller just has one right just as a service and that's it so the code in that case would get a little simpler a little smaller it would look something like this now you can imagine somewhere there's a controller constructor that's taking in this app service you know through an interface and dependency injection and all that but inside of this action method it's just doing this one thing right it's just calling the app service to do mark complete and this is a pretty common approach but it does mean that every controller is still going to be a unique snowflake and have different sets of dependencies that it needs if you have a lot of different actions on your controller your constructor is probably going to have a bunch of different dependencies and if you see a controller that has like five or six or ten different dependencies being injected into it that's a red flag right that's telling you that you're breaking single responsibility principle you're doing too many different things et cetera et cetera and so another option that's very popular now is to use something like mediator to make it so that your controllers get super thin and super lightweight and so you take an api model you create a command out of it you send it with mediator and then you have a separate piece of code somewhere in its own class that is a handler for that command and does the actual work and so that would look something like this where inside of this same mark complete method i did change it here to be async because mediator is async but other than that it hasn't really changed so now we're going to take that item id that's being passed in we're going to create a new type out of it which is this command and we're going to send it with mediator okay so now if i do this with all my controllers and all my actions every single controller's constructor looks the same they all just take in a mediator that's it right they don't need any repositories they don't need any services they don't need anything else in fact i could create a base controller that has mediator as a property and make sure that that gets set up by my di container and now i don't even need a constructor on any of my controllers they all just use the base controller use its property and and you're good right so you don't have to have any dependencies in your controllers it's all done through the base type and everything uses mediator hallelujah all right so you can take this even a step further because three lines of code is just too much let's make it so it's only two because we can leverage model binding to create that command for us and so we just ask for the command that we need through the the parameter itself model binding will give us that as long as we name the properties on that command appropriately and then all we have to do is send it right now at this point you're wondering why do i even need to have this action method right all it's doing is just routing right it's just taking whatever comes in and routing it to another file to actually do the work um and so if you're thinking that you're right and that's why you should just throw this away and just use the api endpoints project that i've got out there on github because it makes it so you can do all that and you don't even have to have mediator so i'll show you that in a minute but this is a lot of teams that aren't using api endpoints they're already using mediator perhaps or other things in which case that's great because mediator can do more than just this it's a really good approach a lot of folks are using all right let's look at eshop on web as a sample and since i'm already over time actually i'm not going to look at it but i'm going to tell you hey you could go look at eshop on web as a sample um and then i'm going to talk about my clean architecture template here uh it's out there on github you can i'll show it to you in a second in visual studio but here's the url you know github.com our dallas clean architecture it's updated for net5 and yeah and you'll see in a second it does have its own solution template that you can use there's there's one for visual studio that gets updated periodically i'm not sure how recent it is um the the one here that's through nuget is is more commonly updated so it's more likely to be up to date with the latest and greatest um and you can just say dot net new and then pass in your project name so if your company is you know acme and your project name is i don't know foo then you could just say you know it's dot net new clean arch dash oh acme dot foo and it will create that and that'll be your name space and all your project names will be appropriate et cetera um and then art dallas api endpoints uh we'll talk about it briefly as well um it's actually being used inside the clean architecture so we'll see it there any questions while i bring this up so one quick one let's see uh and i actually have this question too yeah have some uh colleagues who prefer domain project of record any opinion um that'd be fine yeah you could call it domain if you want i use core mostly uh because jeffrey palermo basically with his onion architecture that's what he called things at the center was core if you look at the eshop on web you can't see it here but if you were to go look at eshop on web you'd see that it's its central project is called application core and that's because it was coming out just as microsoft had decided that they were going to name asp.net's next version core um which you know never really made sense because you knew it wasn't always just going to be this core subset of asp.net it was going to get bigger and they realized that too and that's why now we have done it five um but uh yeah so yeah i wouldn't mind if it were called domain um i just call it core because it's shorter and that's that's what i've always used awesome thanks okay um let's let's pull visual studio up here this is the clean architecture solution template right and so the idea with this is that you would do that.net new in fact let's just do that instead of talking about it you would do that.net new thing and we'd go over to like some scratch folder like this one that you can't see but you want a second and we go into powershell and we say net new clean arch dash oh baton rouge like that and it says boom that's not there what all right that was a horrible demo that's why i should practice my demos first um yeah i must have to reinstall it let me see if i can do that i want to see if see if my docs actually work on this thing so let's go to github.com dallas clean architecture on the fly we're going to install this thing right here with done a new install copy that in there do that i've used this before in this machine so it must just be since i updated the sdk it must have killed it and then do it again all right so now it worked so then if i go to that and we say uh that hopefully i spelled that right if you like this rogue baton um well look at this one right which is not not exactly the one that's out there but really really close right this is the one that's built from a template uh and and so you can see it's got the solution name it's got all the project names are what you would expect there is a shared kernel stop that there's a shared kernel project in here that you would rip out and put that into its own thing but the idea with this is that it's just got all the things organized correctly it's not a sample application it's a solution template so it has a minimal amount of stuff that you might want i did not create separate templates for an api project a razor pages project an mvc project et cetera et cetera because that's just too much work so if you're building a controller view project then you need the controllers and the view models and the views so you just delete everything else if you only need apis and api models you keep the apis you delete everything else and so it's up to you to just throw away the stuff you don't need but there's not a whole lot there right so if you look at the controllers there's like two uh if you want to see endpoints they're they're here so it does have a minimal domain model for you to see just how things are stitched together so there's an aggregate called a project inside a project there is a project aggregate root uh which is marked with an aggregate root interface to enforce uh persistence to only work with that um and then it has a collection of to-do items right so you basically define a project say i've got a bunch of things i've got to get done i'm going to give it a name as a project that's a container for all the to do items and then the status of the project depends on the status of all the to do items when all the items are done the project is done right so a pretty simple domain but enough that you can kind of see how the patterns work out now if you're using aggregates then they make a nice place to combine other things inside your model like events that apply to that aggregate like new item added or item completed handlers for those domain events specifications for how you're going to search for things might belong in there and so when you have a larger more realistic system that has a bunch of different aggregates you have a different folder at the root of core for each one of those aggregates it makes it really easy to find things instead of having you know one project that has like every specification or every repository not project one folder right those get huge um so let's talk about endpoints for a second the way endpoints work is instead of having a controller with a bunch of actions like this one right here's my controller and it only has the the one the one action that's because most of the work's been done by these other endpoints but you could imagine if this had uh action methods for create and update and add an item and delete an item and blah blah right this would get very long um instead the items uh or the endpoints over here are for each one of those operations and so um the way you create an endpoint is you just inherit from a base endpoint type and then you use this fluent generics pattern to specify your request and your response right your your command and your you know whatever response is coming back and so these are optional right so you could say without requests and you could say dot without a response if you wanted to but basically these produce a generic handle method um that uses those types all right and so your request maps to the uh the parameter coming in on the on the handler um which is basically your action method uh and then the response is the response coming back right from your action result so in here when you say hey create a project it says okay new level project create the the thing in the repository generate a response and return it now if i wanted to use an application service for this instead then i would just take all this code here put it inside of the service and this thing would be like one line of code and so that would be how that works now the other thing to notice about this is when you're doing stuff with traditional mvc you typically have to touch things all over the place right so i need to add a new endpoint well what do i do well it's a project endpoint okay well i'll go to the project and i'm going to add the thing here okay well um i need to have a model for that i need to have a model for what they pass in and a model for what they pass out all right well now i gotta go find another folder and i gotta go find the project view model um and mess with that right and maybe i've got an api model here where it's got a project dto and so i'm all over the place inside my project and if this is big at all right i'm scrolling because there's going to be a whole lot of different folders and things here um if you've used razer pages before the really nice thing about razer pages is inside a page like this home page this index page right the code for it is right here right they're chained together and you just you know they're right there right you don't have to scroll you don't have to go anywhere the same thing is true with these endpoints right the razer pages was the inspiration for this so you want to know what the request looks like it's right here right and this is where the router is defined this is handy when you're testing it because now the router is in a place that you can get to uh instead of a magic string and a controller the route is isn't a constant that you can get from a from a test um and what's the response well it's right here right so they're grouped together and they're really easy to find even if using vs code these still sort together right so create create create these things all appear together in other ides not just in visual studio but in visual studio you get this nice chaining thing let's look at when it doesn't have a response like delete so delete only has a request but by convention it returns a 204 no content and so it's without a response and so that's what this will do this just returns no content after it does its delete so so that's how that works um i do want to talk about one more thing and then i'll just answer questions and scroll around and show you stuff and that is functional test so functional tests if i want to do like project get by id here's what this test looks like and so you have to have a web application factory where you configure your dependencies and so you tell it hey i want to use this in-memory data source or this sql-lite data source or whatever for my test instead of a real database and not much else right that's if we go look at this that's what this is doing is it's saying okay go create a scope get the db context um use uh somewhere somewhere it's deciding to use a web provider but also it's seeding the data right so the main thing this is doing is uh getting the db context and using it to seed the data so that every test has some sample data in it and that's that's pretty much the whole thing um trying to see others here's the in-memory there's there's where it's setting up for in-memory all right the other thing this does is it says hey mediator don't do anything right so it just turns off mediator for the purpose of these uh these tests that that's optional based on what you're doing okay so then in here when i want to make a test i just build the route that i want to use and that's that's all uh strongly typed because it's using that route that's inside of the the request and then it just says client go go fetch that and deserialize it so this is using a helper method that's getting deserialized as a helper method from my hp client test extensions nuget package um and then i can just assert what i get back so if we take this and we run it hopefully it works so fast this has never been built yet so it takes a second all right there we go green check mark that's good okay so then we can put a a break point here and debug it and you'll be able to see that we get a strongly typed project id response um that comes back from this and so this var is in fact this get project by id response dto that's been deserialized so we can you know check it out and see like here's all its stuff and it's got this items collection and there's all the records and blah blah so it works really nice and it's really easy and each test is trivially small this would be even smaller if i weren't doing all these assertions so um you know there's there's like i said there's no excuse not to write these tests for your api endpoints we'll just run it by default it already has the web project set as the startup and it looks like this gives you some documentation on how it works you can click this link to go see swagger and see how all this stuff works everything whether using controllers or api endpoints it works the same so here's your thing with projects using a controller this is an api controller here's projects using endpoints that we were just looking at i didn't implement everything one for one but they basically work the same and so you can go in here you can get a list of all the projects and run it and say look there's a project you can go get a specific project to see all its items so you can say get project number one and this is what we just saw a test for so there you can see there's all my projects you can see they're not done the to-do items are are not done yet so you can go hit other endpoints to to mark them complete and basically build a to-do app out of this if you wanted to uh that's not included um all right so any questions about anything clean architecture api endpoints github solution templates testing let's see so far uh nothing's really coming in but i imagine some people are probably typing so while we wait uh yeah i want to thank you so much for coming out and doing this um let's see we got some shout outs to eshop on web i know i've used that we've used it at work as examples that's a fantastic fantastic project if you want to check it out um i don't know if we have anything else i have a ddd question if you're okay with that yeah totally so um one of the things that we've kind of talked about i think you mentioned it a little bit earlier with raising domain events and having things in the in the infrastructure project actually subscribe to them but is there a case where let's say uh a domain object actually takes a dependency on some type of service and how do you handle that um okay so you have like an entity that wants to depend on a service so the example i've i read it in the book a while back is basically like a model wants to validate itself saying that it doesn't have foul language in the text and it has to subscribe to a third party service to call out to that but the model wants to keep itself its state correct and validate on itself so how would you handle a situation like that as far as getting that dependency into the model itself sure sure so there's a few different ways you can do it and i've got an example there's a lot of ways you can do this um let me see if i can find it real quick so go here turn off caps lock um i have a ddd no duplicates repo which i think is called what i just said let's see no duplicates and so the idea with this is that you've basically you've got an example in yours where it's foul language and it has a list of words that wants to get from some service to like say hey you can't say that um in this one it's it's kind of the same idea there's there's a an external dependency we want to validate on and in this case it's uniqueness right so like it's twitter and when you create a new account on twitter it has to be unique right you can't create another username somebody has um and so the model needs to be able to verify that somehow right but the model can't do that by itself because it needs to know about all the other ids that are out there um and so there's 11 different ways that i'm showing how to do that in this this github repo that you can grab and look at and i have an article and the readme talks about it um but you know you could do it in the database right so you could do it in your scenario you could do it in the database you could say i'm not even going to put it in the model let's say i've got a stored procedure i'm going to use the stored procedure to save the thing and in the stored procedure it's going to go look at this other table and look for bad words and then do a like statement or whatever inside the thing you're inserting and blow up if it finds bad words right so that would be like just just lean on the database approach you could use a domain service and a domain service what you would do you'd have this this product service and the service in this case it's going to go do a check to see if they're if they're unique and so here it might say go list me all the things where the name is equal to the name that someone's trying to use now and if we find any then throw an exception that says duplicate right now you can imagine in your case you might have this bad word service that you inject in and it would say well if any of the things that are in my code uh match the list of bad words in this service or if i pass you know the thing they're trying to update to the service and i get back a status code that says it contains offensive language then i'm going to throw an exception right otherwise go ahead and do my work and update it right so you could do it with with a service with a an interface that you would inject in uh this this is an implementation because it's it's not an i product processor but it would work the same for an interface and then your implementation would be the actual service right so then when you're testing you could have your own service that just reads from you know a hard-coded list of strings let's say but then at runtime you could go talk to the external service that has like every bad word from every language ever and speak and whatever else right so that would be another option right that's a really simple one um and you could pass all the data you need to the method right so in product when i say update the name or in your case you know update the text it might have bad words in it i'm going to pass in all the other things that it can't have right either the other product names all of them um or all the bad words right and then i'll do the work in here uh to do it now your service you're using might not give you an api endpoint that actually lists all of the bad words right probably it doesn't um but if it did or if you had all of those in a database table you could do this um i don't necessarily like this solution but but it's an option and it works um and and on and on right so how would i do it these last few are typically how i would do it um either using an aggregate or using domain events um i'm leaning against throwing exceptions from domain events which i think is what this one does um but but it is an option that works so on product what we could do is we could say um update the name to a new name and raise an event right here um and this is using mediator basically directly here uh and so this is a non-async method uh that's doing this evil stuff you should never do but it was just a demo um to go talk to mediator using async and so in getting get a waiter get result um and goes to see hey can i make this request so when that fires it fires off a product name change requested uh and that goes to this product name change handler and it goes and says well go get me all the names uh and verify that if it's one of them then it's a duplicate and throws an exception right this is the part i'm saying i don't like um i don't think domain events should throw exceptions anymore i used to say this is a good plan but um i've come around and decided that if you want to do that behavior you should use a command not an event um so you could still do this i would just do it with a command not my vet um and and so then this would blow up and it wouldn't work if it was duplicate or if it had bad words otherwise it would proceed right so those are uh some different ways you can approach this awesome thanks so we do have a few more questions coming in so what about endpoint authorization wait yeah authorization whatever all right will you use authorize or put the logic down um i use the authorize most of the time so i'll put that on a base uh class typically or you you can even add it globally inside of startup.cs when you configure asp.net core mvc you just say add this as a global filter and then anywhere that you want to punch through it you can add a allow anonymous right so like a typical web form z or mvc view style of app maybe the login page is like the only thing you can get to if you're not authenticated and then everything else you have to be logged in that type of scenario works pretty well for uh for apis usually you need some kind of a token for just about every api endpoint um except maybe like the token endpoint itself if you're using something like off0 or identity server or something like that that stuff's probably going to be in a different place anyway it's probably never going to be part of your app and so it'll just redirect there when necessary and so you can literally just add a global filter that that specifies that you always need to have a valid jot token in order to access it uh and then and then just do that once in startup and you don't have to do it in your controllers or your endpoints awesome all right this one may be a mouthful see how do you prevent developers from doing something on the infrastructure when the web has the reference to the infrastructure project during development sure so i mentioned that and they're talking about this right here so in the package i've got this reference to baton rouge uh infrastructure and in startup at the moment uh you can see i have this using statement that's using baton rouge infrastructure so this one does not show how to do it with without that that project reference i think i have another github repo that shows how to do it but basically let me show you what you would need to do here inside of web properties you would go into post build so is it build events yeah post build command line and you would edit this and you would say something like copy dota whack baton rouge dot infrastructure you know yadda yadda slash bin slash version slash foo whatever um and then infrastructure you know dot dll to you know bin right whatever whatever that folder is so you gotta get all these paths right but you do this essentially when you build um you you don't have the project reference and instead it runs out and it grabs all the stuff it needs and it brings it over and copies it all stuff being like literally that one dll typically um and drops it into your web project so that at run time it can load it uh and then inside your startup instead of having this strongly typed direct reference to it and in configure services you're wiring up all these types so if i you know if i comment this out we'll see what turns red right we'll add the context is red and the default infrastructure module is red this default infrastructure module i think i'm using auto fact for that right yeah so this is using auto fact so with auto effect what i could do is instead of registering a module and strongly typing it i could say um how to go register that module by going and fetching it from another assembly and i don't have the code for that handy but basically you would say load the load the assembly load the module from the assembly right here let's see if there's intellisense for this is there a register assembly or register yeah register assembly modules all right so i'd say something like register assembly modules for baton rouge you know dot infrastructure right and it would find that dll uh or maybe we have to do type of or something i have to make make this code right but it would look at this dll in the bin folder and load this module using late binding basically instead of early binding and the reason why that will work is because all of the actual wire up of infrastructure is in a module in the infrastructure project so we go over here and we look at this default module like everything you need to know about how to wire things up uh is is in here so like wiring up repositories and what their scope is wiring up mediator setting up the service factory setting up all the mediator handlers all that stuff is in this module and so you don't have to specify all this stuff in your web project you can you can put the things appropriate to each module in them and so you don't have to do it exactly like this you don't have to use autofact you don't have to use modules but you do have to use some type of reflection at startup in order to load that assembly um in a late bound way so you can do dependency injection off the types that are in that other assembly instead of having a project reference and i have a blog post that talks about this more if i can find it real quick so it's our dallas reference infrastructure without project reference and i google for my own blog all the time and here's here's two ones uh well one's an eshop issue which i don't remember if i answered um but yeah this one should be the one so it's it's old uh this might be pre dotnet yeah this is this is pre.net core um and it's using registries which are structure maps equivalent to a module um but yeah you can look at this uh let's post this in the comments i don't know if it'll let me well i'll post it in a private chat and somebody else can post to the comments there you go we can handle that for you um but yeah if you search for something like this maybe i covered in this issue on eshop um [Music] yeah i don't know i got to see if i actually have a good reference for core i thought i did at some point but maybe it's still in my blog backlog um but yeah you that's that's the gist of how you do it as far as the detailed code of how to do it um i'd have to look for it okay awesome so another one from tony so follow-up question although a bit off topic how do you write automated tests for endpoints using token-based security right um that's a good question um there's a few different ways you can do that so let's say we have an api endpoint that that has a you know a need for that security and i've got github repo for this too i just got to try and find it basically i get a repost for everything um let me see if i have one that's that responds to a search for jwt that would be the only thing i can think of i would search for uh oh uh api maybe identity oh that might be it oh that's private i probably can't show that um test secure api sample that sounds like what we want all right um there we go so we want to be able to have a token secured api endpoint and dynamically test it all right so let's look at this thing goes secure api test test api endpoints there's a few ways you can do it one is to just rip out the security so in your uh test server thing you can just say allow anonymous you know add and allow anonymous filter and then everything goes through right that's kind of cheating but it will work if you don't need it otherwise this one has code to actually get an access token in your code and so this will go and actually use identity server type logic go get a token endpoints use the identity model with oidc stuff have a spa client go fetch alice alice those are pretty standard identity server uh types um and then and then do its thing right so here uh there's a test to verify you can get the token here's the api endpoint it says go get the token set the bearer token get the response etc etc and it works so um i'll send you this up some beat me to it thank you and you know what what are the odds this thing actually works right it's one thing to show you on github but let's see it's two years old could it possibly still work i don't know let's let's find out so we'll come over here and we'll dot that out of that and we'll say git clone that and we'll cd that no that one and we'll do dot net oh look at that there's a running test let's do that run and test um and it says that my sdk is old and it says can't create a file yeah i don't know what that's doing but uh it is in another window over here spinning stuff up here um and listening and doing things and did it work i don't know i mean it ran but it also shows red stuff so i'm not sure um let's let's try and open visual studio so identity server and api here if somebody else has a question while i get this started go feel free yeah no so far nothing um [Music] all right so these tests i think are just standard x unit tests right but i think i have to host the thing for it to work so if i remember right because this is not using the uh the functional test that use that test host so i think i have to spin up this thing to run it so let's run app there this is running and we can see like if i try and call the service and i'm not logged in it should give me a 401 or something it says not logged in i can log in isn't even doing anything i don't know it seems to not be doing a whole lot um type error cannot read access token of null okay that's fine how about logging in open id course oh course is oh of course it's always a problem um all right well let's let's not worry about that let's pretend that that's not a problem let's go try and run our test so come down here and there's our facts let's just run all the tests i think i think the answer is going to be that two-year-old code out on the internet doesn't actually still work but i really appreciate you trying this is actually a lot of fun well they they came with green that's cool um so so yeah so maybe they do work um i don't know why the javascript client's not working something something i have to set up with course um which usually i just say let everything in when i'm doing a demo um but here it's it's able to hit a public endpoint without a token it's able to hit an api endpoint with a token um and verify that it got what it's supposed to get uh let's let's i don't have a test for it but let's verify that it works without setting the token and by works i i think i mean it should blow up right so let's run the test now we saw it was green and if we don't have a token it should fail and it did and it fails and it says something like uh well that's great true false thanks good job steve um yeah so it's uh this is success status code and so why is it not a success status code well we could debug it and it would tell us that the response was a 401 probably we'll find out wait for it this is why i don't debug it's so damn slow there we go uh api response is a 401 unauthorized blah blah blah okay so um yeah there you go tony i think was the one that asked that so that's that's how you could write tests that's one way you could write this i told you the cheater way is to just go in and say allow anonymous and then you can test all the functionality except for authentication but you can also generate access tokens for your tests um inside your test code and then pass them around all right well i think that may be it but uh again i'd like to thank you so much for coming out tonight i really appreciate it this has probably been the most active we've had um as far as crowd participation so i feel like we set the bar really high here i don't know where we're gonna go after this but we'll figure it out um there's a bunch of new people in here so you know we're here second wednesday of every month you can find us you know on twitch youtube any of the social media stuff this sunday i will be doing you know live coding we do um just sunday streams where we hang out and just put whatever together showcase local users in their projects i think that's something they'll be me doing some blazer with azure functions so be sure to check that out thank you again steve really appreciate you coming and sharing this with us it's been fantastic my phone's been blowing up with people who've enjoyed this so it's a lot of good feedback um thank you jeremy for coming in and filling in for the other jeremy and uh yeah we'll we'll see y'all next month all right let me let me just plug my twitch stream i'm on twitch as our dallas i'm usually streaming open source stuff on fridays like afternoon usually like three to five p.m but it varies awesome yeah be sure to check i think we're gonna i don't know if we have you all hosted but we will soon i'll get on that and yeah we'll share all your stuff and we appreciate it cool thanks a lot it was fun
Info
Channel: Baton Rouge User Groups
Views: 7,442
Rating: undefined out of 5
Keywords: games, twitch
Id: D6IEnMTuawA
Channel Id: undefined
Length: 114min 41sec (6881 seconds)
Published: Wed Jun 09 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.