 All right. So tell us who you are and what you're working on. But my name is Dave. I'm a web developer and I've been working on the admin screens for already. All right. Well, let's see them right on. So I'm logged into already here as an administrator and that lights up this admin section here and I can go into campaigns, which gives me a list of all the active campaigns in the system. And I can create new ones here. I can click on them to view some information about it. See the activities for that campaign and then do all the basic things like editing my campaign and deleting the campaign adding new activities. I see. So this is the sort of flow that you did. Yeah. All right. So how hard was it to do? You know, it wasn't that bad. It's using NBC six. So, you know, we have the standard controllers in the background and we have a entity framework context that we're using to get the data and save it back. So my understanding is that some of the stuff was already there. So what was it that you changed? You told me there were some fundamental changes that you made. Yeah, we changed some of the patterns that we're using. We were running into some issues with the way we were getting the data was sometimes causing problems as opposed to the way we needed. So when we're getting the data just to display it, we needed to do that differently than we were getting the data so that we could make changes to it and save it back. I see. So what we did is we started to separate that out by thinking of it in terms of read only queries. So when we're getting the data, we're using queries and when we're getting the data that way, we're never saving it back. I see. Getting the data to display it on the screen. And then when we're saving the data back, we're using commands. I see. So the commands are more the right portion of the model. I see. Well, let's take a look at some code. Maybe show us how this all works. So let's take a look at the campaign controller. So this is the controller that drives those campaign pages or we're listing them. And you'll notice probably right off the right off the start here is that there's no context coming in here. So my campaign controller doesn't have a dependency on my database context. What it's using is it's using a product called mediator. It's a new package built by Jimmy Bogard. And what that allows us to do is we set send commands on this mediator bus and then we get results from that. So I see very abstractly the controllers thinking in terms of commands or queries that it's sending off to the bus and then just getting the results from that and reacting to Let's see. Let's see the let's see one of the actions where you actually make something. Sure. So let's let's take a look at the index. So the index is where we're listing all the active campaigns. Right. So here what we're doing is we're saying we're sending a campaign list query over to the bus and then that gives us back a list of campaign summary view models which we then pass over to the view. Can we see what the campaign list where it looks like. Yeah. So it's very simple. It actually has nothing in it right now. In the future here we're going to have that scope to tenants organizations in the system. Right now it doesn't actually. So this is really just a POCO that got it is the parameters to the query. So how does a bus know to translate this list query into the DB context select statement. Yeah. So that's that's the interesting part. So that's just the query which is the things you need in order to execute the query. Sure. And it is understood by the handler the query handler which is here we have this campaign list query handler. And really the only connection between the two is that we implement I request handler and there's the that's the tieback. So that's how it knows mediator knows that if I'm executing this type of request. So that's the query type. This campaign was query to run this class and that we're going to return a number of campaigns. So this is like a really loosely coupled way of saying I have this object. Yeah. And I'm going to send this request off. Yeah. And somebody is going to take care of that. And give me back the thing. And the thing that's going to do it is whatever an I request handler is. That's right. And it's going to say OK. If you're an I request handler you're going to have this is the kind of thing I'm working on. And this is the kind of thing I'm returning. And that's what this is doing. And so it automatically sort of glues this all together with dependency injection. Whatever's going on. Yeah. All right. So this is where we're actually taking dependency on our database context. So that gets injected through the D.I. framework and B.C. six. And then when we handle the request this query that's when we're actually executing the we're creating our database here. And then we're using this link projection to project that over to our view model to do a very efficient query. We're not pulling back anything more than what we need. And then returning that back. That's pretty cool. So what would be the main reasoning for doing this type of decoupling. One thing is it makes it super easy to test. So my controller. There's that controller action. Really no point in testing it because there's nothing there. Yeah. If I was testing it the only thing I'd be testing is mediator at that point. So there's no point in doing that. But what we can do is write a test specifically for campaign list query. I see. And then all I need to do is create a new handler pass it in a context of some sort. Maybe it's probably tied to an in memory database instead of an actual SQL server database and then call the handle method and check the results to make sure it's what we expect it to be. Interesting. So the work that you did is you literally took all of this sort of like fetch logic out of the controller action method and you sort of offset it into this sort of mediator pattern. And because we're doing the other really nice thing is that because we know that it's a query and we're only ever getting that data for read only purposes to display it. We can we can really find start fine tuning that query. So one example is something that we should be doing here is as no tracking which is a hint that tells any framework. I'm never going to be changing this. I don't need all the change tracking. I see because usually what's happening is if you change a few change a property what's going to happen is going to say it's going to dirty itself. Yeah. And it's going to say hey I'm dirty. I need to be saved or something's going on. That's pretty. So we can tell it. We don't want to do that in this case because we're just querying it for read only purposes. Let's talk a little bit about sort of when you are actually you are doing it. What does that look like you're still going to use the mediator pattern. You're still going to have some handler I request handler. What does that look like. So let's start by taking a look at the edit command here. So this is the get command the get action method. So here it's a query again. We're getting the campaign summary. So very similar to what we had before. And then we have a few checks here just to make sure that the user actually has rights to edit this before we return it to the view. So that's no different early. That's just passing the data to the view. But then when it comes back that's when it is a little different. So now instead of a query. So these are just our checks here to make sure his user actually allowed to do this. We still have the validation in the in the controller here. And then this is where we're passing this over to the bus. We're saying instead of a query here we're passing in the edit campaign command. So it's a sort of query command pattern. You see in the query you're getting stuff back in the command. You're actually telling it to do something. So here we can look at the payload for this request over to the bus is a campaign summary view model. So that's the data that the user changed. And then when we look at the handler for that one's that's the edit campaign command handler. This is where we go and query for it not without the change tracking this time because we actually do want to edit it. So we have our campaign and we map all our all our properties back from the view model to the the actual EF model class call update on it. Tell any framework update this this entity and then save changes. And I like if you if you scroll up you can see that it's implementing a special interface that does the glue right that tells you what it's returning. Right. It's the same thing I request handler we have this command and then we're going to return this in. Yeah. And in this case what I'm doing is I actually use the same command bit of a cheat but using the same kind to create a new one. So first I checked to see this is there one in the database that matches this idea. If not I'm just creating a new one. And then it passes back the ID. So on my create I can actually I know the idea of the one that was created. That's what comes back and then I can redirect to the details page for that campaign. How long did it take to do this kind of refactoring. It took us a little longer than we thought initially. Just going. It's always a little longer when you're starting with something as opposed to when you're doing it from scratch. But it was about a better party yesterday. There was two or three of us working on it. How did the tool and how did Visual Studio help with all of this. Was there anything that it did that you're like man I couldn't live without this. Well you know it's the intelligence right now. So it even though the only thing that's gluing these together is this Visual Studio knows that in in my campaign controller. So I'm calling bus and bus dot send. It just takes a request. You have no idea what type it is. But as soon as I give it a strongly typed command or query here it knows what the result is. It's telling me that it's a campaign summary view model that's coming back. It's just you know that's Visual Studio. It's the way intelligence lights up and it just guides you through the process. Awesome. Well I guess I'll let you get to work. But all right. Thanks.