Clean Architecture with ASP.NET Core 6

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody uh thanks for coming to dot net conf we have just a short 30 minute time span to cover clean architecture with asp.net core 6. my name is steve smith you'll find me online as at our dallas i work for nimble pros we help companies uh with with training and implementation to move to the cloud and move to clean architecture a lot of time and follow domain driven design principles to build better applications so one of the reasons why i really like clean architecture and hey we've got the slide showing now that's awesome uh is that uh it's it's able to make it so that we can focus on the business logic and the problem we're trying to solve and not get hung up on all the plumbing uh and infrastructure concerns that really make it difficult to build applications that we can test with automated testing that we can deploy with confidence because we have that automated testing and automated deployment pipelines all right so let's first off let's just talk about what is clean architecture and very briefly clean architecture formally has gone by other names these include things like onion architecture which my friend jeffrey palermo came up with that name and some blog posts about i think it's been like 10 years now hexagonal architecture or ports and adapters were also commonly used names even before that but basically it's a domain-centric approach to organizing the dependencies in your application all right so any application that we're going to build it can usually be broken down into different concerns we've got some user interface concerns we've got business logic we've got somewhere we need to persist data typically we probably have other concerns as well but those big three items are generally present in just about any business app you're going to build and so clean architecture provides a way for us to organize those concerns in a way that lets us continue to maintain that application over the long haul now there are two common approaches to this type of organization the first one is what i call end tier or end layer and it stacks those concerns like the user interface business layer and data access layer like you can see here where the data access layer is responsible obviously for talking to the database the business layer talks to the data access layer and depends on it and the ui layer in turn depends on the business layer sometimes the ui layer might do an end run around and talk to the data access layer directly that's usually frowned upon but at the end of the day this is what the dependencies look like between all these and what that means is that your whole application generally is going to be dependent on that database now what clean architecture does is it kind of flips this around a little bit and it says we're going to have the domain be the thing that everything else depends on we're gonna have the user interface depend on that domain model we're gonna have infrastructure implement uh abstractions or interfaces that are defined in that domain model and they're going to use types that are defined in the domain model not somewhere else and yes the infrastructure layer is going to be responsible for persistence it's going to be what's talking to that database now it turns out if you build these applications but in using both of these structures frequently you're going to have some health problems with that app when it comes to maintainability once it gets to a certain size i often go to clients and they they're coming to us because they want us to help them you know fix their application or help migrate it somewhere but it's a big application they've been building it for 10 years and it's organized in this end layer approach and i asked them what kind of pain are you feeling and wait before you tell me do you have problems like there's you know lots of sore procedures there's lots of logic that's in the database there's things that you're afraid to touch because you don't know what else is depending on it you've got a database that's shared by multiple applications that are all using similar architecture to this and so you can't even rename a table or a column without fear that it's going to break some other app and yeah they're usually nodding your head like yes yes those are the things right and so clean architecture if you apply it the nice thing is is that you're not coupled to that low-level database stuff right your application is free from it you can swap it out right it's a plugable architecture and so if you're using sql server right now but in certain environments it would be nice if you could use something else like maybe in your test environment you want to use sqlite because maybe it's easier to blow it away or and reset it or something like that maybe in production you're thinking about using cosmos db right you can plug in those different implementations to this architecture without having to change the ui or the business layer all right so this end your approach has been around for a while right this slide is actually from the msdn website that microsoft has their microsoft developer network around 2001. so that's like 20 years ago literally and you can see there's different ways that you could take something that had no separation of layers which was pretty common back then and break it up into these different layers based on responsibility but no matter how many layers you broke it up into with this architecture the dependency always ended up being on the database and what we'd really like is something that's more like this diagram which is also from the early 2000s and you could probably get a sense for where the names you know ports and adapters or hexagonal architecture come from just by looking at this diagram now if you look at the center here where you have that green hexagon that's your domain layer that's going to be your business logic and all the things that belong there that have to do with business rules and the entities that you're modeling you may have an application layer that sits on top of that but provides a set of services that your user interface is going to talk through sometimes you you benefit from that sometimes you may not need it but the little purple circles there are important those are called ports in this diagram what they really are is abstractions typically interfaces in your code and they represent the things that you're going to plug into from outside of the core project in your application so on the left you've got different ways that you could plug into the application layer with different ui implementations and on the right you have different ways that you might plug in different persistence mechanisms or different ways to talk to other systems through apis or something of that nature and so the idea here is that you have a plug-and-play model for your architecture that lets you swap out the the pieces and how they talk to that core application model all right so this is another slightly more updated diagram that shows what we're going to talk about today and in this one we're going to have that center domain layer we're going to call that the core project because it's at the core of the whole system and that's where your domain model and abstractions are going to live outside of that you're going to have your web project because this is a net 6 asp.net core 6 application at the end of the day we're going to have a separate infrastructure project that's the only place in the whole system that's going to know anything about our data access so there's not going to be any db context or ef core or dapper or other type of code in the other projects it'll all be in that infrastructure project and then we'll have a couple of different test projects that'll interact with this whole system and talk to different other projects all right now the nice thing about clean architecture is it's pretty simple to follow these basic rules um first you want to make sure that all of the business logic is in the core project so you don't want to have sort of leaky abstractions where you have business logic that is in store procedures or it's in you know javascript inside your your web application ideally now you might duplicate some rules just to increase you know user responsiveness or something like that so if you're going to perform validation in your domain model but you also want to do some validation you know on the web form then that's perfectly okay but you don't want to have any of your business logic only exist in the ui and not be inside of your domain model then you want to make sure that all of your dependencies flow toward the core project it's very important that we keep the core project free of dependencies itself and the way that you do that is you make everything else depend on it one of the nice things that visual studio and the.net project system in general does for us is it won't allow us to have cycles inside of our project references so if i say that the infrastructure project depends on the core project i can't then go and say that the core project should now depend on the infrastructure project visual studio won't let you do it and so that it is helpful for our solution to enforce these rules that your domain model should not depend on infrastructure because we're setting it up with these separate projects right those are going to help us fall into the pit of success and make the right thing easy and the wrong thing hard then the third rule is sort of a consequence of the second rule which is that we need to define our interfaces or our abstractions inside the innermost projects usually the core and then outer projects can implement those interfaces so you don't want to have your interface for example data access live inside the infrastructure project because that's going to force things that want to use that abstraction like the web project to then have a direct reference to infrastructure we want to have the web project reference the core primarily and minimize any interaction it has with the infrastructure project okay so what belongs inside that core project and in just a second we're going to look at some code so you'll be able to see this a little more concretely but you know sort of abstractly in general these are the kinds of things you're going to find inside that core project the first one is going to be interfaces most of the abstractions most of the interfaces that we're going to use in our application whether they're describing how to do persistence or whether they're describing how to send an email or even business logic things that are certain domain services are going to have interfaces that represent them and those are going to live inside the core project then we have to have some way to model the actual things in our system that have state and have some persistence and those are typically going to be aggregates and entities as well as value objects now entities you're probably all familiar with those are basically the things in your system that have an id and you store in a database with that id and then you fetch them by looking them up by that id the identity is where the the entity name comes from and so things that have an identity and live over time are entities aggregates are just a domain-driven design pattern for grouping entities together to give you another encapsulation boundary and make it easier to to do persistence with groups of related things think about something like an order with all of the order items you could construct that as an aggregate and then when you persist it you would store the whole order and then fetch the whole order you wouldn't typically want to work with just an order item all by itself value objects are things that don't have an identity and that you can compare just by looking at their properties and so very common value object that you've probably all worked with is the date time in dot net one of the really nice things about value objects is if they require validation you put that validation into the constructor of the value object and then you don't have to check it anywhere else in your code and so frequently a lot of apps i looked at they're not using value objects as much as they should be and so there's lots of places where validation or invalid out of range values can exist inside of entities and so you're having to do checks a lot of the time to make sure things like you know the start date precedes the end date and things like that if you created something like in that example a date time range type then you could verify in the constructor of the date time range that the end date follows the start date and now you can use that anywhere and be confident that it works i'll bet you've probably never had to do a check on a date time to verify that the day didn't exceed 31 right because it won't let you make one like that right that's the same benefit you get in your domain when you start to apply value objects all right you might also have domain services this is where logic lives that has to do with multiple entities or value objects and how they work with each other you want to try and put as much behavior into your entities aggregates and value objects as you can but sometimes it doesn't belong in one of those and so you have domain services for that type of thing i really like custom domain exceptions instead of relying on a low level exception like a null reference exception that some developer has to go and debug the system figure out what it is why not throw a domain exception that says something like customer not found exception or order doesn't exist exception or something like that where it's much more clear what is null what is the thing that's missing without you having to debug to see what it is domain events and domain event handlers would also live in the core typically you could have handlers in other places as well but the events themselves should usually be defined inside of core domain events are another ddd pattern i'm a big fan julie lerman and i have a course on pluralsight where we talk about these i don't have time to cover them in this very quick clean architecture talk but they're they're an awesome pattern you should check out and so are specifications specifications are a way to take query logic uh and take it out of your repositories take it out of that link that you've got cluttering up all your controllers and put it into your domain model i have a nuget package called our dallas.specification that you can just grab and use and put your link into those specifications in your domain model give them good names that say what they are and then you can reuse those you can also test them without having a database you can actually just create a list of items apply a specification to it and verify that you got back the subset that you were expecting using that specification any kind of validators you need for your domain using something like fluent validation would live here enums or or smart enums that are like classes that sort of act like enums would also live in core along with any custom guard clauses you might have guard clauses are simple validators you do to make sure your system is in a consistent state and you could create your own custom ones that you reuse that apply to your domain model i have another nuget package called our dallas.guard clauses that you can use as a starting point for that if you want all right so with all that let's look at an actual core project and while we're doing that let's show how to get started using the clean architecture template so first let's go to a browser window here and this browser window is on github it's github.com clean architecture my mouse up there so i can zoom in for you there we go uh and so this has all the stuff i'm going to show you so you can just jump out to that github repo you can you can look at it browse it clone it download it then on nuget we have a our dallas clean architecture template so this is the project template that you can use to create this you can see i was just updating this a little bit within the last hour or so so what you need to do is is this line right here that lets you install this template so the very first thing we're going to do is that so we'll just copy that jump to powershell here and make this a little bigger and then we'll just run that and i've already installed it so it's going to say it's already installed okay now that you have this installed uh the other thing you can do is say net new list this will show you all your things that are installed and you'll see the asp.net clean architecture one is here this is just alphabetical order so clean dash arch or arc is what you want to to use so we're going to use that now we're going to create a new template we'll say dot net new clean that's how you type clean arc and then we'll call this nimble [Music] pros.net conf and assuming i don't have that already so i mean i don't have that already in this folder which i don't think i'd do it should create it alright so there it is now we can cd into that one and then we can just do the uh solution file that'll open up visual studio and now we'll see what visual studio has with the clean architecture template now the reason why i have this template is because normally in visual studio when you're using templates it only gives you project templates and it's really tedious to create this structure that you want doing it all by hand with project templates you have to you know create a class library and create another class library and create a web project and set this reference and set that reference and it's it's just a bunch of uh crud that you don't have to do if you've got a template and so the template basically gives you these seven projects uh there's core infrastructure and web along with something called shared kernel that we'll talk about in a minute and then there's three different types of test projects and those are broken out based on whether they're testing the whole web application which is the functional test whether they're testing some aspect of infrastructure which is most of the integration test or the unit tests which are just testing things that don't have any dependencies on infrastructure at all so let's look at the.net core project and in here you'll see we have interfaces we have broken things down into an aggregate and in here there's some handlers and some specifications all right so if we zoom in on this take a look at it what you're going to see is that there's a couple of interfaces here that describe certain types of services that we might want to implement like the search service and the email center there's a project aggregate now how you organize your folders is totally up to you but recently i'm following sort of like a feature folder approach inside of my core project where i group things based on how they're likely to change right when i need to make a new feature or add some new behavior i'm usually doing it limited to a particular aggregate and not you know just going into a folder called entities that might have 50 different classes in it and so by grouping this into aggregates most systems are only going to have you know up to a dozen or so aggregates typically and and fewer if you can break it down and follow more microservice approach and so there aren't going to be too many of those folders but inside of them i'm going to have all the events that relate to that aggregate all the handlers for those events all the specifications for how to fetch and persist those will all be in that same place so by organizing things like this inside this project aggregate i'm able to make sure that all the things related to it are are right in this location okay the the entities themselves are are going to be this project and this is again this is a solution template so you're going to throw all this away this is just there to kind of show you how things might be organized uh and give you like just a starter it's not a sample app it's it's just a template for you to start as a solution so in here we've got a project it's a it's a base entity it's an aggregate route that interface is used to enforce the persistence rule that says that we only want to fetch and store aggregates as a whole not individual entities and so if we look at it has a collection of to-do items inside this project that's a child of this if we look at the to-do item type you'll see it's also an entity but it is not an aggregate root all right so it's not going to be something we can persist on its own all right so that's about as much time as we can spend on that let's get back to what goes in the infrastructure project and the infrastructure project is just all the things that talk to stuff that's out of your process so it's going to have data access in the form of repository implementations db contexts uh cached repositories if you're using that it might have api clients how to talk to the file system whether you're talking to an actual file system on your local machine or talking to like azure blob storage using some kind of storage accessor any type of email or sms stuff is going to go in there access to the system clock might go in there you might have other services and even other interfaces that live in infrastructure but these would be only those interfaces that don't use your domain model for their parameters and return types so for instance if you're using some sdk and it's returning some azure type you don't want to put that in core because now you're going to have a dependency on azure in your core project so you would put that interface or any interface that uses those azure specific types inside of infrastructure and then put any of those services in there as well but you would typically not call them from outside of infrastructure all right so let's jump back and look at what goes in there so we'll close this down and open up just infrastructure and we're going to see there's not a whole lot there we look at this you see that we've got a data folder and in there there's the the app db context there's our ef repository and then all of our configuration of our entities is in there as well then there's just the the email sender is pretty much the only other thing there now these infrastructure modules um those are just used for the dependency injection so i can keep my dependency wire up local to the project and minimize how much reference to what i need to have inside the web project where it's going to do the the composition route of the system and wire up all those services all right so moving quickly let's talk about what goes in the web project next and the web project has anything that has to do with asp.net core so it's going to have your api endpoints or razer pages depending on if you're doing apis or you're doing something that uses forms and server-side pages alternately you can use controllers and views but i think api endpoints and razer pages are a better abstraction for both of those any dtos that are that go along with those things whether they're view models or api models or whatever you want to call them those would live here as well along with any kind of filters model binders model validators tag helpers etc this is where your composition root will live so this is where you're going to do configuration of services to say this interface is served by this actual implementation class that's called your composition wherever that happens in your app and that's going to be inside of the web project because that's the entry point for our app that's where we actually start the whole application in dotnet 5 and earlier that would be in startup.cs in.net 6 we've got new templates that have the minimal apis inside program cs so you might just do that there instead of in a separate startup class you might have other services and other interfaces there as well same rules apply as an infrastructure these are going to be services that have parameters or return types that are made up of these types of things that you see inside the web project so if it's working with view models or api models if it's dealing with controllers or views or any of that those services should live here because that's where those types are all right so let's look at a web project real quick so we jump back here close up the infrastructure open up the web and you'll see that inside of web for this template i'm basically giving you all the different options that you want to use so if you want to do api controllers that's right here if you want to use controllers and views that's here and here if you want to use api endpoints that's here and if you want to use razer pages that's here if you only want to use one of those just delete the other folders that you don't care about all right everything else in here is standard asp.net core stuff and so if we look at one of these let's go look at an api endpoint we have all the project endpoints right here they're broken out by the actual endpoint and for each one you can expand it and see right with it you know this is the request that gets sent this is the response that comes back uh and here is the endpoint itself it has just the code needed for that endpoint so instead of having a whole big controller with 5000 lines and a dozen different actions um each endpoint just has one class and its dtos are attached to it right here um so that's that's a separate thing you can go download the api endpoints nuget package if you want otherwise everything in here is just standard asp net core stuff all right so then what about sharing code between applications well for that ddd uses this shared kernel term and what it does is it holds common types that you want to share between your different apps and they're typically referenced using your core projects and ideally distributed using nuget packages okay so what goes in here well this would be all your base types for different abstractions i'm going to just show you all these and then you can pause if you want when you're watching this recording so base entities base value objects things like that common interfaces if you've got the same type of authentication you're using everywhere you might have certain interfaces that you want to keep here or user types that you want to keep here same thing for guard clauses same thing for common libraries you want to apply all that stuff could live in here however make sure you don't put any infrastructure dependencies in shared kernel because all your different core projects in all your different solutions are going to depend on this and again we really want to keep that core project your business logic from having any dependencies on shared kernel all right so let's show shared kernel project uh and then we will do a quick application demo so i'll throw this resources slide up here i want to briefly mention the eshop on web sample this is a full-fledged actual sample application it's a reference app from microsoft so you see it's a.net architecture under github i help maintain that repository there's an associated book that goes with it which is that other link there the architecting modern web apps with asp.net core and azure um download that and and read it if you want it covers a lot of these concepts as well and talks about the eshop on web sample and how it's put together all right so with that let's come in here and let's actually run this application well let's look at the the shared kernel briefly um so like i said it has a bunch of base things in here so you see there's the repository stuff is all in here base domain event base entity etc and a value object base class those are all what's inside of shared current so if we run this and give it a sec to start up by default it's going to kind of give you some documentation here on this first page this is how to use the template how to find help et cetera et cetera um in here there has all the swagger stuff set up here so if you want to look at the project endpoints they're there if you want to look at the controller the api controller it's here kind of does the same thing if we want to get a particular project there's some seed data that runs in here so if you look at project id 1 you'll see here's here's project id 1 it has 3 items in it currently none of them are done they're all false all right so then we can close this down and say well let's go uh actually complete one of these so we'll come in here we'll say i'm going to try and complete project id 1 item id 1 execute and you can do all this testing right inside of swagger and so that is gonna actually blow up because it's trying to send an email but uh you can turn on a localhost mail server but it sends the email after it does the persistence so i know it already did actually set the thing as it was supposed to so if we come in here and we execute this one again we'll see that now this one is done is true and so if you want to pull this down and play with it in addition to showing you how clean architecture works it also has domain events wired up it has specifications wired up if i show you the repository implementation in here the thing that may shock you is the fact that it doesn't need to have a whole ton of different things in it to say you know get this project by that and get that you know project with items and and give me you know this custom query the reason why it doesn't have any of that custom query logic is not just because it's it's a tiny template but also because we're able to use these specifications to perform those types of queries and so i can take all that query logic and instead of having custom methods in my repository i can just have a different specification for each one and when i need to perform a search um i can do that you know inside of like this custom search service where what you do is you just create the specification and then you call the repository and you say get by specification and it will apply that query from the specification to your data you don't have to put that inside of custom methods all right so i think we're just about out of time there might be a few questions i will throw the resources slide back up for a second and then the thank you slide and then come back to brady and see what you guys have uh in terms of questions sounds good uh we do have a few let me pull this uh screen up here uh the first question is more of a comment uh we had a nice compliment on your talk uh the clean architecture presentation might be one of the best things dot com so far so thank you for awesome talk steve um uh billy asked a question here uh are the clean architecture available in net five yes if you go to that github repo it has different versions going all the way back to i think.net core 2.1 uh they're just tagged commits so you can just click on a link there it'll take you to the right tag okay and any other question and we had uh doug asked and then asked it a second time here um i think what he was asking is uh c sharp classes and structs right here yep so you can use records uh for value objects there's some downsides to them uh value objects should be immutable and records can be uh i mean they're they're strictly immutable as they are but you can make a copy of them using the with keyword that can bypass some of your validation if you have that inside your constructor um and i don't like that so i i prefer to use a base class and actually use classes for the value objects but but records are continuing to evolve and i think we'll be able to get the the protection that we want for value objects to be able to make sure that not only are they immutable but also there's no way to construct one that bypasses the constructor and the rules that are in it uh in hopefully a future version of c sharp got it got it and i think i saw one more um this one right here uh done from uh david around.net con probably more minimal api but i know you're into that too steve stop stop yeah minimal apis are great for for starting up applications and not having to write nearly as much code to get started and start showing something that works um once you get beyond a certain number of lines of code you want to start breaking that up into methods of functions right you know kind of organize it and eventually you might move towards something that looks a lot like we had in previous versions of net where you know maybe you don't have a startup class but you might have a separate method for configuring services and a separate method for adding middleware it's totally up to you how you want to organize that so yeah you you can use minimal apis until you think that they're they're longer than you like and then you can break them up cool awesome that's awesome well i'm going to go ahead and uh add jerome to the screen and steve thank you so much as always it's been great to hear from you take care of yourself
Info
Channel: dotNET
Views: 113,824
Rating: undefined out of 5
Keywords: .NET
Id: lkmvnjypENw
Channel Id: undefined
Length: 29min 57sec (1797 seconds)
Published: Tue Nov 16 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.