Тёмный
Ardalis
Ardalis
Ardalis
Подписаться
Steve "ardalis" Smith's RU-vid channel. Find more from Steve at:
ardalis.com
twitch.tv/ardalis
twitter.com/ardalis
github.com/ardalis
facebook.com/stevenandrewsmith
C# Primary Constructor Tips
17:03
Месяц назад
You Should Blog
17:28
Месяц назад
POCO or DTO?
8:28
2 месяца назад
5 Rules For DTOs
17:56
6 месяцев назад
REPR and Clean Architecture
11:48
6 месяцев назад
Deliver Better PowerPoint Presentations
9:03
6 месяцев назад
What's New in Clean Architecture Template 9.1
11:27
7 месяцев назад
Using Ardalis Specifications with EF Core 8
13:06
7 месяцев назад
Custom Specifications with EF Core
5:33
8 месяцев назад
Log App Startup in ASP.NET Core with Serilog
8:13
9 месяцев назад
Fluent Validation in MediatR with Results
7:18
9 месяцев назад
When To Validate and When To Throw Exceptions?
11:00
10 месяцев назад
Improve Your Code with Ardalis GuardClauses
10:37
10 месяцев назад
What are Guard Clauses?
6:39
11 месяцев назад
ChatGPT Can Pair Program?!?
20:09
Год назад
Ardalis Intro
0:30
Год назад
[C#] Updating SmartEnum NuGet Package
2:00:52
3 года назад
[C#] Open Source Packages Updates
2:03:59
3 года назад
[C#] Getting Started with Azure Identity
1:43:53
3 года назад
[C#] Getting Started with Azure Identity
2:17:19
3 года назад
[C#] Updating Open Source NuGet Packages
1:58:05
3 года назад
Комментарии
@carlosirias4474
@carlosirias4474 2 дня назад
Great explanation. Thanks!
@Ardalis
@Ardalis День назад
Glad you liked it!
3 дня назад
Another issue I have had with some dotnet tooling (but cannot remember which one, as it was a really long time ago), was a Norwegian character like æøå.
@Ardalis
@Ardalis День назад
Yeah that would probably do it, also
@eser-sahin
@eser-sahin 3 дня назад
We had the same issue on azure devops, great video Ardalis, thank you.
@Ardalis
@Ardalis 3 дня назад
You're welcome!
@pazzuto
@pazzuto 3 дня назад
I found spaces in project paths to be an issue since I started using VB 6 30 years ago. I made a point to never use them from the root drive all the way down. The only place I use spaces is in the SLN name. Thanks for the video! I can image how hard this would be to troubleshoot.
@Ardalis
@Ardalis 3 дня назад
Yeah, it's not like it took days but it took longer than I'd have liked. The compiler ought to detect if weird characters might be in the path and provide a better exception message, ideally.
@williamliu8985
@williamliu8985 3 дня назад
Thanks for sharing! It would be better if the error message could output some hints like this.
@Ardalis
@Ardalis 3 дня назад
For sure! I’m going to suggest that to the team, that it try to detect known path errors.
@mahmmoudkinawy2783
@mahmmoudkinawy2783 5 дней назад
Nice video, but we need more videos for things like how to handle a lot of languages for something like product, how to handle globalization and localization for also the products
@melvinselvaraj
@melvinselvaraj 9 дней назад
Only few can explain things better & Steve is one of them ❤
@Ardalis
@Ardalis 4 дня назад
Thanks!
@krccmsitp2884
@krccmsitp2884 10 дней назад
Great stuff! 👍
@Ardalis
@Ardalis 9 дней назад
Thank you! Cheers!
@paulreinhardt6052
@paulreinhardt6052 11 дней назад
Nice clean explanation. Thanks!
@Ardalis
@Ardalis 9 дней назад
Glad it was helpful!
@Time21
@Time21 11 дней назад
great explanation
@Ardalis
@Ardalis 9 дней назад
Glad you liked it
@codeDotnet
@codeDotnet 11 дней назад
thanks so much
@Ardalis
@Ardalis 9 дней назад
You're welcome!
@Judgedredd95
@Judgedredd95 23 дня назад
Thanks, Jack Burton!
@Ardalis
@Ardalis 19 дней назад
Just remember what ol' Jack Burton does when the earth quakes, and the poison arrows fall from the sky, and the pillars of Heaven shake...
@islandparadise
@islandparadise 24 дня назад
Love this video, thanks! Question on the Result UpdateName(): Here I see that the Validation Result method is in the Entity. However if the field Name is used in several Entities, would it be practical to avoid copy-pasta by strongly typing the Name & put the validation logic there? Perhaps Name may not be the best example for my scenario, but Email could appear in multiple Entities?
@Ardalis
@Ardalis 19 дней назад
Yes, definitely. Using more Value Objects (strongly typed name) will reduce the need for validation in your entity. Ideally down to zero.
@islandparadise
@islandparadise 19 дней назад
@@Ardalis I’m on the right track, yay! Thanks! 😊
@michaelakin766
@michaelakin766 24 дня назад
Question, how can we combine your guardclauses and results into a single pattern?
@Ardalis
@Ardalis 19 дней назад
Results are meant to avoid exceptions; guards throw exceptions. If you want to combine them, you'd need a try-catch in the method that returns Result<T> and in the catch block you'd return Result.Error and provide some details there.
@Ruisrd
@Ruisrd 27 дней назад
Hey Steve, Great points around this topic, thanks for clarifying this feature, sometimes this sugar syntax can be messy. Keep doing this great work 💪🏻
@Ardalis
@Ardalis 26 дней назад
Thanks!
@iulian9796
@iulian9796 29 дней назад
Hello Steve. Nice video. Great to see you directly on my homepage :) I do have 2 short real life usage questions tho, related to a current microservice hierarchy I am developing. Could primary constructors and records be used also for commands, queries and integration bus events or would it be better to just use classes and have the whole record as a record and not one containing references? And secondly would be, why use MassTransit when you can very easily (and more performing) use MediatR for local orchestration?
@MazdakShojaie
@MazdakShojaie Месяц назад
Very well said Smith, it was amazing and from my point of view, this video was very motivated. Thanks for sharing such a great experience
@Ardalis
@Ardalis 26 дней назад
You’re welcome!
@PUBG_PRO_GAMES
@PUBG_PRO_GAMES Месяц назад
This video is very useful for me, thank you so much Steve :)
@Ardalis
@Ardalis 26 дней назад
Glad it was helpful!
@DaveRogersEsq
@DaveRogersEsq Месяц назад
Cool. Some good points there. I've only used them a couple of times and don't really understand what they bring to the table other than brevity.
@Ardalis
@Ardalis 25 дней назад
Mostly brevity, which isn't a bad thing. They're just inconsistent with how everything, even other similar things, work which makes them confusing to many devs.
@AlshafarazGazi
@AlshafarazGazi Месяц назад
Do you have a enterprise example.
@Ardalis
@Ardalis 25 дней назад
eShopOnWeb is probably the best thing to check out: github.com/NimblePros/eShopOnWeb
@dennycrane2938
@dennycrane2938 Месяц назад
FastEndpoints not supporting ctor injection for DI is big sad. I am a huge fan of this pattern though, and it jives real well with vertical slice architecture which I've been pushing really hard to point of fewer physical layers overall and it has been going very well.
@Ardalis
@Ardalis 25 дней назад
FastEndpoints uses constructor injection by default. I think maybe you mean Minimal APIs? fast-endpoints.com/docs/dependency-injection#constructor-injection
@dennycrane2938
@dennycrane2938 20 дней назад
@@Ardalis I was following Nick's video for FastEndpoints and he called it out too. I requested the services in a constructor and got an error. I had to create public properties and use the [Inject] attribute on them iirc
@dennycrane2938
@dennycrane2938 16 дней назад
@@Ardalis oh interesting. Went back and tried it again on a new project and it's fine. Fluke or added recently maybe? Oh well, I'm fully satisfied now :)
@dennycrane2938
@dennycrane2938 9 дней назад
ruh roh, endpoints dont show up in the endpoint explorer though! But I see you opened that ticket and it got closed as "no solution"
@naefp
@naefp Месяц назад
they are nice and i like to use them, but i dont understand why microsoft decided to make them mutable by default. i mean if the primary constructor parameters would always be readonly, i could still assign them to a mutable field or property when needed. instead of the other way around…
@Ardalis
@Ardalis 25 дней назад
I agree that would have been an excellent decision, in hindsight. Probably they had reasons. I think they are looking into supporting readonly in C# 13.
@christpetitjean
@christpetitjean Месяц назад
What happens with reference types mutation in method and property initialization ? Does it follow reference or is it safe ?
@Ardalis
@Ardalis 25 дней назад
You mean something like: public class A(Product product) { private Product _product = product; public void DoSomething => _product.UpdateState(); } Will this change the product that was passed into the constructor? It will behave exactly as if you had a (normal) constructor and you passed in Product there.
@christpetitjean
@christpetitjean 25 дней назад
@Ardalis not exactly. If you call product.update (the one from primary). Did this mutation also impacted _product field ? As they share the same ref, I am wondering what happens. (Mutation can also happens outside the class 😱)
@alexlo5655
@alexlo5655 Месяц назад
Hi Steve, Thank you for publishing the interesting video. However, the source code link is not working correctly. After clicking on the source code link, I was brought to a page saying, "Almost finished... We need to confirm your email address. To complete the subscription process, please click the link in the email we just sent you." Unfortunately, I haven't received any email (I've also checked the spam folder). Could you please look into this issue ? Thank you for your help
@Ardalis
@Ardalis 25 дней назад
Sorry it's not working for you. It seems to be working overall so I'm not sure what the issue is with MailChimp and your email account.
@AlshafarazGazi
@AlshafarazGazi Месяц назад
You should do a series for modular-monolith using vertical slice architecture.. :)
@Ardalis
@Ardalis 25 дней назад
I do cover this in my course on Dometrain, actually. I show how different modules can use whatever architecture is most appropriate to that module, and specifically demonstrate Clean Architecture in one module and Vertical Slice Architecture in another.
@SajadJalilian
@SajadJalilian Месяц назад
Invaluable insights rooted in years of experience. That Ardalis - Help your future self by writing about how you solved something - Create a Personal Brand - Keep it simple, just write something valuable Best advice: When you spend time learning or fixing something more than a couple of minutes. Write a blog post about it.
@Ardalis
@Ardalis Месяц назад
Thanks!
@alexvanheerden5702
@alexvanheerden5702 Месяц назад
Agree, wording is unnecessarily verbose. Does visual studio allow you to customize the toolbar? The default definitely encourages debug over run. What about hot keys? F5 is (marginally) quicker / simpler than ctrl + F5.
@Ardalis
@Ardalis Месяц назад
Yes, you can assign whatever keys you want, but in my experience it's a pain doing so because you have to redo it when you reinstall (yes, you can export/import) and it won't work whenever you work at someone else's machine (common if you pair or are a teacher/trainer)...
@paulreinhardt6052
@paulreinhardt6052 Месяц назад
🫡 Thank you for your service, Steve!
@simonkalu
@simonkalu Месяц назад
Nice... Thanks for sharing
@Ardalis
@Ardalis Месяц назад
Welcome 😊
@BicTic
@BicTic Месяц назад
why would they change it how do you go back to old update?
@Ardalis
@Ardalis Месяц назад
Why would who change what? Visual Studio hasn't changed anything, yet, although it might be good if they did so.
@BicTic
@BicTic Месяц назад
@@Ardalis yes they have, they changed the layout and moved stuff around update or re-download it and see for your self
@maradasa985
@maradasa985 2 месяца назад
Hello, your template is awesome, I am always checking it and comparing it to others, I sure love the REPR pattern, the only headache I have is how to integrate authentication and authorization while respecting the intent of the architecture. A tutorial would be awesome
@Ardalis
@Ardalis 2 месяца назад
Yeah, I need to add that at some point. A more full-fledged sample that includes auth is eShopOnWeb, available here: github.com/nimblepros/eshoponweb
@maradasa985
@maradasa985 2 месяца назад
@@Ardalis I manage to make it work for my project using jwt auth/auth with fastendpoints and swagger, if you like I can send you the repo link, maybe it will help
@br3nto
@br3nto 2 месяца назад
The difference between a POCO and a DTO: a DTO has Dto in the class name or namespace. TL;DR - don’t do that. They are both just classes, records, or structs. All classes, records, and structs are used to transfer data, otherwise there wouldn’t be a point to them. I’ve never encounter a situation where it’s useful to make a distinction that a POCO is being used as a DTO, because that’s just naturally what they are for. It’s just not useful to talk about Dto’s. Maybe you have some classes that specifically represent the API between an app boundary like between modules, or returned from web requests, or from library calls; it’s better to name these classes based on your domain model - a class, record, strict, or namespace should never have Dto or DTO in the name.
@Ardalis
@Ardalis 2 месяца назад
Yeah like I said elsewhere, use the “Dto” suffix as a last resort. And no, not all classes are used to transfer data. Consider any service, and in particular stateless services.
@kaustavchakraborty3244
@kaustavchakraborty3244 2 месяца назад
So the classes the Mediatr library uses as commands are not either DTO or POCO, as it depends on an interface.
@Ardalis
@Ardalis 2 месяца назад
They don't have behavior, so I consider them to be DTOs. You're correct, they're not POCOs, because they require a (marker) interface to function. My next video will probably be on the topic of interfaces and DTOs (and then I hope to move away from the whole DTO topic, but I might do ONE more after that).
@kaustavchakraborty3244
@kaustavchakraborty3244 2 месяца назад
@@Ardalis looking forward to that.
@0x4b55
@0x4b55 2 месяца назад
I think an override of ToString() is an acceptable behavior for a DTO; often makes debugging easier especially with a list of DTO instances
@nkesteren
@nkesteren 2 месяца назад
All these years I felt free to share a video with friends. Oh noes. 😂 👍😉
@Ardalis
@Ardalis 2 месяца назад
What? Without explicit permission from the RU-vidr? How could you! 😉
@VitaliiShmidt-UA
@VitaliiShmidt-UA 2 месяца назад
Which kind of behavoir in Domain models do you talk about? Didn't get that one. All the examples of DDD's structure that I've seen uses anonymic domain-models.🤔
@Ardalis
@Ardalis 2 месяца назад
Like these, for very simple examples: github.com/ardalis/CleanArchitecture/blob/main/sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Project.cs github.com/ardalis/CleanArchitecture/blob/main/sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItem.cs Obviously in real world systems there would be even more special cases, invariants, events, etc.
@VitaliiShmidt-UA
@VitaliiShmidt-UA 2 месяца назад
@@Ardalis very interesting, thank you for sharing 🫡
@redspidermkv4525
@redspidermkv4525 2 месяца назад
I'm a little confused.. your DTOs have public setters but the POCO you demonstrated with an Update method isn't a DTO. So a DTO can only have a default setter, if you have logic in your setter (or getter) its not a DTO?
@Ardalis
@Ardalis 2 месяца назад
Correct. DTOs are just properties. I mentioned in another comment you could have static methods for mapping or validation or whatever and that doesn't break this rule because they're not on the instance.
@alphamaster2
@alphamaster2 2 месяца назад
Now lets throw "Model" into the mix
@Ardalis
@Ardalis 2 месяца назад
Yeah, that's an overloaded term, which is why usually it's prefixed. There's Domain Model on one end and ViewModel on the other. I also see (and have used) ApiModel (since there are no views) as well, and a host of other variants. Domain Models should not be DTOs but ideally should be POCOs as much as possible. ViewModels in MVC should be DTOs, typically. But in MVVM frameworks ViewModels are where the logic lives, so it's not a 100% rule at all - depends on context. ApiModels I've only seen in MVC and are just used for transferring data over the wire, so should be DTOs.
@kurokyuu
@kurokyuu 2 месяца назад
Does a record really fit into the dto defintion? There's bunch of compiler generated code like PrintMembers, Deconstructer, a different constructor where you can also pass the record and it'll set the values from the object. it has it's own equality operators and stuff like that. Wouldn't a record in this case be more like a Poco since it has behaviour. If you're really nitpicky under the hood properties are compiled down to getter/setter which then change a private backing field~ Or, to come back to the main question, does compiler generated code not count and as long as you don't put custom code in it the record would still be considered as a dto?
@Ardalis
@Ardalis 2 месяца назад
You're not wrong, records *do* have a bunch of behavior, but it's mostly hidden away. They're very frequently used purely for data transfer purposes, though, which is why I tend to consider them DTOs by default, assuming no methods are added to them. Of course once you add your own custom/bespoke methods to your records, they cease to be DTOs.
@kurokyuu
@kurokyuu 2 месяца назад
@@Ardalis Okay, thanks for the answer. I'm using records too very often since they're very handy if your data-object is not too complex, and can be created very fast. One of the best features they've added into C#.
@josephmoreno9733
@josephmoreno9733 2 месяца назад
@@kurokyuu Take care, most of the built-in behaviors in records are not used but can increase the complexity of some scenarios, especially when using AOT.
@occularmalice
@occularmalice 2 месяца назад
We still have to explain the difference between POCOs and DTOs to people in this day and age? Faith in humanity lost.
@Ardalis
@Ardalis 2 месяца назад
Every day someone starts their programming journey. Actually, a lot of someones...
@tunawithmayo
@tunawithmayo 2 месяца назад
I like the term Passive Data Object; PDO. If you're going to transfer something to somewhere else you might call it a DTO, but it is implicitly just a Serializable.
@Miggleness
@Miggleness 2 месяца назад
I don’t know. I don’t want to ask the question “have you created the ‘p-do’ class yet?”
@Ardalis
@Ardalis 2 месяца назад
I've never seen that term before. You're welcome to try to make it a standard term, but regardless you'll run into folks already using the terms DTO and/or POCO in the dev community today. As I noted in other comments, it's useful for everyone to understand these terms so when folks use them, there's no confusion.
@peepeefrog_
@peepeefrog_ 2 месяца назад
Why would I care about the theoretical definitions?
@JansthcirlU
@JansthcirlU 2 месяца назад
Rumpelstiltskin principle
@Ardalis
@Ardalis 2 месяца назад
For better team communication mainly. If one team members suggests to another to use a DTO for something, that *means* something specific. Likewise if a complicated class is depending on some 3rd party library, suggesting replacing it with a POCO means something very clear as well... as long as you know what a POCO is. If you think POCO and DTO are the same thing, you're going to be be confused (or make the wrong change).
@jz5153
@jz5153 2 месяца назад
To be honest this knowledge will be useful on interview and only there :).
@yetanotherdex
@yetanotherdex 2 месяца назад
not quite. just had a discussion about this with a dev 2 days ago
@Ardalis
@Ardalis 2 месяца назад
This would be a pretty dumb interview question to ask, IMO. It's useful mostly for clarity on teams. If one team members suggests to another to use a DTO for something, that *means* something specific. Likewise if a complicated class is depending on some 3rd party library, suggesting replacing it with a POCO means something very clear as well... as long as you know what a POCO is. If you think POCO and DTO are the same thing, you're going to be be confused (or make the wrong change).
@br3nto
@br3nto 2 месяца назад
@@ArdalisI don’t think DTO is a useful concept to talk about. It’s useful to talk about the design of the public APIs of your app; e.g where there are modular boundaries, network boundaries, public API boundaries, it’s useful to talk about what that interface looks like. But the language used should always use the terminology of the problem domain - e.g a web request returns a response; it doesn’t return a DTO. Based on the primacy of your chosen domain model nomenclature, DTO or Dto should never be added to a class name or namespace. Otherwise you’d get superfluous names like “Responses.UsersDto” or “UsersResponseDto” or “Dtos.Users”.
2 месяца назад
”Microservices experiment” :) I have been there.
@Ardalis
@Ardalis 2 месяца назад
:)
@ItsSalesGabriel
@ItsSalesGabriel 2 месяца назад
Nice video, tkss
@Ardalis
@Ardalis 2 месяца назад
You're welcome!
@mgkeeley
@mgkeeley 2 месяца назад
Where do you think validation should go? On the DTO? Or in the ingress function that accepts the DTO? For our internal Model classes, our team likes to do validation in the constructor; but I'm not so sure that is really necessary. Validation should perhaps only be for external interfaces?
@VoroninPavel
@VoroninPavel 2 месяца назад
Both ;-) DTO requires structural correctness (required fields have values of the required length, etc), POCO (or Behavior Rich Object) guards business invariants. As you told, this is usually a responsibility of constructor or method whcih mutate state. And ther's also a validation which covers a set of aggreates, this is effectively a buiness requirement.
@ErazerPT
@ErazerPT 2 месяца назад
Think. What is validation? Behavior. What does DTO's NOT have? ... Or to put it simply, it it has anything but data, it might be many things, a DTO is NOT one of them. Which is why, IMHO, thinking about DTO's without instantly thinking "Interfaces at transmission boundaries" is deleterious, because it muddies the waters if there is no a) interface or b) transmission. Structure it like this, for a "perfect world": - there's a plain data class PDC that presents the DTO in it's simplest form, ie, plain data - there's an interface PDI that presents the DTO in it's simplest form, ie, plain data - PDC, by force of definition implements PDI and should have a constructor that takes in PDI to create a PDC - there's a business class BC that has a .New(PDI) method that returns BC ( if all is well ), or even a Tuple<enum,BC> where enum represents either OK or some error - at the egress side of the transmission, you create a PDC, and ship it out as PDI Now at the ingress side of the transmission you have two options: - you receive PDI and turn it into PDC via PDC's PDI constructor, and pass it around as plain data, which has no guarantees of sanity, or - you receive PDI and turn it into BC via BC's .New(PDI) method. And HERE is where you perform validation. If all is well, the data was sane and you move forward, if not, you do whatever is appropriate While this might sound like a lot of work, it's a minute or two per DTO, and literally peanuts if you do it from the go. And you win on the fact that a) both sides MUST respect the interface and nothing but the interface and b) with strong "gatekeeping" of the interface, nobody will go around changing it willy nilly and breaking things. It might ruffle some feathers at the start, because some people are cowboys, but eventually they "fall in line".
@Ardalis
@Ardalis 2 месяца назад
I prefer separate classes for non-trivial validation, using a library like FluentValidation. This keeps DTOs from having this. I will say that it's generally fine for DTOs to have *static* methods on them for things like validation or mapping, for instance. The *objects* are DTOs and have no behavior; the static methods are just functions that happen to be attached to those class definitions. You generally do not want to have a bunch of guard clauses or constructor-enforced rules in your DTOs. They should just be getters and setters. No encapsulation. No checks. They can have attributes to assist with validation. Why? Because you don't want serialization/deserialization to fail midway or with an exception. You'd almost always rather have a nice list of validation errors than a serialization exception with a stack trace.
@Ardalis
@Ardalis 2 месяца назад
I don't usually use interfaces for DTOs - in fact that's a likely subject of an upcoming video. There are times when it's useful but most of the time the DTO *is* the contract and there's no need to add another type that mirrors it. I have seen some good uses cases for using interfaces with DTOs but usually they're not 1:1 but rather an interface that requires a certain subset of properties that many different DTOs might have which then allows for those DTOs to be treated a certain way collectively. But having one interface for ever one DTO class isn't something I've seen value in.
@ErazerPT
@ErazerPT 2 месяца назад
@@Ardalis I don't use it as a requirement but as a "nice to have". IMHO, the interface defines the DTO and the DTO implements the definition. By using an interface, which by definition is JUST a contract, both side are STRONGLY discouraged from relying on any internals of the DTO. Or even thinking about them ;) It does add a bit of work on the deserialization side, but i find that to be worth it in the long run.
@kwameaddo1007
@kwameaddo1007 2 месяца назад
Thank you
@Ardalis
@Ardalis 2 месяца назад
You're welcome
@jorgepedraza1275
@jorgepedraza1275 2 месяца назад
The detail is that ChatGPT does not have its own criteria, it responds according to what the user expects.
@Ardalis
@Ardalis 2 месяца назад
It responds based on the vector database its model has created that guesses the most likely word to follow the stream of words it has output (in response to the stream of tokens/words that the user input).
@bogy912
@bogy912 2 месяца назад
Thanks for the video Ardalis :) I use F5 (Debug) just for the debugging, when I need to hit a breakpoint and check something at runtime. Ctrl+F5 (Run) when I want to check something on the UI or just checkt the process I made changes to :) the VS names are so so loooong, I'm a Rider user for last 6-7 years...
@Ardalis
@Ardalis 2 месяца назад
Yeah I've heard nothing but good things about Rider...
@caseyspaulding
@caseyspaulding 2 месяца назад
Great explanation. Thanks just learning this pattern
@Ardalis
@Ardalis 2 месяца назад
You are welcome!