Clean Architecture with ASP.NET Core 3.0 • Jason Taylor • GOTO 2019
Вставка
- Опубліковано 6 вер 2024
- This presentation was recorded at GOTO Copenhagen 2019. #GOTOcon #GOTOcph
gotocph.com
Jason Taylor - Solution Architect at SSW
ABSTRACT
The explosive growth of web frameworks and the demands of users have changed the approach to building web applications. Many challenges exist, and getting started can be a daunting prospect. Let's change that now.
This talk provides practical guidance and recommendations. We will cover architecture, technologies, tools, and frameworks. We will examine strategies for organizing your projects, folders and files. We will design a system that is simple to build and maintain - all the way from development to production. You leave this talk inspired and prepared to take your enterprise application development [...]
Download slides and read the full abstract here:
gotocph.com/20...
/ gotocph
/ goto-
/ gotoconferences
#SoftwareArchitecture #dotNET #Programming #CSharp #CSharpdotNET
Looking for a unique learning experience?
Attend the next GOTO conference near you! Get your ticket at gotocon.com
SUBSCRIBE TO OUR CHANNEL - new videos posted almost daily.
www.youtube.co...
Domain layer - 8:34 key points 16:37
Application layer - 17:03 key points 31:39
Infrastructure layer - 32:07 key points 41:25
As much as I like software architecture, it often tends to get very fuzzy and abstract, when spoken about. Especially for newcomers (like myself). Therefore it's so nice to see a presentation with a lot of concrete examples and actual code. Great job!
Thanks, Noceo! 😊
@@JasonTaylorDev Hi Jason. Great presentation! What or where is the best place to send email notification? For example, every todo list that I add will send an email to me. Is it on domain or application? Thanks
Thank you very much Jason. I really like Clean Architecture and your example solution is very straight forward and easy to understand. Only 1 thing I would not use: Automapper. I don't like Automapper because it hides references and increases in most cases the code reading time. I think most people believe that Automapper saves development time, but its actually the opposite. When I refactor code or implement new functionalities and I don't have the references which would tell me where all those properties are in use, I would have to constantly look through the AutoMapper mapping profiles from each type which is involved and try to figure out what is going where and what might break if I change a property, because the compiler wont tell me due to the fact that Automapper is doing everything during runtime with reflection, but during development time I don't get any help. That costs much more time than the time you maybe saving when writing the code. And I haven't even mentioned other problems which Automapper is causing like misleading of static analysis. If you want to shrink writing time, then look rather into the Visual Studio extension MappingGenerator on GitHub ;)
Not sure if I agree with data transfer object (dto) depending on Domain Objects (do). DTO are a communication concern not a data storage concern.
Yep
I've been playing with this template for a while and now I'm getting the whole team up to a real product based on it. It has a very solid foundation, and it's a very approachable implementation.
Hi Alejandro, I'm genuinely curious about your feedback after using it in production for a couple of months. Thanks in advance.
@Andres Rondon, We are not in production yet because it's a large project. What I can tell you something about is adapting the system to our needs and the learning curve for me and my team.
I have modified some things, the entire security (following a specific requirement), the entire UI as we don't plan to use Angular at all, and some other details. There was no big problems implementing all this stuff, as the responsibilities are very well segregated.
I found useful to duplicate each layer, keeping the base proyects to reuse across all our future developments and putting our domain specific logic in separate projects. No problems with this either.
MediatR is sweet, reliable, and enables a lot of order. The MediatR pipeline is very useful, but for the non-business related topics (as logging request duration, etc.) you have to evaluate if a asp.net middleware isn’t more suitable. I kept only validation as a MediatR behaviour.
Mappping approach is nice, but you have to watch carefully the reflection hack and the implication of that autoimplemented IMapFrom interface (you have no implement interface suggestion on mapping method and no override).
Tip: Keep and eye on the template repo, as new concerns are added from time to time. The version (for .net 3.1) with I started didn’t have Domain Events and not it does.
Another Tip: Think and talk all the time on how to pull down logic into domain layer and value objects. Each achievement on this is worth.
Talking about the adoption curve, our team was coming from a very crud like approach, the new concepts were not particularly easy to assimilate, especially due to the considerable amount of new stuff. I’m trying to include some DDD and testing concepts in a progressive way, assuming that some old-style code will be leaked into the project, and (ok, never) fixed later. I thinking that maybe I walked into my own trap, but we need to produce.
One big (maybe the biggest for us) thing is EF, although is not specifically related to the architechture nor the template. Our team has a lot of xp on databases, so I kept a repository with Dapper up my sleeve, but I didn't have to use it for the moment. It took some time but people got used to query with EF.
More complicated is the code first approach and migration handling. It’s hard to know the implications of each thing you do in your entities and configuration and maintain the schema without crash the migrations. But it’s rewarding.
Right now I’m dribbling between my boss, ask me for the old development speed, and the project, begging me for more tests and a CI pipeline. I believe that is there (with CI) when we will have some more clear benefits in the middle term. In the long run, I expect lower maintenance costs and more confidence in what we put into production, a well as less “this was made by …, call him!”.
If you have a team of committed people and time (figth for it!) to do technical meetings, code reviews (I am implementing them now, as I ends up convinced that they are absolutely necessary) and bosses capable of invest into the future, I keep recommending this approach. In the other hand, I’m sure if we were to skip the guidelines, take shortcuts over the architecture and let concerns leak through the layers, we would be facing a very complicated situation.
If you walk into this,
plese tell how it went.
Regards
@@malehernandez1975 Thanks Alejandro! That was a very insightful overview of your experience with this. I may grab some approaches and patterns from this template for an upcoming project, though will not be able to start from the template itself. I will remember to post feedback if ever got something useful to add.
Thanks again and good luck for you and your team.
Regards.
@@malehernandez1975 What a detailed feedback. Thank you!!
It's a very good talk on how to achieve clean architecture, but I disagree with the definition of domain and application layers. I guess the author is not following DDD, but domain is domain whether or not DDD is followed.
I don't think domain is the enterprise wide logic and types nor application layer contains business logic and types.
If we follow DDD, the domain layer actually has the business logic, it represents the business ubiquitous language. All the business rules are there. All the important domain validations, the model itself, etc. It's not enterprise wide, it is the bounded context wide.
The application layer has the orchestration of the use cases that delegate on domain layer to achieve state mutations. Command handlers for example.
But it's a good presentation!
If this had been recorded in 2020, more than a few audience members would have fled the room when Jason kept coughing.
Joking aside, this is a fabulous presentation. Thanks!
Haha, so true. I'm going to be presenting a bit from home so I can cough freely and people will just be glad not to be in the same room with me. 😄
Thanks for the feedback Brian! 😊
@@JasonTaylorDev Just out of curiosity... I'm implementing things gleaned from your presentation(s) (I see at least two, one with updated info)... and I found myself wanting to confirm the lifetime of your Validators. Quickly discovered I don't exactly know how your project hangs together, because I couldn't immediately figure out where Validators are created. It *seems* they are created as Transients... in IPipelineBehavior implementations? I was curious what about Validators (ones that don't use db connections, at any rate) would prevent them from being Singletons.
@@brianwells990 No worries. The validators and the validation behaviour are wired-up within Application/DependencyInjection.cs. This contains an extension method to IServiceCollection and is invoked by WebUI/Startup.cs. The validation behaviour is invoked for all requests.
The default for FluentValidation in ASP.NET Core is to register validators as transient, however in the past, they were in fact registered as singleton. You can learn more about that here; github.com/FluentValidation/FluentValidation/issues/814. I'm registering them as transient to be consistent with the default behaviour and since I want to inject services from time to time. As mentioned in the above issue, the initialisation cost is low, so this scope works well. You can still register them as singleton if you like, this is covered here; docs.fluentvalidation.net/en/latest/aspnet.html.
@@JasonTaylorDev Hi Jason, I can't find your GitHub page or twitter anymore.
@@lilee5187 sorry about that. You can find me here:
github.com/jasontaylordev
twitter.com/jasontaylordev
Best architecture presentation I have watched and understood.
Look like experts thoughts about repository pattern are cut out from context... but anyway, when you use EF Core abstractions from application layer you are breaking The Dependency Rule. Also, your Infrastructure layer uses domain entities directly in DbContext, which might be okay for a really small (and useless) demo project, but will be bad in real development. Probably, most common real life example - many-to-many relations will looks differently for EF Core entities and for domain entities.
Definitely needs to be more videos like this, you listening C# content creators? Show how things actually work in the real world, what the code looks like, so much better than just an explanation!
I think CQRS makes things complicated. If the frequency of writing or reading is not very different, then there is little need to use CQRS. Also the read or write models should be quite different I think. Thanks for presentation.
Yes, you are right.
You can swap the meditor + CQRS pattern with service pattern in Application layer if you would like to or if your domain does not contain any complex logic! 😇
@@shreyasjejurkar1233 that's what we did! We replaced cqrs with service pattern and thought it's much simpler than this one. But the idea still remains
@@kunichiyawa1660 yeah. CQRS is just one of the example on how we can implement Application layer!
This is so educational plus his voice is so asmr-y
I did exactly this a couple of years back while modernizing an old webforms application, step by step! Awesome that there is new stuff on the topic coming out still. Tip for new comers is reading up on what Jimmy bogard has been blogging about for years, who Jason mentions as one of the disagreeing experts 😅 nice stuff!
I do not understand why your application/service layer returns viewmodels. This makes the application dependant on the presentation layer. For example: A mobile phone app and a desktop app might have different data needs for presentation.
Good question. Also interested
My guess is that you could convert those viewmodels into application specific models later on in each consumer. The point of returning viewmodels is security; you wouldn't want to return certain properties from the database to each consumer.
@@ajricherson1099 He could return a Dto...
@Ivan Lapitski You are correct. Use cases should return generalized DTOs, not view models. Otherwise, your app layer depends on the UI.
The disadvantage of following clean architecture strictly are leaky abstractions and over abstraction. I personally prefer the simplicity of vertical slice architecture in JBogard's literature. Great talk on the topic. The template would be very helpful, too.
Well, this is not Clean Architecture as its primary design goals are not met. Leaky abstractions are not a feature of Clean Architecture but this particular implementation, which incorrectly abstracts certain layers. You can argue against abstractions, but it's a matter of using the right tool for the job - use it where it makes sense.
Very good talk, very informative. Thank you for providing the github repo.
do you have the link please?
@@emekaegbuniwe7372 here you go github.com/jasontaylordev/CleanArchitecture
@Jason Taylor, thank you for the nice example. I am only ambiguous with the following. I've seen plenty of code, even in frameworks, which relies on an exception being thrown by the validation. I've worked for a few people, who despised this approach and preferred to have the validation result being returned as an object. Needless to say, this is mostly due to the contextual switch of try-catching it. What are your thoughts about it?
Excellent talk and a really nice take away solution
To me, clean architecture is best explained by making the distinction between compile time dependencies vs runtime dependencies. It helps explain why interfaces and implementations are in separate layers
Best tech video I've watched in a long time. Perfect level of detail.
looks good, to my regret, i can't find any architecture content in my native language, so this is really looks good
This is really amazing template. However, most of the time (at least from my experience) domain and application are really the same, if so, isn't it a little bit over engineering to separate them?
0:44 Domain represents the business and it's logic. Business logic which doesn't fit inside a domain is placed in domain service. Application layer contains use case's of the application.
This is simply amazing! it shows how easy it is to make architecture clean (in terms of uncle bobs definition) and maximal reusable
Awesome!! Really loved the no fuss, simplistic, to the point explanation❤
Thank you! Lots of new topics to look into!
Love this solution, can't wait to apply it myself!
Thank you! Indeed.
min 19 why doesn't create the sample on the fly?
where is the easy way??
I'm trying to learn and understand this architecture. The thing that bothers me is the number of classes that need to be created. There is something ying yang about being able to request an object, modify it, and send it back. Rather than request an object, format it, make changes, and then save it as some other class that doesn't even share an interface or base class. Am I crazy?
It depends on scalability of dev work. If you're expecting to have lots of engineers touching the codebase this kind of architecture makes sense because it reduces the mental overhead needed to implement new logic and features. This would be overkill for a small team that will remain small, and you likely wouldn't use this if you had an extremely large team (~1000s) that all worked in different languages because the ramp up time would not make sense. This is sensible for a large, strictly C# shop
Hi Jason Thanks a lot for this clip but I have one question here. How can I use this with MVC client . Currently I am not looking for SPA rather I am doing my project in .NET core razor pages. Can you give me some tips or any reference site.
Thank you again !
This template is so full of bugs. Out of the box you get swagger errors. Can't scaffold any identity items. Nothing works properly.
The BeUniqueTitle sql validation in not correct in a concurrency scenario. Before the time you perform the validation and the time you save the entity, another entity with the same title might have been already inserted.
Great video !! Many Thanks
I don't see how CQRS helps with modifying and maintaining. If the app is simple, it seems true. But if you move from controllers calling services which call other services to controllers sending events to be dispatched to handlers and those handlers calling services, it seems to me that complexity isn't decreasing. You have to modify both handlers and services if you change or add functionality. Is there an example of a big and complex application using CQRS? I really want to see how it works.
@Jason Taylor Why is Core project dependent on view models? Why is it creating and returning them? It should be the responsibility of Presentation layer.
I agree with that, vm - implementation is concern of presentation - layer
Good talk. Thank you.
I believe validation (in your example is a data validation) should be at the domain/data layer.
The required field is part of the domain schema construct..
Domain values are affected by command and queries, so validating those at first level will also be good.
And also domain does not contain any logic of validation, those are just clean. Domain might be share across the other application and can have different requirements and validations that's why the validations are the part of application layer and not domain layer.
Yee this is how you 'abstract' your data layer. Since he didn't want a reference to entry framework to domain so that becomes good to keep in a different layer. Your database is 80% of your application and the whole we will just swap a layer and use a new database is impossible. For example try implementing unique constraint on cosmosdb. Sql does this out of the box but cosmosdb only allows uniqueness on a single partition. So if you put that unique constraint it's not going to work unless your partition is good.
I saw many many hard to solve bugs when people switch from ef to ef core. I am still looking for someone that managed to do this with out major refactoring on a non todo app.
@@FilipCordas todo is just simple way to show real world scenarios, when you start building your next apps with this architecture, you will thank yourself by choosing this arch.
@@shreyasjejurkar1233 hey don't get me wrong a lot of the stuff here is good advice but changing the database is a myth
@@FilipCordas what do you mean by its, you meant changing database provider is hard with this type of arch?
THIS IS A SAMPLE AMAZING , THANK YOU SO MUCH
Great stuff! Thanks for sharing
I got question, if we infrastructure where all commands Queries should go as by naming convention 'Infrastructure' and all data related activities. DbContext, dataModel, Model Configuration then why we putting CQRS in Application! for me it does not make sense?
Do I understend correct that Query classes actually follow to Specification pattern?
Hello Jason,
I am using "Clean architecture".
Your blog helped me a lot to implement it.
I want to add "log4net" in "clean architecture"
Please help me.
Thank you
Did you implement the Domain-Driven Design principle to achieve Clean Architecture?
One Thing I still dont get that by adding an extension method in the Application to register the Class and interface of the Infrastructure you need to add a reference from Application to infrastructure aswell so you have infrastructure depending in Application because of the interface and the startup Project depending on infrastructur because of the Service registration for DI.
Which is kinda Bad... Since now somebody still can use the direct repo Implementation to connect to DB instead of using the interface.
Is There any way around that?
I've been waiting on you to upload this amazing talk! Thank you very much!
Thanks Kevin! 😊
Hi Jason Taylor,
I really appreciate this video, it is very helpful.
However, I am confusing a little bit.
At the beginning of the video, you mentioned that the infrastructure layer depends only on the Application. But when you explained the infrastructure, especially the AppDbContext, I saw there is a reference to Domain (ex: DbSet ), which is a cross border, isn't? I would appreciate if you have a time to reply to this question, because I could not find the answer.
I'm confused as to why the application layer has database commands - shouldn't this all be in the infrastructure layer?
Could someone please explain to me how domain.entities being used in persistent (configuration) layer without having to add a project reference from the domain layer?
Only commands should be queued in the mediatr. Queries are read-only, should be listed from the repository only
Hey Andre. Interesting idea, but I think this approach might end up with rather bloated repositories. I think MediatR is really well suited to support both commands and queries. It's support for cross-cutting concerns with behaviours is awesome.
@@JasonTaylorDev You can use application services to access repositories.The idea of cqrs is to keep writing completely apart from reading. Leaving asynchronous commands and synchronous readings
@@bandaopsi the thing is that it's not possible to wire up meditr behaviors with services because it does require IRequest.
Behaviors like logging and query response cashing
Good presentation. Thank you !!!
How to handle context switching? If I want to join more than one tables
where should the regular middlewares be added in this type of architecture?
i'm visiting this 3rd time and now i realised that i would realy like to execute GOTO 2019 from title... 2020 blows
Nice one!!!!
This was really great!
It so smart and secure! even i can´t start it from visual studio!!
Great videos,
I have one question please :
I tried to implement the clean architecture based on your template in UI side I created a WPF app and now I can’t figure out how to write handler to catch exception from the application layer those under common/exception
How to target specific framework while creating this solution template?
What about Domain Services and Domain Specifications? Don't need them anymore?
I've not taken a DDD approach in this example, but for a sufficiently complex business domain I would. Either approach works well within this design.
It's a nice presentation, but you can't call it Clean Architecture if you don't abstract persistence. Your application is still coupled to your database schema and to the limitations of the ORM.
yeah, i agree. Infra assembly dependent on domain assembly.
Nice presentation, clean archtecture, clearly explained :) Nesting handlers in Query classes is a little bit messy in my opinion. You can create separate file for handler and put it in the same folder as Query class.
No fast navigation is vital, trying to find and having to click on your handlers gives me cancer. One should not always sacrifice ease maintainability for pseudo cleanliness.
Lots of food for thought
is there something wrong with the audio? i find it too soft.
Very good talk even if hard to follow because of the accent. I would not use fluentApi for validations but specifications called by application service, then just chain potential validations warnings/errors to return as metadata. That would improve re usability when checking on submissions ranges values etc.. or validate against the DB. It's possible to use reflection against the type submitted and build the tree of validations dynamically. Few bits here and there, for complex problems I would promote more domain factories, but loved the talk. Thank you
Pretty damn good!
While executing the Add-Migration AddOneTabel command on the project Infrastructure gets the exception "Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see go.microsoft.com/fwlink/?"linkid=851728" Please help! Thank You.
Anyone can suggest what I am doing wrong ?
is there any books that covers this?
What about events?
How would you use automapper for a command, like creating a person, when working dtos.
Let's say I have a collection of EmailsDTO's (public ICollection Emails { get; set; }) in CreatePersonCommand.
How would this be used/saved in de Handle method (context) without creating a new collection (list) of Emails ?
Numerous approaches, but check out docs.automapper.org/en/stable/Reverse-Mapping-and-Unflattening.html
Any example to changes infrastructure DB layer with MongoDB ?
You can just do by changing provider in infrastructure project provided you have installed supporting ef core package for mongodb
Wonderfull!
where is the business rule in this architecture? which layer?
In Domain Layer. Avoiding anemic entiities rly helps.
Repo : github.com/jasontaylordev/CleanArchitecture
Petty nit: at 19:52 you meant to add a property CurrentPage not CurrentSize.
Yep, you're right - thanks.
Thanks man.
If anyone is interested this is a follow-up talk that I recently released: ua-cam.com/video/2UJ7mAtFuio/v-deo.html
32:37 exactly what I was thinking when using the repository pattern. If you use ef core it's the same thing. It's just that you have 1 layer for naming requests and that's it. Also Everytime you add a using statement which bloats and repeats everywhere so I am not so sure about that
Repository or not, but when you use EF Core abstractions from application layer you are breaking The Dependency Rule. This is not a Clean Architecture style
The repository pattern should completely abstract the entire persistence layer, not just the database as it's the case with EF. The presented solution tightly couples the application layer to the persistence library, a library that introduces breaking changes every few years. That's a horrible design decision if you're wanting your solution to last a decade.
Honestly DDD will not make easy to understand the project. It add extra learning curve for freshers and who new to ddd
How can I control in Login and Registration flow internally ?! ,Thank you Jason
👍
Each time Jason is giving same talk )
God if was a solution architect
Is this supposed to be KISS? omfg XD
Hey Alfredo. The simplest approach to enterprise application development. 😛 But if you do have any questions feel free to reach out on the repo - github.com/jasontaylordev/CleanArchitecture/
Simple for stupid 😜
this guy had corona when he did this right???... Otherwise its damn awesome!!!!
CQRS, a specific pattern that should be used when useful... The masses: Let's use CQRS for ALL the things!
Good talk but I have a criticism around the idea of lasting software. I think there's a fallacy in the software world which is: "you can or even should write software that lasts 20+ years." It's a nice thought and perhaps a useful guiding principle but that's just not the world we live in anymore. This is just a beautiful lie we carry around to convince people and ourselves of the great value we're creating while we pretend the entire tech world doesn't completely shift under our feet in less time. There was an era where such things were true. That era is gone. Having said that, software should be effective and reliable for its lifetime
Google Maps is 15 years old! In 5 years do you think you will use it more or less?
well if it was easy he culd make a sample on the fly... always with this languages is the same... .net is a pain head
When did Clean mean adding piles of layers. The software industry has lost its mind on this garbage. Think about how much of this due to the fact that we can't figure out how to properly reconcile object graphs and relational data. It's time to stop and think that maybe just maybe the entire approach of object relational mapping is just bonkers. I mean.. LOOK AT WHAT MUST BE DONE!
I don't want to say I have a solution (*cough* functional programming *cough*) but this is absolute madness and how it's considered to be good practice baffles me. So. Much. Boilerplate and exposition. Do you not know the misery in which you live!? lol
Can you please talk with example, rather than shooting bullets in air? 🙄🙄
@@shreyasjejurkar1233 No. It's much easier to shoot bullets in the air. :)
@@ryanleemartin7758 keep going then!
When requirements change, you'll be happy you had a robust architecture from the start. Also, collaboration is way easier when everything is split up nicely
forcing developers into the pit of success 🤣
... it is something so sad :( to see a man working on the Windows CMD terminal.
I've upgraded to the new Windows Terminal - github.com/microsoft/terminal ❤
You should try Linux 😜
The way he is coughing throughout the presentation disturbs me a lot at this time of the age ..
Surely asp.net and clean are completely at odds to eachother?
Why?
Non sense
Why?
Clearly you have not used C# or ASP.NET recently and are letting past biases color your judgement.
Russian troll?
Don't know why people bother with all this nerdy "architecture" and "best practice" shiat. ASP.NET is a piece of piss, end of. Jsut stick all the code in your action methods, keep it simple, and job done.
How to target specific framework while creating this solution template?