Are events in C# even relevant anymore?

แชร์
ฝัง
  • เผยแพร่เมื่อ 27 ก.ย. 2024

ความคิดเห็น • 391

  • @nickchapsas
    @nickchapsas  2 ปีที่แล้ว +81

    And for those wondering, there is an Rx video coming. The approach in the end is just one example of a safe and easy alternative. Not a goto for everything event related.

    • @adambickford8720
      @adambickford8720 2 ปีที่แล้ว +2

      I've been using Rx for a couple years now and really like it, especially for lots of async I/O calls. The big challenges are:
      1) In the java ecosystem blocking threads is a basic assumption, including specifications like servlet and jdbc.
      2) Its a really different way of thinking. Since everything is immutable even things like loops go away!
      Kotlin, but i think most will get the gist:
      Flux.interval(Duration.ofSeconds(1))
      .map {
      object {
      val guid = UUID.randomUUID()
      val time = LocalTime.now()
      }
      }
      .doOnNext { println(it.guid) }
      .filter { it.time.second % 5 == 0 }
      .doOnNext { println(it.time) }
      .take(10)
      .subscribe()

    • @frotes
      @frotes 2 ปีที่แล้ว +1

      Can’t wait for RX! After using RSJX, wanted to give it a shot in NET too

    • @teodorchirileanu
      @teodorchirileanu 2 ปีที่แล้ว

      Please notify me!

    • @frotes
      @frotes 2 ปีที่แล้ว +1

      Hope this one is still upcoming!

    • @austinescobedo5006
      @austinescobedo5006 2 ปีที่แล้ว +1

      @@frotes I second this!

  • @ryanlashkevich9615
    @ryanlashkevich9615 2 ปีที่แล้ว +64

    Nice try! But no way, Nick, you just replace Observer pattern with Mediator (some simple kind of), and say - Events are deprecated.
    Built-in events mechanism allows to implement push and pull notification strategies, and in case of complex systems you have to mark your classes with redundant INotificationHandler + memory traffic is probably bigger.
    So, there is space for discussion here, but not for loud sounds sort of "Events are deprecated". So personally for me - don't worth it.
    And thanks for nice content, anyway. Keep coding.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +6

      Events, the observer pattern and the mediator pattern are all separate things

    • @ryanlashkevich9615
      @ryanlashkevich9615 2 ปีที่แล้ว +34

      Events is a built-in observer pattern. Similar to IEnumerable (Iterator pattern, but implemented, actually better than officially described by GoF). My imho.

    • @wobuntu
      @wobuntu 2 ปีที่แล้ว +24

      I agree. Events have and ever will have their place in the .Net world. They are fast, lightweight, easy to use. If one doesn't understand why an object gets captured in a lambda, then pulling a blown up nuget package and introducing tons of micro classes with dependencies to that nuget package won't help them either

    • @jonathandunn9302
      @jonathandunn9302 2 ปีที่แล้ว +3

      @@wobuntu Agreed! Maybe I'm just bad at C# but for my front-end use cases in Unity Actions and Events do just fine.

    • @gnack420
      @gnack420 2 ปีที่แล้ว +5

      @@jonathandunn9302 I mean he did specifically say in the video that the context of the video is backend services, not front-end work like WinForms and UIs etc.

  • @markharrison9021
    @markharrison9021 2 ปีที่แล้ว +3

    This is another one of those .... "Don't use XXX ... it causes so many problems!!!" .... where XXX can be nulls or event etc etc. I have to say I'm struggling to remember the last time I had issues using events ... in the same way I don't think I've had problems with nulls. I know I'm becoming quite an old dog now but I'd really like to stick with my events for as long as I can. Thanks for the video.

  • @myuuiii
    @myuuiii 2 ปีที่แล้ว +55

    That blur at the start 😂 I’m curious

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +37

      Video used to have a sponsor and the write line was saying “Thanks ”, but I decided to not go with them so I blurred it. That’s why my website call-out is from another video too

    • @Gruggo
      @Gruggo 2 ปีที่แล้ว +10

      Makes sense, I was thinking "What kind of insidious nonsense are we writing to the console?"

  • @bahtiyarozdere9303
    @bahtiyarozdere9303 2 ปีที่แล้ว +10

    Thank you for great video as always.
    16:18 : I expect to have the same Guid over and over because Trainsient services follow the lifetime of its injector. Since TickerService is Singleton and even not its injector (BackgroundService) is a singleton, TransientService injected into TickerService will not be disposed until TickerService is disposed. And whenever the event methods are called it will use same TransientService. And the same instance of TransientService will have the same guid which is assigned once.
    I personally do not see a problem with event system here. I agree that MediatR is a modern approach and very flexible. However this is a bit missleading.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      The only way this would work without passing the factory of the service down would be to create a new class every time. It’s bad and I actually do events a service of not showing how bad it can really get. The feature itself isn’t bad obviously, but people (and I invite you to check on GitHub) get it more wrong than right

    • @Lokiddr
      @Lokiddr 2 ปีที่แล้ว +1

      I completly agree, if TickerService would want to new instance on every call, It would need to have a somewhat factory for TransientService, not an instance itself.

    • @T___Brown
      @T___Brown 2 ปีที่แล้ว

      Factory is definitely a shortcoming in the worker services. I have an inmplementation on stackexchange because its definitely needed.

    • @yunietpiloto4425
      @yunietpiloto4425 2 ปีที่แล้ว

      Can't you just workaround this by resolving the service every time with the IServiceProvider interface instead of injecting it into the singleton?. Nice video as always btw

    • @T___Brown
      @T___Brown 2 ปีที่แล้ว

      @@yunietpiloto4425 yes but that is seen as the servicelocator anti-pattern

  • @21yarpen
    @21yarpen 2 ปีที่แล้ว +2

    Sorry, not convinced at all.
    Your expected result which I would sum up as:
    1. Handler of event without "memory", new instance every time.
    2. async calling.
    It's not "default" setting for events, but still it's very easy to make them work that way. With simpler code in which you see the behavior. If I see code, which looks like some plain old class with injected dependensy to some service, and for some strange reason this class is instanced every time, I woud not call this code good.
    You could get the same result with just simple factory or get returning new instance change. Like one line of code and you know -> Ok, I will get new guid every time I use it.
    As for the async you have full control with events over how and when event would fire. You can filter subs, you can fire them sync, you can use tasks, queues and bilion other things with that. async handler isn't always a way do it.
    To sum up, question.
    Let change your example. I want it to write those guids on some file -> poor man simplest log.

  • @Haapavuo
    @Haapavuo 2 ปีที่แล้ว +171

    In Unity, event driven architecture is very useful to reduce dependencies between various components, such as UI, managers, controllers etc. It is also one way to prevent the use of Singletons.

    • @Wobling
      @Wobling 2 ปีที่แล้ว +36

      Highly recommend implementing a message broker / mediator into a Unity project to allow communication between systems without the need to be depdendent on one another.

    • @dahliaspumpski5837
      @dahliaspumpski5837 2 ปีที่แล้ว +4

      As someone who will be starting to use unity soon I appreciate these comments!

    • @Artmos
      @Artmos 2 ปีที่แล้ว +3

      I am going to second Atoms for Unity and would even suggest combining it with Reactive programming using UniRx

    • @Haapavuo
      @Haapavuo 2 ปีที่แล้ว +9

      @@Artmos I hate doing any referencing in the inspector since that will make debugging VERY HARD and annoying in bigger projects... You cannot see in a feasible way whether some function is called, asset referenced etc. That is why Atoms is a no-go but UniRx might be nice.

    • @Artmos
      @Artmos 2 ปีที่แล้ว +1

      @@Haapavuo I think that's personal preference. I really like having my components decoupled by using ScriptableObjects. I guess if you don't like that, another solution could be a dependency injection library.

  • @djupstaten2328
    @djupstaten2328 ปีที่แล้ว +3

    There's really no way to get around events when programming for games, where there are so many individual systems running (for instance AI/NPC) as well as player input and possibly multiplayer/server input. Also when working with speech recognizers, the recognizer isn't predictable if the speech is continuous, so events will be necessary to collect the results as they trickle in.
    One could set up ones own polling mechanisms but they tend to be a lot less sophisticated when created from within something like C# (i.e. no interop) than the stuff perfected by framework library creators over the course of many years. The top layer of event design should be handled by you of course, but under the hood there can be a lot of elaborate stuff going on to make events less expensive and just slicker, like hooking up to system interrupts or sniffing other events to start the polling, or up its frequency, only when logically necessary.

  • @logank.70
    @logank.70 2 ปีที่แล้ว +3

    I wrote something, inspired by Aurelia, called EventAggregator that is this same thing. It has been easy to test functionality that only happens when an event is published too. It's been tough since the team I'm currently working with is stuck on events but are slowly starting to see how easy event aggregation is to use in comparison to wiring events all over the place. Plus...you can have two things working together without needing to know of each other's existence. Both components have a dependency on IEventAggregator that ties them together. Just like with anything event related...have to make sure you clean up after yourself and unsubscribe from events when they aren't needed any longer. I'm a big fan of this approach to domain events.

  • @looksharp1088
    @looksharp1088 ปีที่แล้ว

    Event in C# is very powefull but alot of pple didnt know how to use it correct.
    Try to define the event as static and subscribe on constructor everytime. And you can use EventHandler instead of eventsarg object

  • @Eric-kx7do
    @Eric-kx7do 2 ปีที่แล้ว +12

    This is a clever alternative but what is the performance difference for expensive event handlers. It seems that Mediator would create and destroy the objects for every call.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +11

      But that’s fine because you want proper scoping. The risk of closure in the event handler approach is way more dangerous because it won’t be just slow it will also capture dependencies and cause bugs

    •  2 ปีที่แล้ว +3

      People are often worried about DI having to have to create many objects and that being slow or taking too much memory. In reality, if you for example have a C# class with some logic and say 4 dependencies (some injected services), the resulting piece of memory allocated for that object is really just 4 pointers to the dependencies.
      Now compare that to a foreach that creates an iterator and causes about the same. But somehow people don't think about that.

    • @ShadoFXPerino
      @ShadoFXPerino 2 ปีที่แล้ว

      @ If it's transient then it's constantly reallocating those 4 dependencies, if it's an iterator then it's just allocated once.

    •  2 ปีที่แล้ว +1

      ​@@ShadoFXPerino yes but the point I am trying to make is that people are not rational in this regard and somehow fear this one allocation of the transient object. The same people then go on and create a monster Linq in some hot spot method of some Singleton.
      In my opinion it is a good price to pay for having the scoping clearly handled.

    • @flyingmadpakke
      @flyingmadpakke 2 ปีที่แล้ว +1

      @ You are very correct on that irrational obsession, and I'll admit, I have probably obsessed just like that on more than one occasion. However, I think the impact this could have on the garbage collector when you subscribe with many handlers can be a valid concern. Of course, then your main problem is just that you think you have too many handlers, but if you subscribe with stateless objects, like most services, then you can argue that this is waste... Though I wonder, if there is an "INotificationHandler" interface, then maybe there also exists something like an "INotificationStateless" interface from which objects would be put in a singleton.

  • @ironnoriboi
    @ironnoriboi 2 ปีที่แล้ว +4

    I wonder what the performance difference is between mediatr and manually getting the transient service from the DI in the event

  • @FromBeaverton
    @FromBeaverton ปีที่แล้ว +3

    When you are writing "Hello World", you do not really need events. You can use a mediator or not. Once you start writing something meaningful, you use something like BackgroundWorker or SerialPort or other dotnet APIs, which fire events. Once you go beyond junior level, you start working on larger projects and work with third party libraries written in other languages with COM interfaces, or do tricky stuff with operating system components. They fire C# events.

    • @jfpinero
      @jfpinero 6 หลายเดือนก่อน

      I work in larger distributed systems and MediaR is just fine for decoupling certain aspects of your business layer. No need for other 3rd party libraries or COM interfaces when a simple pub/sub model is needed.

  • @kevinlloyd9507
    @kevinlloyd9507 2 ปีที่แล้ว +9

    Hey Nick, I'm a bit confused about the GUID issue. If you're requesting transient services from the BackgroundService shouldn't you inject the ServiceProvider and then get a new scope and resolve services every tick? Wouldn't that give a new GUID?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +9

      Injecting the ServiceProvider is an anti pattern called service locator. It should be avoided because you never know what services will be resolved if you do that

    • @RENAUDADAM
      @RENAUDADAM 2 ปีที่แล้ว +1

      @@nickchapsas MediatR is really just a wrapper around a service locator. If you are using Microsoft DI it is the service provider that it is calling in the end is it not?

    • @shakeuk
      @shakeuk 2 ปีที่แล้ว +1

      @@RENAUDADAM service locator pattern is an anti pattern which should be avoided in most use cases, but if you are building frameworks (such as mediator) then it can be okay, but using it as a normal way of pulling "magic" dependencies out of thin air into a class should be avoided, it makes your code hard to test. It goes against the dependency inversion principal.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +3

      @@RENAUDADAM sure but it’s not MY service locator. I don’t know about any of it and nothing in my application knows about it either. There is a big difference there. Dictionary.ContainsKey uses gotos. That doesn’t mean that I would use gotos

    • @andreamariotto348
      @andreamariotto348 2 ปีที่แล้ว

      @@nickchapsas great video man! I have a question, sorry i don't have much experience. If i want a new viewmodel for example so it has to be "empty" or as its initial state, how do i get one without saying new() or the service provider? For example the user switches between some views and everytime they have to be resetted..

  • @georgehelyar
    @georgehelyar 2 ปีที่แล้ว +4

    You can also do something similar with reactive extensions

  • @TropicsAU
    @TropicsAU 2 ปีที่แล้ว +2

    "... and you'd expect the GUID to be different every time" - Absolutely not. Since you are instantiating it during initialization of the Handler, you obviously get the same GUID every second. If you want it to be different every time, you have to create it in the handling code. If you are creating the GUID in the Handler creation but want it different every time, it is simply a programming error.

  • @bogdanbanciu1781
    @bogdanbanciu1781 2 ปีที่แล้ว +2

    The dance while pressing buttons killed me ahaha

  • @BeyondAppearances-0
    @BeyondAppearances-0 ปีที่แล้ว +1

    May this video should have been named : "Benefits of using MEDIATR for events handling."
    Instead you ask a question ? I'm ok to give my opinion :
    With MEDIATR, it just seems that the Handlers are instanciated each time so that, their constructor param which is TransientService, will just be reinstanciated before being injected.
    No magic here, this is just a MEDIATR mechanism of reinstanciating handlers here.
    Thanks for showing this MEDIATR feature but for me this is absolutely not excluding the native events feature benefits.

  • @justgame5508
    @justgame5508 2 ปีที่แล้ว +4

    Implementing async events really isn’t that much work, you can just use delegates and task with event handlers and it ends up working quite nicely, I’m surprised there isn’t for support/documentation on async events as in certain use case there very powerful

  • @DoorThief
    @DoorThief 2 ปีที่แล้ว +2

    This was finally the mediator video that clicked for me

  • @ShadoFXPerino
    @ShadoFXPerino 2 ปีที่แล้ว +3

    Object modularity vs dependency injection. If you'd have went back to Y2K and told them you're going to reinstantiate every object for every tick they'd call you a nutjob. Then we had global internet, gigs of ram, stagnating CPU clock rates, and 32-core CPUs and it didn't sound so stupid anymore.

  • @jonse5a
    @jonse5a 2 ปีที่แล้ว +1

    Events are not the most intuitive things to create. One thing I've sometimes used them for is cross thread communication, but in doing so you may also need to marshal to the other thread, since normally the thread that fires the event, also does the listener work.

    • @jonse5a
      @jonse5a 2 ปีที่แล้ว +1

      forgetting to unsubscribe from events can also be a source of memory leaks.

  • @parkercrofts6210
    @parkercrofts6210 ปีที่แล้ว

    It can't get anymore simple than this. Thank you soo much howtobasic!

  • @oldclient
    @oldclient 2 ปีที่แล้ว +2

    This video blog is confusing for me. Just don't mix the concepts of Event, 'scheduler' and 'service controller' (aka MediatR). MediatR has its pros and cons. Among its disadvantages is we can't see from a Controller who's running our request. In my opinion, from project to project, we have to choose the right tool. There are cases when Events are the best option, there are cases when we have to use the good old school Timer class and there are cases when it's better to split event requests and handlers and control their runtime under common Generic interface behavior via MediatR.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      I don’t know why you call MediatR a “service controller”. What mediator is is very specific and it’s nothing like what you describe.. There is no scheduler here either. The interval is used for demoing the events as something that would happen in a background service, not for any scheduling purpose.

    • @oldclient
      @oldclient 2 ปีที่แล้ว +1

      @@nickchapsas That's why I quoted those words. MediatR' requests represent any class which implements IRequest interface. MediatR' handlers represent any class which implements IRequestHandler interface. A class in CLR .Core can represent any behavior: a Data model, an Attribute, an EventArg, a DLL library, an Assembly (including late binding) even a Win Service. At some degree it's hard to put a line between App, Process, Assembly, AppDomain, Service, Context, because all these entities can represent each other. Events "operate" with methods while MediatR "operate" with classes, which is a different level of abstraction. This is an analogy to the Win OS' Service or Unix daemon model.

  • @mojizze
    @mojizze 2 ปีที่แล้ว +1

    One thing Visual Studio has over Rider is that to looks better in video regardless of the theme selected.

  • @lukkkasz323
    @lukkkasz323 2 ปีที่แล้ว

    0:15 great transition, at first I didn't even notice it.

  • @ADSNGreenLife
    @ADSNGreenLife 2 ปีที่แล้ว +1

    Hey Nick can you publish video of mostly used design patterns in c# and how ? And when to used it.

  • @XeonProductions
    @XeonProductions 6 หลายเดือนก่อน

    You are a fantastic teacher, I'm glad I found your videos.

  • @LeutnantJoker
    @LeutnantJoker ปีที่แล้ว +2

    This video completely dropped the ball. Madiatr not only mixes command and query with notifications, it also is a terrible implementation of command snd query since it unifies both into one irequest interface.
    Not only could you implement it better yourself in 5 minutes since command and query basically consists of just a handful of interfaces, videos like this, claiming this is somehow more modern than c# events are exactly the reason I've seen code bases overengineered and wannabe architects using mediatr for all application communication when 90% of it is synchronous.
    DONT implement solutions before you run into a problem. I HATE this "I found a new library, now I'll use it everywhere and claim this is the state of the art way of doing things, feeling smart".
    I like your videos but please be aware that videos like this are regularly used by shitty developers to make the project hell for their colleagues.
    Libraries are tools. They should be used where appropriate. Vlaiminb things like "this is how it's done nowadays" is massively damaging.

  • @CockroachSlidy
    @CockroachSlidy 2 ปีที่แล้ว +1

    Looks like something from Java to me. You have an observer/listener pattern with a mediator. I think it's good for application or system wide events as it only adds dependencies to the mediator. But for local messages C# events are better. A lot less code and slightly better performance.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      You’re mixing observer and mediator. They are completely different things. There will be an observer video coming soon

    • @CockroachSlidy
      @CockroachSlidy 2 ปีที่แล้ว

      @@nickchapsas Notification listeners are observers in your example.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      @@CockroachSlidy No they are not. They aren't observing anything. They are notification handlers but they don't listen to anything.

  • @janjonas270
    @janjonas270 ปีที่แล้ว

    maybe in set models for apps, where you can somewhat predict what component will be connected to another. But in Unity it's a lifesaver.

  • @rirajojo
    @rirajojo ปีที่แล้ว

    Interesting, because I am now using it a lot with Blazor.

  • @Dustyy01
    @Dustyy01 2 ปีที่แล้ว

    Thanks for showcasing this and also showing how to properly capture Background Services with mediatr!
    It really depends on the use case, if you really don't need any DI or developing a lib, Events are fine imo. For bigger apps I'd definitely stick to mediatr

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      Yeah there is definitely room for them I have just found that people who don’t full understand how they work end up with not properly awaited actions and or closures that lead to bugs. The mediatr approach isn’t perfect either btw but I didn’t wanna go too deep in this video so I’ll do it in another one

    • @Dustyy01
      @Dustyy01 2 ปีที่แล้ว

      @@nickchapsas you mentioned async events in the Video, are you going to make a deep dive in a future video on this? What I do know is that you need to capture the delegates invocation list or to override the + and - operators to keep track of the callbacks by yourself. I dont know if there are better solutions to this but why doesn't .net bcl provide a better way?
      And on a sidenote, I think you made your point about the usecase for events and when not to use them👌

  • @NotMarkKnopfler
    @NotMarkKnopfler 2 ปีที่แล้ว

    My first question: How on earth did you get multiple projects to show up in Rider? I can't work it out, and even the forums for Rider give the impression that they are not going to add this feature. ??

  • @alexclark6777
    @alexclark6777 2 ปีที่แล้ว +1

    So at 15:00 where you're passing in the instance of the transient service via DI... does this mean MediatR is constructing/allocating a new instance of EverySecondHandler each time that event is fired?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      It depends on the lifetime of the handler. The default is transient yes, but you can change it.

  • @Gruggo
    @Gruggo 2 ปีที่แล้ว +1

    11:59 Unrelated, but I was curious about why I often see types being passed into methods to mark an Assembly for scanning? Why not pass in the actual Assembly object, possibly obtained from Assembly.GetExecutingAssembly() ?
    Or is is purely for consistency, if the Assembly you want to refer to is not the current executing assembly, so instead you pass in a type from the aseembly you intended to target?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      It’s for deterministic execution. Code can be moved around, the project might be referenced by another project etc

  • @FarukAFeres
    @FarukAFeres 11 หลายเดือนก่อน

    I got an application in blazor build around events.
    Events only make sense around state.
    Since backend is 90% statelless then you may never need events.

  • @carlmen6567
    @carlmen6567 2 ปีที่แล้ว +43

    This makes no sense, you want to use polling instead of events. Events have their own use, you can't just obsolete them in favour of polling.

    • @M0ns1gn0r
      @M0ns1gn0r 2 ปีที่แล้ว +5

      Where did you find polling in his examples?

    • @gnack420
      @gnack420 2 ปีที่แล้ว +4

      You've misunderstood what the demo is doing. The ticker is not polling for events, it's kicking off an event at regular intervals. The handlers are still very much subscribed to the event.

    • @raptorjesus3396
      @raptorjesus3396 2 ปีที่แล้ว +1

      The publish loop just simulates events, it's not polling, but easy to misunderstand. The handler is awaiting for a event that's not polling, it's listening

    • @codewithreen5768
      @codewithreen5768 9 หลายเดือนก่อน

      Events are still very much useful in MAUI.

  • @f135ta
    @f135ta ปีที่แล้ว

    I use IServiceScopeFactory when I need to consume transient or scoped in a singleton

  • @Memento2747
    @Memento2747 6 หลายเดือนก่อน

    How do I run this Api in Visual Studio 2022 ver 17.8.6 and see a Console output? Using minimal APi with no swagger, auth or https. Only options i see is http, IIS Express and WSL...

  • @LynxxLancer
    @LynxxLancer 2 ปีที่แล้ว

    This is just an EventAggregator, which have existed for a long time. If you're writing WPF apps, then this stuff is no brainer though I still prefer events because it is much cleaner and I will always know the source of the event.

  • @JacobSmith-hj2kt
    @JacobSmith-hj2kt 2 ปีที่แล้ว

    Like the video, but a question: In the handlers, why did you do the pattern Console.WriteLine(...); return Task.Completed... instead of await Console.Out.WriteLineAsync(...); ?

  • @ARVash
    @ARVash 2 ปีที่แล้ว +1

    I think this is interesting. I don't know that it completely makes events irrelevant to me but it seems like a nice pattern to reach for when you know there's going to be many consumers. You can avoid using labels/goto if people get upset by using while(true){} .
    It does make me a little sad how much indirection is required or at least normal convention in C#. I wonder how much of the unit testing is actually useful and productive in a typesafe language, and how we probably could be putting more constraint in our constructors/properties to lose the need for several unit tests. I'm not advising anyone actually do that as a general philosophy, because I think that's a terrible idea at face value, but I do think that maybe someone should be exploring the idea. Can you just defend the boundaries of the object and obviate classes of unit test.

  • @AkioJunichiro
    @AkioJunichiro 2 ปีที่แล้ว +3

    For me it's a design problem but anyway c# isn't just for apps back, events and observable pattern is still relevant for video games

  • @EspenSkaufel
    @EspenSkaufel 2 ปีที่แล้ว +1

    🍎 and 🍊. Not deprecated at all. What about file system, network or other devices? I has to be a callback or event.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Not at all. You can hook up whatever you want in there, they don’t have to be events. Also a callback and an event are 🍎 and 🍊

    • @EspenSkaufel
      @EspenSkaufel 2 ปีที่แล้ว

      ​@@nickchapsas My point was that events should not be used in the same circumstances as mediator notifications, but events and callbacks can. If I were to create something like the FileSystemWatcher, using mediator would be a bizarre implementation. Also, it would be fun if libraries started to implement events as mediator notifications and disagreed on what version or library to use.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      @@EspenSkaufel Ofc they are not the same, I never said they are, but the Notifications implementation of MediatR can give you an argueably better alternative for this usecase. Ofc you would not use MediatR for the usecase you mentioned. An observer pattern would be way better here. Events can be used to implement callbacks. Notifications can be used to implement events. Events as a concept is the root, not the end. Event he callbacks you mention aren't events. They are just callbacks triggers by something. That something can be events but it can be something else too.

    • @EspenSkaufel
      @EspenSkaufel 2 ปีที่แล้ว

      @@nickchapsas Sorry for being annoying, bad habit. Your title triggered the response, as I expect to see developers trying to avoid using events at all costs after watching this. Knowing when to use what is why experience matters in software development. Just like with inheritance, it is bad most times, good sometimes 🥴.

  • @davilinkicefire
    @davilinkicefire 2 ปีที่แล้ว +1

    I think your backend example and the explanation is a little bit flawed because it's not really showing a problem using EVENT but a problem with background service and dependency lifetime.
    Technically i can achieve the expected output by resolving TickerService in the while loop (by injecting IServiceProvider in the constructor instead of TickerService) , but it will surely not be the correct way because it would create a new service, a new event handler and so on and greatly impact the performance because the Garbage Collector will have more work to do.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Closures are a problem no matter the concept. Unless you’re instantiating classes all over the place, you will eventually have people mess it up. I’ve only rarely seen it not wrong

    • @davilinkicefire
      @davilinkicefire 2 ปีที่แล้ว +1

      @@nickchapsas i agree, but i just feel a bit mislead by the example and the wording of your explanation. Because if you remove the event pattern, the problem will still be there, you still get the same guid. I understand the problem you're trying to demonstrate but the example wasn't really adequate, maybe is too simple to see the real danger.

  • @RoughSubset
    @RoughSubset 2 ปีที่แล้ว +3

    Nick you such a legend bro, I learn so much from you, keep it up!

  • @xeoneraldo1254
    @xeoneraldo1254 2 ปีที่แล้ว

    Really love your videos 😍 keep coding and stay safe

  • @shaihulud4515
    @shaihulud4515 ปีที่แล้ว

    Now, that I finally wrapped my head around events and event handling, it's outdated. I'm too old for this...

  • @easycodeunity3d14
    @easycodeunity3d14 2 ปีที่แล้ว +1

    Nick, it's amazing but not that new. Check UniRx MessageBroker class usage.

  • @computer9764
    @computer9764 2 ปีที่แล้ว +1

    Shoutout for Reactive Extensions ✌

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      That’s something that I’ll be taking a look at very soon btw

    • @fatalfailure6240
      @fatalfailure6240 2 ปีที่แล้ว

      If I can use IObservable and Rx, I try to use them every time. DryIoc has a simple built-in mediator which I added IObservable into, works great. Always thought Mediatr was a bulky library but it seems it's straightforward as well.

  • @MrEnvisioner
    @MrEnvisioner 2 ปีที่แล้ว

    Despite the fact that I was aware of the existence of the `event` keyword in C# due to my experiments in the Unity game engine, my webdev job always just creates an interface with some async handler methods, a manager that loads services implementing the interface via DI, and then executes all of the async methods before or after whatever operations it performs. Now I wonder what value there might be in refactoring such things into `event` instances and the subscriptions to them. Thoughts?

  • @devchannel5232
    @devchannel5232 2 ปีที่แล้ว +1

    Sry, for this maybe "stupid" question, but if you attach the eventHandler in the constructor then how you detach the eventHandler, if the object is destroyed? Do you have to overwrite the destruct constructor (~TickerService)? Or what will be best solution?

    • @TheToeb
      @TheToeb 2 ปีที่แล้ว

      no need, since when tickerservice is collected also its methods are collected. you do need to be wary of events and eventhandlers though, in other cases you could cause a memory leak

    • @devchannel5232
      @devchannel5232 2 ปีที่แล้ว

      @@TheToeb Memory leak is what i thought. So the gc will take care of this case...thanks!

    • @agsystems8220
      @agsystems8220 2 ปีที่แล้ว +1

      Not really a stupid question at all, and hits at the root of the problem. The difference between the two models is who 'owns' what. In the older event model the event handler is responsible for doing the work. The event pulls in the objects it needs, and then does the work. The object itself has no idea what might happen to it, which can be a problem if that object might want to do something that those closures need to know about (such as being disposed of, or switched out). In the publishing model data is pushed to objects, and the event has no idea what might be done with that data. The major difference is that the object definitely knows about event handler, and so can definitely send messages back to it. 2 way communication is possible, and basic functionality can be available by default (such as dependency injection, or disposal).
      Unfortunately there is no general answer to what an event closure should do in the case of disposal of one of it's dependencies, but defaulting to disposing itself (and informing it's other dependencies it has done so) seems reasonable. It is inherently a 2 way communication problem. Standard events are a lightweight solution where we know that one way communication is sufficient, but for anything above the lowest levels it usually isn't. How you extend it to a 2 way system is a more complicated problem, and I'm not qualified to post an opinion on what the 'best' way is. My first thought would be that you would definitely want to be wrapping it rather than using events directly though. Whatever you do will come with some overhead, which is why we still want the normal event system.

    • @TheToeb
      @TheToeb 2 ปีที่แล้ว

      @@agsystems8220 Just as an aside I tend to go away from events other than when it is necessary to interact with third party libraries. Instead I use System.Reactive / IObservable/ IObserver because it allows more control over subscription and disposal as well as bringing in alot of functionality (reactive.linq) also it might be more lightweight than a larger system such as mediatr (though i haven't measured it)

  •  2 ปีที่แล้ว +1

    Can you make a video about NativeAOT?

  • @JayBlackthorne
    @JayBlackthorne 2 ปีที่แล้ว

    Your event example captures keypresses. You don't capture keypresses in your background service example.
    I must be missing the entire point somehow?
    I stopped using events when I stopped building WinForm applications. It's all WebAPI calls these days.

  • @stef2528
    @stef2528 ปีที่แล้ว

    Awesome! Thank you :-)

  • @maurohefti1157
    @maurohefti1157 2 ปีที่แล้ว +1

    Thanks for the great video. If I have a worker as a hosted service. This then fetches new orders every second as an example. This is done in a separate class where a HttpClient is needed. (Injected in the class which inhetit from BackgroundService) How does it make sense to use these mediator notifications? Are there other advantages than "only" the handling of the lifecycles? Greetings from Switzerland

    • @ryan-heath
      @ryan-heath 2 ปีที่แล้ว

      Another approach could be to get an instance of the separate class via an injected ServiceProvider (core's IOC container). As a result the lifetime of the separate class (and its dependencies) is observed.

    • @maurohefti1157
      @maurohefti1157 2 ปีที่แล้ว

      @@ryan-heath Thx for yout answer. Yes, that's right. But for me, the lifetime doesn't really matter. Should you still prefer the notification pattern? For out use case ServiceProvider often is an anti pattern.

    • @ryan-heath
      @ryan-heath 2 ปีที่แล้ว

      @@maurohefti1157 for a singleton background service I don’t think service provider is an anti pattern, but in general it is an anti pattern, yes.
      Would I use a notification service for something that runs every few seconds? No. We have timers for that.
      Your service fetches for new orders. If there was a “new order arrived” event, then subscribing to such event would make more sense than pooling each few seconds for new orders.

  • @teodorchirileanu
    @teodorchirileanu 2 ปีที่แล้ว

    Thanks

  • @zbugi8537
    @zbugi8537 2 ปีที่แล้ว

    How to unsubscribe one "Mediator Event Handler" ?

  • @ThugLifeModafocah
    @ThugLifeModafocah ปีที่แล้ว

    This is a really good content. Thank you.

  • @logicchild
    @logicchild 2 ปีที่แล้ว +1

    It's not dead; it's just not a best practice in dependency injection :)

  • @SirPrsty
    @SirPrsty 2 ปีที่แล้ว

    thanks master, but we can use new guid before publish? its same right? and use transient services

  • @rolandtennapel5058
    @rolandtennapel5058 2 ปีที่แล้ว

    So...why are all the GUID's different when I do this using events (used custom delegate / EventHandler and only System.GUID as an argument instead of a System.EventArgs)? 😅 I think the objection here is purely on the pre-built System.EventArgs, not so much the whole event system (which doesn't rely on it AT ALL, it's just the default and recommended use of). The only reason this should fail is because the System.GUID instance wasn't destroyed yet; The Argument object hasn't been disposed of yet. If the effects are the issue, then the solution should be focussed on the problem... I guess what I'm saying is that if you want all your listeners to have a different GUID, just make an argument object with GUID { get { return System.Guid.NewGuid(); } }, or accept that what you put in (in Invoke) is what you'll get out (as it should)...

  • @christianstadler6575
    @christianstadler6575 2 ปีที่แล้ว +1

    Hi Nick, Thanks for sharing this video with us. It's awesome. I did not know about this lib. For more complex scenarios I was using most of the times Akka.Net. But for all in process communications this lib is perfect. Could you also please share your sample code with us?

    • @sidmendax
      @sidmendax 2 ปีที่แล้ว

      That is the standard code for mediaR.
      But seriouly akka is a nightmare for big projects; I am working in one.
      I wonder why we can’t have a simpler approach like this one or other pub/sub approaches while handling some situations like this.
      This would made life easier for the people who would be working on the projects javing akka in backend…
      Btw you can simply search for mediatR examples for .net core.

  • @jorgerochagualtieri
    @jorgerochagualtieri 2 ปีที่แล้ว

    What about performance? Does MediatR delivery the same performance as old fashioned events?

  • @clearlyunwell
    @clearlyunwell 2 ปีที่แล้ว +1

    14:48 “But,… and there’s a BIG BUT…” 😂

  • @antonmartyniuk
    @antonmartyniuk 2 ปีที่แล้ว +5

    I like assigning the empty default value to the event to prevent any checks in the code. public event EventHandler ButtonPressed = delegate {};

  • @Rajeshsingh-ws5th
    @Rajeshsingh-ws5th 2 ปีที่แล้ว

    But Nick one of your video you said MediatoR will take more memory and will it be fit for every time, like a silver bullet?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      I dont think that the memory allocated here is prohibitive. If you need the most efficient version possible you can totally build something custom or use events but you have to be extremely careful because they can lead to bad performance too

  • @cnikolov
    @cnikolov 2 ปีที่แล้ว

    I wouldn't say its dead node js is progressing a alot on events, also if you don want to use packages you could use the observer pattern.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      Absolutely. This video isn’t about the concept of events but about the event keyword and mechanism

  • @DF-ov1zm
    @DF-ov1zm ปีที่แล้ว

    Looks like MediatR is kind of a hammer for Nick and there is a bunch of nails around 😁

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 2 ปีที่แล้ว

    Events are relevant. It's how the IObservable stuff works and it's how you notify other classes of state changes in any UI context.
    IMediator is cool if you're not doing UI work. There's also TPL.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Observable works with callbacks not events

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 2 ปีที่แล้ว

      Yeah, that's what I get for commenting on something I haven't touched for 5 years. INotifyPropertyChanged does indeed use callbacks. But the UI is still driven by events.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 2 ปีที่แล้ว

      @@nickchapsas Do you think IMediator replaces TPL?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      @@7th_CAV_Trooper I think you misunderstood me. I think that the event keyword and that event mechanism is irrelevant. Not events/callbacks or delegates as a concept. Just that specific implementation of the event feature. MAUI, Blazor etc can still use events internally but you only interact with the implementation of those events, not with the event itself.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 2 ปีที่แล้ว

      @@nickchapsas yeah, I'm with you now. btw, love your channel and share your videos often.

  • @NawfalHasan
    @NawfalHasan 2 ปีที่แล้ว

    This is called weak event pattern and has been around since. NET 1.1 days. There are various forms of it, with varying benefits. But I agree I like it more than events which are bit more cumbersome.

  • @Xero_Wolf
    @Xero_Wolf 11 หลายเดือนก่อน

    I think I've been spoiled by using GDScript too much lol. Signals are basically Godot's version of events but it's so much simpler to implement. You setup, connect to and emit a signal in just three lines of code. I guess because I'm new to C# but this is gonna take some time to sink in.

  • @josephizang6187
    @josephizang6187 2 ปีที่แล้ว

    Man, Nick great video again.

  • @yummybunny7351
    @yummybunny7351 2 ปีที่แล้ว

    Hi, Nick! At 4:47 i see autocorrection "handELR" -> "handLER". What plagin You use for that?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +7

      Video editing 😂

  • @kevinmerrell9952
    @kevinmerrell9952 2 ปีที่แล้ว

    Good post. Thank you.

  • @Krilllind
    @Krilllind 2 ปีที่แล้ว

    Message busses like RabbitMQ uses traditional events (which I agree on, it's not very elegant). Is there any way to use an implementation like Mediator for that?
    I see many people using traditional event handlers for Async messaging in micro service architecture.

    • @jasdefer
      @jasdefer 2 ปีที่แล้ว +1

      Maybe building a wrapper for each event? Of course you still need to subscribe to an event, but you wouldn't have the scoping problem.

  • @HaythemKaroui
    @HaythemKaroui ปีที่แล้ว

    Nice alternative to classic events management inside an api managing server. Really good job and keep up!🎉

  • @MrIsrael3000
    @MrIsrael3000 ปีที่แล้ว

    In this case would be similar to have Masstransit in place instead of MediaR, I will have more benefits (persistence, queuing) what is your opinion?

    • @jfpinero
      @jfpinero 6 หลายเดือนก่อน

      Sometimes you don't need persistence and/or queuing. You just want to decouple some action from running in the same namespace for example.

  • @ColinM9991
    @ColinM9991 2 ปีที่แล้ว

    What a coincidence! I've recently had this thought as to why the classic event based approach isn't as prevalent in apps nowadays. In reality, we've just moved to a more message bus based pub-sub model, such as MediatR.
    By the way, I was unaware of MediatR having a notification based model. Thank you for sharing! I was planning on going with something like RabbitMQ for a personal project but actually MediatR notifications are perfect.

  • @benniebees
    @benniebees 2 ปีที่แล้ว

    But why do we need events, or a library for this? On types that expose "events" just create a dictionary of Action. When the event is fired, all Actions in the dictionary are executed. To subscribe, call the public Sub(Action a) method that returns a key, and pass the key into a public Unsubscribe(Key k) method to unsub.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Yeah you can totally do that. I wanted to show us safer way that you can’t get wrong

    • @wobuntu
      @wobuntu 2 ปีที่แล้ว

      @iLikeCookiesQ totally agree. Much simpler, no need for yet another extra nuget lib, easier to read, etc. Not everything needs to be blown up into its own class hierarchy

  • @titiksasanti2205
    @titiksasanti2205 ปีที่แล้ว

    thanks BRo

  • @lexxynubbers
    @lexxynubbers 2 ปีที่แล้ว +1

    This is great. Now I don't have to regret never getting my head around events.

  • @martijnvanderham4317
    @martijnvanderham4317 7 วันที่ผ่านมา

    Wow! Did’t know speedy gonzalez was programming these days

  • @damn_right_man8606
    @damn_right_man8606 ปีที่แล้ว

    Why not drop the lambda and go for oldschool eventhandling.... Do not See any Benefit besides that easy async....

  • @Dippps
    @Dippps 2 ปีที่แล้ว

    you could not use lambda, but instead make new method with id, and it give you different id

  • @Alex-gj2uz
    @Alex-gj2uz 2 ปีที่แล้ว

    I was actually curious that with the goto code it doesnt spam the console resp. onbuttonpressed event with null or string empty :)

    • @gnack420
      @gnack420 2 ปีที่แล้ว

      The Console.ReadKey() method will wait for a key to be pressed before continuing.

  • @rodyu8077
    @rodyu8077 ปีที่แล้ว

    i enjoyed this video.
    Did not understand a single thing however.

  • @TheNeozas
    @TheNeozas 2 ปีที่แล้ว

    Mediator feels like old good Publisher/Subscriber for those, who don't have an events :D Actually lots of Notification/MessaginCenters raised and fell since I had met them for the first time in 2008-2009, seems Microsoft had got a couple themselves in this decade. And for me personally it has one big downside - debugging them is a hell (as well as events)
    Personaly, I don't think that events are dead in .net as long as Microsoft keeps INotifyPropertyChnaged and MVVM in their frameworks and doing natifve UI with languages, that does not support any kind of events can become a big pain - Java frameworks and Mac/iOS use Strategy pattern for this
    The real alternative in .NET for events is System.Reactive namespace with old but good IObservables and maybe you can do some videos about it too :)

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      You’re the second person spoiling one of my next videos. Yea a video on Reactive is coming. 😀

  • @Sad-Lemon
    @Sad-Lemon 2 ปีที่แล้ว

    This is neat! Thanks!

  • @ChristophLoacker
    @ChristophLoacker 2 ปีที่แล้ว

    while i do get the point of what you're explaining i'm not sure if one is better than the other. you compare the observer pattern with mediator the pattern 🤔

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      Events aren’t the observer pattern. They can be used to implement it, but at their core they are just that. Events. You can use them to implement both the observer pattern or the mediator pattern. At the end of the day, this usecase is about in process pub/sub. If you want proper observer you should use RX anyway

    • @ChristophLoacker
      @ChristophLoacker 2 ปีที่แล้ว

      @@nickchapsas Sad to see you keep deleting my comments pointing out that your not 100% right. Made you lose a day-1-fan

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      @@ChristophLoacker I am not deleting any comments. TH-cam is notorious for deleting comments automatically that it assumes is spam. I have no control over this auto-moderation.

  • @lukassinkus6162
    @lukassinkus6162 2 ปีที่แล้ว

    Could you use record types to simplify those arg classes with constructor injection and a getter?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      No because they need to extend EventArgs and it kinda defeats the purpose of the record. If you do manual eventing then yeah you can

    • @Kirides
      @Kirides 2 ปีที่แล้ว

      @@nickchapsas actually,you don't have to subclass eventargs. EventHandler is just a convention and nothing more than an Action.
      Just create an event with an Action based delegate and everything is dandy.
      This also allows for async events, by using Func though the invocation of those is harder, since you have to get the multicast delegates invocation list and cast them to the respective Func to await the calls properly...
      I'd never think of providing a library that is strictly coupled to mediator or another library to provide events to an application.

  • @HollandHiking
    @HollandHiking 2 ปีที่แล้ว

    Aren't notification snot just implemented events bottom line but well hidden for the programmer? I agree in backend code I never had to use events. Timers is one of the rare moments you may consider this. I would not call it obsolete. In the UI layer events make a lot easier. I still remember programming windows applications in C, which did not support events and the huge difference it made when I learned C++ Windows programming using the MFC library.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Yeah so this video isn't against events, as in the concept. It's about the event keyword and how clunky and outdated that feels nowadays.

  • @bar10dr
    @bar10dr 2 ปีที่แล้ว

    Blazor uses events, it can be handy

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Yes because, like I mentioned in the video, for MAUI, Blazor or WinForm that Microsoft themselves has implemented all the internal eventing structure and they just give you the callback to play with, it’s totally fine because it’s very hard to mess it up

  • @kwstaslalaounis3212
    @kwstaslalaounis3212 2 ปีที่แล้ว

    Thank you Nick this tutorial it was very helpfullllllllllll!!!!!!

  • @DmitryV_HF
    @DmitryV_HF 2 ปีที่แล้ว

    Again an interesting topic. ;)
    But there is not enough proof! that the TransientService in Singltone mode also works correctly.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +4

      Yeah but that wasn’t the point. The point was that it captures the service in the closure and the lifetime doesn’t matter so it’s fundamentally flawed

  • @warny1978
    @warny1978 2 ปีที่แล้ว

    I don't think that MediatR and Events stands for the same utilisation.
    The right use of mediatR is well demonstrated here.
    Events are used to cast messages to subscribers. With events, the receipter must subscribe to the event to start receiving messages. You can subscribe or unsubscribe events dynamicaly, which is pretty convenient in a form based application scenario. Events had been designed for components to communicate back with it’s parent component or with other related components. It has not been designed for broadcasting messages across an entire application, even if it’s possible to do so.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      Your dependency injection is the subscription. You are right that you can't unsubscribe with mediatR but the truth is that I never had to unsubscribe event handlers. There is probably a usecase for that but it's not my experience. Also MediatR is just a means to pub/sub. You might use observer or you might use something else. I just believe that events in their rawest form isn't something you should be using. Obviously for Blazor, WinForms or MAUI they are used, and that's totally fine because Micrsoft is handling the eventing internally and you just get the handlers.

    • @warny1978
      @warny1978 2 ปีที่แล้ว

      @@nickchapsas MediatR, implicitly subscribe classes. Events cast to explicitly subscribed functions. These architectures are so different that I can't think of using one in place of another.

  • @TheZimberto
    @TheZimberto 2 ปีที่แล้ว

    The quick answer to this question is a definite YES! Mediatr may work well in some scenarios but having tried it I can tell you that it didn't work for me and I ended up using plain old C# events. One gotcha with Mediatr is that it news-up INotificationHandler objects as transients so you should not apply that interface to any classes that shouldn't be transient (such as Razor pages). I think something like Mediatr would be good in a CQRS system, but there is still a place for C# events where dependencies between event publishers and subscribers are explicit.

  • @Wizatek
    @Wizatek 2 ปีที่แล้ว +1

    easy = better, so yes events are still relevant

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Easy to get wrong = dangerous

  • @ericvosselmans5657
    @ericvosselmans5657 2 ปีที่แล้ว

    wow. fantastic content.