 Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green, and on today's episode, we are going to talk about dependency injection, and what better person to have on the show to do that than Miguel Castro. And the guy that still talks about dependency injection. That's right. So we're going to talk about what is dependency injection, how do you do it, but more importantly, why should you do it? Absolutely. Now, am I doing it already and not knowing it? If I'm not doing it, why should I be doing it? And what problem does it solve? Well, it solves two primary problems. It solves testability and dependency resolving. And the two, one can exist without the other, but by implementing the dependency injection the right way, you've conquered two things. You've killed two birds with one stone. And you can do one or the other, and you're halfway there, but you're still missing something. So by getting full blown in the BI, you're making applications testable, and you're making the ability to resolve dependencies down what can be a complex object graph significantly easier. And instantiation of dependencies is not something trivial. It's very easy to say, I'll just new something up if I need something. But first of all, by newing something up inside a class method, you're already making the class untestable because you're causing a coupling there that probably should not be there. You're hard coding the newing of something from something else. And that's something we want to avoid. That's one of the things that dependency injection helps you remedy. Also, when you tell somebody to stop newing stuff up, you better sure as heck have a alternative for them, because that's a pretty shock and awe statement. Because you eventually have to instantiate that out. Exactly, but all you're doing is that you're offloading that responsibility to something else. That something is the product that helps us with dependency injection. A dependency injection itself is not a product. A dependency injection container is a product. DI is an architectural design pattern. And it solves these two things, testability and resolving. It solves resolving through the help of the container. It solves testability because in order to do DI correctly, you have to learn how to embrace abstract classes out to interfaces. And that helps you with the testing. So you see how the two can exist without the other, but the overlap is significant to where it's a match made in heaven for those two things. And the sad thing is, we started out the conversation by me jokingly saying, I'm the guy that's still talking about it. And I speak at a lot of conferences, and I do these kinds of talks at conferences. And I get a lot of good feedback. And then I got a lot of feedback from more advanced developers that asked me, why am I still talking about this? We've been doing this for the last 10 years. Everybody's doing it. Let me tell you something. That's one of the biggest fallacies. It is. And I'm, and it's... Everybody's doing it. Turns out that for many things, not everybody's doing it. I wish I didn't have to be talking about it, but I fill the room up when I talk about DI at a conference like today's conference. I fill the room up completely with people that just have not used it at all or not using it enough, or it's not mainstream in their everyday development. And they don't realize just how much it can help you out and how much it can remedy things, better things for you in your applications. And when I start bringing five people into the room when I do this session, maybe then I'll stop talking about it. But until then, there's still too many people out there for whom this has not become mainstream and it really does need to be. It's too good to pass up and it's very cool. When done the right way, there's a coolness element and everything we do in code, it has a coolness element. It just makes it all so much worthwhile. So let's see, let's see how to do it. All right, all right. So I got this demo broken out in the three different stages, okay? And the first stage is gonna be the problem stage. This is without the problem being solved whatsoever, okay? So what I'm gonna show you here is that I'm gonna show you a hosting class. This is the class that my UI, this is my UI right here, my console app. And in stage one, which is the one we're gonna do first of course, my main class is called the commerce class. And the commerce class, its job is just to process an order. And the order is contained in this one data object that you see here, order info, which you're looking at at the top. Just has some arbitrary information. This is not my real credit card number. I just wanna make sure there's nobody taking notes right now. But that is my real email address where people can notify me if they like or hate what they're seeing here. And as you can see, we're doing something that's completely ordinary. We're instantiating the commerce class into a variable and we're processing an order. It doesn't get simpler than that. That's anything wrong with that. Let's dive into the commerce class a little and see what's going on in there. Now, I've broken out, in the interest of separation of concerns, I've broken out the stuff that the commerce class is doing into three different subclasses, just so I can have some reusability and some code manageability. So that's not really part of what we're doing here to solve the problem, but this is something I'd expect everybody to do anyway. The billing processor, the customer processor and the notifier. The job of the billing processor is to process your credit card. The job of the customer processors to update the database with the fact that you've now purchased these products and the notifier sends you out a receipt. Simple enough, no big deal. Now, if I run this right now, all of these things are just gonna show something in the console app, nothing major. No, I am not processing anybody's credit card nor am I sending out any emails. But there's a reason that I mentioned that because what if I was? As you can see here, it says payment processed. That customer processor is calling another class. I'm gonna show you that. It's calling a data repository and it's calling a product repository to update the inventory. That's what you see there, purchase saved and inventory updated. Then the customer record is finally updated and then the receipt is sent. So you see what's taking place here. Now, if I go into that customer processor class, simple class, but as you can see, that class is instantiating two other classes. So already I've shown you two problems that I don't know if you've seen yet. The customer repository is just doing something very simple but it can just as well be doing something more complex. In reality, that customer repository is gonna update the database. The product repository is gonna update the database. Where's the problem here? This customer processor is hard coding the instantiation of these two classes. So number one, how am I gonna test this? How am I gonna write a unit test to unit test the update customer order without hitting that database? The answer is I'm not. Without hitting the database. Without hitting the database, how am I gonna do that? Without making any code changes. I can't. There is no abstraction taking place here. The instantiation of these objects. You can create a mock customer repository and then go and change the code. I can eventually do that but I gotta change some code in the way this application is written right now and sadly there's just a lot of stuff that's written this way. That's the testing part. Let's go up one level, back up to the commerce class and talk about that testing again. How am I gonna unit test process order without being locked into whatever these classes are doing? You know, local DB or SQL Express on the machine. Now you're talking about pointing to a different. Now it's just changed the connection string. Yeah, but you're not. Problem. That's not really a, I wouldn't consider that a good idea. That's not what I would wanna do. I don't wanna hit any database. I mean in a true unit test, in an integration test maybe. In a unit test, that's really not the job of the unit test. That's way too large of a unit. You're doing way too many things. So there's a lot of stuff taking place here. So this doesn't impede testing, overall testing, but it impedes unit testing. Mostly unit testing. You can't isolate the units. Right, the individual thing going on. Exactly right. You're having a hard time isolating the units. Okay. Is the screen on? Yeah. Oh, okay. All right, so that's the number one thing that's going on. I mean, I imagine running a unit test where I'm processing the credit card in the unit test, which is what I'm doing here. When I'm updating a database. If I don't unit test, I don't have to do dependency injection, right? That's my out. As much as most people would agree that that's the solution to the problem, I'm not gonna even attempt to dignify that. Unit testing has to be done. Look, none of us, not all of us really enjoy writing tests. And I'm not the biggest lover of writing tests, but I acknowledge the fact that they need to be done. It's like exception handling, right? We don't wanna do it. Exception handling at some point has to be beyond slash, slash to do. Right. You know, you gotta take care of it somehow. Somehow making the user happy is something that you have to do. So we have two problems here. Number one, if we wanted to unit test as we can. Number two, if we wanted to introduce another dependency, it's a matter of going into the level that we have to go into and instantiating that new dependency, thus adding to the problem of unit testing. Right. So we're just furthering the problem. So that's stage one. So let's fix one of these problems first. Let's concentrate on the unit testing problem, okay? We concentrate on the unit testing problem by abstracting classes to interfaces. Now I have my other folder here and I'll make sure that all this code is available to your viewers, but in this commerce class, in this stage two folder here, notice, well, I'm not gonna open that up yet for a reason, but I'm gonna start by showing you the new building processor. Now the new building processor, as you can see, it's abstracted to an interface, iBuildingProcessor. Okay. It's abstracted to an interface called iCustomerProcessor. Now the customer processor receives in the, let me open this up, in the constructor two arguments for the dependencies that we're injecting into it. This is the architectural design pattern or the code design pattern of dependency injection. Without the use of a container yet, we haven't gotten there yet, but we've abstracted out and we've injected the dependencies into whatever class is going to use them. So we've made our classes testable because now we're given the customer processor the option of what kind of customer repository implementation it is going to use. In the case of production, it's gonna use the real one that accesses the database. In the case of a test, we may actually either have a test class that does something else that we wanna do or more efficiently, we would use a mocking tool to mock up a test class, which is what most people do today. Okay. The repositories, same thing. If I go to the customer repository, it's abstracted to an interface. So everything is abstracted to an interface. So we have that nice abstraction that we're embracing and we've decoupled one class from another, one implementation from another by depending only on definitions, which of course is defined by interfaces. So now, without getting into a unit test, how do we instantiate commerce now? I'm looking at commerce here. We see that commerce, I don't know, I have no idea why it's been doing this recently to me. Yeah, I see that from time to time. Yeah, I can close it down and open it up and we're fine. So take a look at the commerce class. We see that it requires three dependencies just to be newed up. If I go into one of those dependencies like customer processor, we know that it requires two dependencies. So now the newing process has gotten a little more complicated. We've eliminated the problem from the classes itself, but now we have to, we've relocated that problem is what we've done. Right. If I go over to my- And then where do you create- Ah, well, let's open up stage two and see what happens. Now, doesn't this look beautiful? I was being totally sarcastic, by the way. Oh, that's good news. Yeah, totally sarcastic. So. A looks ugly, B looks harder. It does. See, I don't understand what gains me as I'm being paid by the line of code. Oh, it gets even harder. Now, see, what happens is that we've made these classes fully testable, which is really good news. But by doing so, we've introduced the problem of dependency resolving now because we can solve the problem like this, but notice that commerce is being instantiated with new instantiations of building processor, customer processor and notifier, and customer processor needs the instantiations of its dependencies, customer and product repositories. So it looks like a mess. So if we did this here, what have we gained? If we stopped here, we've gained testability. Because. Because we abstract it to interfaces, it can now not rely on the hard coded implementation of these interfaces in testing as well as production levels. This is production right now, but if I wanted to test the building processor, I'm sorry, the customer processor, let's go over to the customer processor. I can unit test this class now. I can unit test this method by instantiating this class from a unit test and sending into it something other than the real customer repository and the real product repository. Which you would have to have written somewhere or you mock it or you mock it. Most people would say that you mock it. That's what I would tend to agree with. There are situations where you have a set of test classes and a set of production classes. So previously, back in the building processor, if I wanted to test that. Well, building processor, in our example, building processor does not have any dependencies. Is it? Which is the first one that calls, what calls customer process? Commerce. Is it commerce? Right here. Okay. If you wanted to test process order right now, you'd have to mock building processor, customer processor and notifier and in the process of mocking customer processor, you would have to mock its dependencies. Now that's not going to change going forward with what we're gonna do because we solved the testing problem and we've given it to the testing guys if they happen to be a different team. If they're a different team, it's awesome because we can go get a drink. If it's us, which more often than not, it's gonna be the same guys. We've at least given ourselves the ability to do it. We haven't gotten to the next part yet but now we can test. Now the job of testing is a job unto itself. Writing unit test is as much of an art as writing code. So either way, in stage one or stage two, I have to have two different versions of each of the processors. Well in stage one, you don't have that choice. Stage one, you're locked in. Stage one, I'd have to create. You're locked in. Building processor and test building processor. That's it because it's being created for you inside the hosting class. Right. So here, I still might create the test building processor but I only have to create it at the very highest level. I don't have to dive down into everywhere it's called to switch from the real building processor to the test building processor. Is that right? No. If you're going to create a mock of building processor, you only need to do it if you're going to unit test a class, a class methods that needs that dependency only. I mean, if I'm unit testing building processor, let's look at the building processor class itself. Well, if I'm unit testing this particular class, it's got no dependencies and this particular implementation is probably going to call a payment gateway and process a credit card. So that's not something I would run from a unit test. But if I were to unit test customer processor, it's relying on customer repository and product repository. So I need to mock these up just to instantiate this class from a unit test. Right. And if I'm going to instantiate commerce, I need to mock up its dependencies. Okay. My apologies. No worries. Okay. So this first example, we've eliminated one of the two problems. We've made our co-testable. But like I said, if you're hung up on the complexity of the unit tests, unit tests are complex. They can be complex. There's no doubt about it. And calling a class and sending a bunch of mocks into it, you got to know how to do that. But that's just the art and the task of writing unit tests. That's not going to go away. But introducing that necessity for us is a good thing, not a bad thing. With step one, we didn't have the necessity of doing all of that because we couldn't test. Right. So we couldn't do it and that's a bad thing. So yeah, we got less work to do, but down the line, we have probably caused other problems for ourselves. Okay. So by writing, being able to test this and calling this a testable class, that's the key thing. But here's where it gets more complex. What, now I got the other problem. Dependency resolved. What if I wanted to do something else inside billing process, inside commerce, or how about inside customer processor? What if I wanted to introduce another dependency? Sounds easy enough. Do the same thing. Write another, let's say another repository. Write the repository, abstract it to an interface, send in the interface to this constructor, and then use it down in the method, right? Sounds simple enough. But now what about instantiating something to fill that argument? Now we have to start backtracking. What calls customer processor? Okay. What calls customer processor? Commerce does. So now we got to, okay. Where does it get instantiated? Well, it's not instantiated here because we did a good job of abstracting. So what calls commerce? And we start going up the chain. And we get up to the point where we instantiated commerce. And obviously if we have another dependency, something has to be inserted here. And this is just one simple app example that I put together for this webinar. Imagine this being a full blown app where this happens five layers deep, where it happens in 17 different locations all over the place. This can get to be a code management nightmare. It really can. So that is where the next problem gets solved by introducing something called a DI container dependency injection container. It's also known as a inversion of control container. Dependency injection is kind of a derivative of inversion of control. Inversion of control is a concept. Dependency injection is a type of inversion of control. There's several other types of inversion of control. Put simply, it's just giving the responsibility of control of instantiation, control of one class from one actor to another. In this case, our actor is the DI container. I like calling it a DI container. Unfortunately, we have now reached a point in software development where the word container has been yet again overloaded. Some will tell you, well, we've been calling it a container for 20 years. Yeah, but as Microsoft people, we really didn't care because that was just Linux stuff, right? But now container is dominated by products like Docker, specifically Docker because that's what Visual Studio interacts with. So what do we do? Do we refer to this as something else? I don't think that's gonna happen. So I just call it a DI container. Just use more words. So we're dealing with the DI container here. For a DI container, I wanna show you that the same abstractions are used. So I'm gonna open up stage three here and show you that the commerce class looks exactly the same. The customer processor looks exactly the same. There's my interface. Look at my customer repository. We've done exactly, I've just taken all that abstraction and moved it, okay? Now what I've done is that I've added a DI container to this project. I use a container called Autofac. To me, it's not only one of the most powerful ones, but it's also very, very easy to use. It was written with a later.net framework, so it's pretty modern. This is not product push or product placement. You use the container that you like with containers like mocking tools. Once you learn how to work with one, they all do kind of the same thing. Just choose the syntax that you like or the ones that maybe your teammate advise you to use. There's a lot of great ones out there. Castle Windsor, StructureMap, NINJECT, Unity by Microsoft. Hell, even MEPH has some container capability, even though it's not typically used as a DI container, not anymore. But I just happen to like Autofac because it does everything that I want. Is Autofac just the DI container or is there a bunch of other stuff going on? No, it's a DI container. And all of those that I mentioned are also DI containers. Just DI containers, okay. They're not plug-in frameworks like MEPH is. MEPH has DI container capability as a byproduct of its plug-in architecture. But it's not typically used for DI. It can be and I have been known to do so, but I typically use Autofac now just because I like it and it's what I know. I can program Autofac with my eyes closed. I just know everything that it can do. But the truth is these container, the guys that wrote these things are very competitive with one another. You can get Autofac, it's just an extension. It's just a NuGet package, that's all it is. All of these containers are NuGet packages. And we'll talk about this a little more later, but for these containers to work with certain .NET ancillary products like WCF, MVC, WebAPI, those things, there are some assistance needed to let the Autofac containers interact well with those products. And there's NuGet packages out there for this kind of stuff. There is a WCF extensions for Autofac. There's WebAPI extensions, MVC extensions, all sorts of fun stuff. And there's a lot of, there's a big ecosystem around all of these. So people have written additional contributions. There's Contrip projects or EX projects, things like that. So I've added Autofac to this project. And what I'm gonna do, I already showed you the classes and the classes look exactly the same. But what I'm gonna do now is show you how the instantiation looks a little different. Now, it looks like there's a lot more code here, but I'm gonna talk about this for a couple of minutes, okay? So when you deal with a DI container, you're dealing with two primary things, R and R. Not the R and R that you and I would like to take with our wives, but registry and resolve. DI containers will take care of all of the instantiation for you. But in order to be able to do that, they need to be made aware of the classes with which they're going to be working and the interfaces with which those classes are associated. So what I've done here is register everything that I need. Now, these- Okay, so you'll do this once. You'll do this once. That's exactly right. So you need it presumably. In a desktop application, this will happen in the famous splash screen. In a web application, this will happen in the global ASAX. So yes, you do this once. This doesn't have to be done anymore. There's various ways of registering using any container, including auto fact. What you're looking at here is procedural registration, meaning I do it in code. There is a way to do this with config as well. So what you're basically doing here, correct me if I'm wrong, but you're saying that any time you see an I. Okay, so now you're jumping ahead a little bit. Let me tell you what, let's start at line 71, which is the first one, okay? Here I am registering the commerce class and I am not associating it with any abstraction. There is no interface for the commerce class in this particular case. There probably should be, but there isn't, but I wanted to give you different possibilities here. If you're registering a class or an interface, it means that somewhere down the line, something is going to ask the container for that. Okay. In the case of concrete classes like commerce, where they have no association with an interface, some containers don't require them to be registered. Only if they use interfaces, some containers do. God knows why. Auto fact does, unity does also. But stuff like Ninjek, for example, does not. So you're seeing me register the commerce class here and all I'm doing is telling the container, somewhere in the future, you may see something ask you for this class. So know about it. Now the second one, I'm registering a single class called Notifier and I'm saying associate this class with the iNotifier interface. This means that when something, and I haven't gotten to what that something is, but when something in your application somewhere asks you for an iNotifier resolve, I want you to new up the Notifier class and give me that, okay? So that's I think the part that can trip you up because you look in the code and everything's an interface, but at some point you have to new up an instance of the actual Notify class, but I don't see that in code. So this is where you do it. These are instructions, exactly right. Hand it off. Exactly. The dependency injection, the DI container's job. The control has been inverted. Exactly right. So when I see iNotifier, oh, I know what to do because I need to new up Notifier. That is exactly right. And if I wanted to use a different Notifier, I just change this single line of code and everywhere in my entire application, any time I'm using iNotifier, you're gonna get another one now. I'm gonna use whatever's here. That's exactly right. That's cool. Okay, now I've just registered one class on line 72, Notifier to iNotifier. I need to do this for billing processor. I need to do it for customer processor. But I don't want to waste time doing it manually because in my example, I only had two classes. You only invented a new process. Exactly. And that's what I did here is just show you away. There's a coolness factor here and how cool is this code? Lambdas are like the coolest thing in the world. I love lambdas. Lambdas are one of those things that hit you like a rock. Like you, you don't get them, you don't get them, you don't get them. And one day, poof, you get a moment of clarity and you can deal with lambdas. All I'm doing here is saying scan this assembly for any class that ends with the word processor where I added to it where my nameshakes ends with stage three because remember, I gave you three examples. This is just from my examples. So that brings up an interesting question. Scan the assembly. So does it happen each time at startup? This happens one time at startup. Once at build? No, at startup. At startup. When this application first runs. Okay, so there is a somewhat of an increase in startup time. It's probably not noticeable. It could be. I've never noticed it. But yes, if you wanna count computing cycles, absolutely, of course there is. It's like, but it's all about returning value, right? It's like reflection. And by the way, there's gonna be a lot of reflection used. It should be fairly minimal and not really noticeable. And if you do things right, the value that you get back completely mitigates the start of time. So I'm saying find me everything that ends with a processor class in my stage three namespace and associate it with the interface that is of the same name but starts with the letter I. That's all that little magic is there. And this will take care of handling the billing and customer processor. This will take care of the customer and product repository. I do this technique with, for example, controllers. Because if you have a convention, you can do this stuff. And everybody should have conventions. You can do it with view models. Yeah, absolutely. View models, views, controllers, and WCF clients. Everything ends with the word client, at least by my convention. So, yeah, as long as you have a naming convention, which I strongly feel all teams should have good naming conventions that they're following, and they should be well-defined. And if they're well-defined, it's easy to tell what a class is doing just by what it's named. So that's what I've done here. I've registered everything. And now in line 86, I'm building the container. Okay, excuse me. So this is where it's gonna scan through the code and... Nope, nope, it's not. It's not gonna touch your code. It's just building a key value pair list, a bucket list, if you will. That sounds kind of morbid. Just a bucket of key value pairs. That's all I'm doing here. And how does it know what all the processes and repositories are yet? Well, where they are? No, we haven't gotten to that point. It just knows the classes are there. Obviously they resolve in the compiler. So it's just standing by and waiting. Now, AutoFact gives us two classes to do this with. One of them is the builder class, which you're seeing in use. And then the other one is the container class, which is a result of calling the build method. Every container is different. A lot of them have a build right off the container class, so it's not a two-step process. It's no big deal. It's just the way the container was done. Now, a typical practice is to make the container application scoped. So as you can see, I've put it into the program class in a static variable, which means if I need it anywhere throughout my application, I can just call program.container. This, for people that don't like static variables and say that, well, we don't need them in web applications, you're absolutely wrong. Because when I'll show you later, an NBC example, an NBC, when I create my container, I do it with a helper method that the AutoFact NBC integration package gives me. If you look at the code behind the scenes of that, it's actually putting the container in an application variable. So it is holding on to it because it's going to need it. So when builder.build runs, is that when it finds customer processor, customer repository? Nope, that hasn't happened yet. All it's doing is building this sort of rules. A registration list. That's it. Okay. That's absolutely right. That's all it's doing. Now, here is when that is happening. So then the up front time is less than I was asking about. It's minimal. It is minimal. Because it's not actually now looking through your code for every single time you call an eye customer process. That's correct. It does that at runtime. Yep. It does that at runtime and only for what you. An execution. And it gets to that line of code. And depending on what you ask for. Depending on what you ask for. Here in line, what line is that? Line 88, I am instantiating the commerce class. But I'm doing it very differently. Instead of saying new commerce where I am forced to provide implementations of all those arguments as many levels down in the object graph as are necessary. And I gotta know about all that. I simply, as long as my registrations are right, are done right, all I'm doing is saying, hey container, go give me a commerce class. Okay. That's all it's doing. That's all I'm asking for. Very, very easy as you can see. Compare that to this gorgeous indentation nightmare here. Got it. Okay. Much, much lighter. Yeah. Lighter to the eyes. At that point, container.resolve, it goes against commerce that says, oh, I need these additional things. And here's where to go find them. Here's where the beauty starts. Here's where the magic of DI starts. And I'm gonna put this out there before somebody starts yelling at the screen. There is reflection involved in dependency injection. All these containers work using reflection. I say that because there's a lot of people. I don't think it's bad. I think reflection is an incredibly powerful tool. Are there extra cycles involved in reflecting? Absolutely there is. But there's extra cycles involved in setting one variable to another. So it all comes back to the value that you're getting. The return on the investment. There's a lot of people out there that are really, really anal about not using reflection. I can't use it because the application slows down. You tell me how it slows down because I don't think my eye can blink fast enough. So does taking longer to get updates and fix problems because it's harder to test. Exactly right. It's all traded. Exactly right. Performance is, I think it was my buddy Bill Vaughn who you know very well said this to me a long time ago that performance is probably the most important thing in your application. And he was talking about the performance of your developers. And that's absolutely right. It really is. Now the commerce class here hasn't changed. But let me explain what the process is. When that program class told, when I asked the container to resolve the commerce class, what happens here is a recursion dream. It really is. What it does is that it doesn't instantiate commerce yet. It reflects into the constructor of commerce and sees if it has any interface-based arguments. The minute it finds one, it reflects into that one, see if the constructor has any. And it keeps doing that down the object graph until it finds a constructor that doesn't have any dependencies. Now it knows it can instantiate this class. And where does it instantiate it? What does it instantiate? By going to the containers registration list, looking for that interface and saying what class is this associated with? Ah, new this up, plug it into that argument or get it ready on standby because it's gonna go up the chain now. And if it has to resolve more, it does so. If not, if this class is now ready to resolve, it instantiates that sending in the instantiations that it just made the previous time. And it keeps doing that all the way up till it gets up to the commerce class. By the time it's ready to instantiate the commerce class, the container already has an instance of whatever class is associated with iBuildingProcessor, which in our case was the building processor class, whatever class is associated with this and whatever class is associated with the next one. And it injects all three of those instantiations into commerce. And when it injects the customer processor, if it's, it resolves that prior to this. So by the time it has something to inject right here, it's taken care of making sure that these dependencies are resolved. Right, cool. So that's how it solves the resolving process. Now, just when you think it can't get cooler, let me show you something. I have this other class here. It's called logger. Yes. It's gonna audit trail something. It's gonna log something to a log file or whatever, right? Where in my system can I use a class like this? Now, just a side note. Do you, do you have the interface in the same file as the class for readability or is that typically what you would do? No, no, it's completely readability. That's just so I don't have to waste time here in front of you guys. Yes, check. Oh no, complete. I'd have it in a different folder called abstractions or something like that. In fact, a lot of this stuff would probably be in another assembly. So this class, where would a class like this be usable in your application? There's only one answer to that question. Everywhere? Everywhere. Exactly right, everywhere. So what if I want it to do the following? What if I want it to go to customer repository and log something right here? What would I have to do? I would have to do this. Shoot, this is, I don't think code rush is installed properly here. Okay, so I'm going to, this is the only code I'm gonna write. I'm gonna add a constructor here and I would need to probably expand the scope, right? Okay, now that I did that, oops. I can go ahead and use the logger class here, right? I'm only gonna do this in one spot. But I can do this anywhere in my application at any level just by adding it to the constructor of something, right? And then again, it's easy to change the logging mechanism. Maybe you have five different types you wanna test. Maybe for development purposes you just wanna write to the output window and production, you wanna do something different. But I haven't done anything, I haven't told the container yet that it needs to know about logger. I'm gonna do that right here. I'm just simply gonna say. That's why you'd call it processor and take it out. You can, absolutely, that's perfect. You're unbelievably lazy. I totally can do that. I totally can do that. But good, that means you're paying attention. That means you're paying attention. And that's it. Now, I just registered logger. And then you can add multiple loggers, customer logger, billing logger. Well, at that point you'd probably have different. You'd use that bigger scope there. That bigger scope, right? But you have one logger here. Right here I just have one logger which is more often than not what I'm gonna be, how I'm gonna be designing an application. And as you can see, all I did was two levels into my object graph. Remember, it all started at commerce. From commerce it went to customer processor. Customer processor went to customer repository. And here I'm saying this is customer repository logger. Now I'm gonna go ahead and run the application and let's see if that log takes place. Three, there we go. Where is it? There it is right there. There it is. This is customer repository logger. So if logger was already registered, that's this step right here. Once it is registered, anywhere that I wanna use it, all I have to do is inject that dependency. You see the terminology? I love it. Rearing its head? Yeah. That's all I have to do is inject. I can put this anywhere that I want and just use it as simple as that. It will take care of instantiating it for me. The fact that I don't need to backtrack that. Imagine if we were in this stage right here. Imagine if we were there. What would I have to do to get logger working in customer repository? I would now need line 60, new stage two customer repository, would now have to have inside there new logger. Exactly. And I have to do that in a lot of different parts of the application. So I think the value of it is kind of very present in your face. Now the last example that I have here is an NBC application. This NBC application has a simple controller. And this controller is using a class here called customer service, customer repository. Customer repository is simply getting a list of people, very important people as you can see. Yes. And it's just returning it. So imagine that it's just going out to the database for this, right? As you can see, customer repository is abstracted to an interface. And if I look at that interface, it's just the definition of everything there, okay? Now if I look at the NBC controller, the NBC controller's job is to go out and get those customers and return them as a model. As you can see in line 26 to the view call customers or go get a single customer in line 31 and returning it as a model in line 32. But we need that customer repository. So how do we get the customer repository to the NBC controller? You inject it. Yeah. As simple as that. So using. What's missing here? The registration is missing. Right. Obviously I gotta build the container. No different than that program CS file built to the container. So in the global ASAX is where I'm building my control. What I'm doing here is that I'm registering my controller, exactly. Now the beauty about this, what makes it really nice is that. Pendency resolver. I'm gonna describe that. You see in this program, in the program CS file that you saw here, I kicked off the initial resolve process by asking the container to give me something. In the case of NBC, we have the control inverted even further for us because we never go and create controllers. NBC, the NBC framework creates the controller based on the route. And when it creates a controller, it does so using a controller factory. But it also does so through a dependency resolver. We have the luxury auto fact gives you a product called the auto fact. Let me open this up. The auto fact integration, NBC integration product. It's available from NuGet also. We also have one for web API. There's one for WCF as well and one for a couple of other things. And when we have that, we hook it up in the global ASAX like this. That's the answer to your question. What is auto fact dependency resolver? The default resolver that without touching this, there is a resolver built in to NBC and its job is to new up the class. Once it determines what controller needs to use, what the name of that controller is, its job is to new it up and give it to you. All of that is behind the scenes. All we've done with the architecture that NBC put in place is override how that is being resolved by telling it, don't just new it up, go ask the container for it. And as long as we did the registration possibly, it's going to ask the container to get the controller for us, which is why you're seeing line 25 through 27 register all my controllers. Got it. And once we have given the job of creating a controller to a container, we can inject anything we need into it. And that's how you do dependency injection in NBC. And this is exactly how you would do it in web API. So auto fact and these others work they all do the same thing everywhere. So wind forms, WPF, web form, a little different, a little different, a little different because in web, well in web applications using NBC, the kickoff point of code is the controller. And something is already controlling that force. Something's already given us a controller. So by us overriding what gives us the controller on line 31 there and saying get it from auto fact, we don't have to do anything else. But I can use auto fact in all of those. You absolutely can, but the resolving is going to be a little different because the kickoff process for a view or a view model in WPF, for example, is more manual. And then there is no factory that gives you a view automatically like we have a factory that gives us a controller. So there may be some manual stuff that you have to do but the concepts are all there. And then I think some of the MVVM frameworks have that built in like MVVM cross. If you're using that it already has dependency injections part of the framework, is that true? That I don't know. I've never used those. I've always done my own. I've always built my own MVVM frameworks but it wouldn't surprise me. Okay, so this is awesome. Yeah, it's cool stuff. And I wish that I would see this more mainstream. And I know it's been years and years and years that this has been available to us and that makes it even more frustrating for me. Well, I think, and one of the reasons we do this show in the first place is that people have heard about it and then they see code where there's nothing but interfaces and it's never clear where you instantiate anything and now I'm confused. And if I'm confused, forget it. I'm just gonna keep doing what I'm doing. They never bothered to learn it. Yeah. They never bothered to learn it. The way you just explained it makes it very, very easy to understand and actually start doing. It's not that hard. It's not super difficult. Most things aren't once you understand what's going on. And once you see the value of it, it just becomes so easier to write apps and to extend apps and expand them and modify them. So, but yeah, so that's it, man. Cool, thanks so much for that. No problem. All right, I hope that demystifies dependency injection. I know I'm gonna start using it all the time. I do. And we'll see you next time on Visual Studio Toolbox.