 Hi there. My name is Steve Smith, aka Ardellis. I'm a Microsoft MVP and one of the maintainers of the eShop On-Web reference application. In this short video, I'm going to show you how to add some additional features to the eShop On-Web app using Visual Studio for Mac. Let's get started. If you haven't already, you're going to want to download the eShop On-Web reference application from its location here on GitHub. Once you've done so, go ahead and open it up in Visual Studio for Mac. It should look something like this. The feature that we're going to add is an enhancement to an existing feature. Currently, if you use the application, you'll typically log in with this demo user account, then you can add items to your basket and check out. Once you've done that, you can view your orders and you can see the status is pending. Likewise, when you click on the detail page, the status is shown as pending there as well. This is hard coded into the system. Our new feature that we're going to add is an improved order status that will take into account three different options, pending, out for delivery, and delivered. When it shows out for delivery on the details page, this page here, it should also show an estimate of when the delivery should take place. And if it's been delivered, it should show the time at which it was delivered. Since this is just a demo app, we're not going to actually integrate with any shipping providers. We're just going to hard code some of these values using a formula that's based on when the order was created. Now, there are a few different ways that we could get started to build this in our application. As you may recall, this solution is broken up into three different layers. There's the web project that represents the user interface, the application core, which has our business logic, and any infrastructure project, which handles some of the ways that we communicate with other services like databases or websites or sending emails or things like that. I'm going to go ahead and start with the user interface, but you would be just as correct if you wanted to start adding this feature by looking at the business model first. The first thing we need to do is identify the pages where we're going to need to make this change. In this case, we're talking about things that affect the order. The order controller has two action methods that it uses, one that lists all the orders called my orders, and another that displays the order details called detail. This is following the MVC pattern and the views that correspond to these action methods on this controller are found in the views folder. You'll see the two of them here. The first one we're going to look at is the detail view. The detail view displays the order status here on line 23. It just takes the view model and displays the model.status property. Likewise, if we look at the my orders list, it displays the status as well on line 24. Again, it's simply taking the item that's found in the view model for this view and displays its status property. What that means is we don't actually need to make any change to these UI views at all. As long as we do the proper logic somewhere else to set the correct information in the view model, the views will do what we need them to as they stand. It's generally a good idea to minimize how much logic goes into your view. So in this case, we're not going to add any logic at all. We're going to perform the work inside the controller. Let's return to the order controller and figure out what we need to do to change how we're going to display some additional information when we're on the order detail page. Remember, we want to show both when the delivery is estimated, if the status is out for delivery, as well as when it was actually delivered, if the status is delivered. To do that, we need to change this line right here where we're currently hard coding the status to be pending in the detail action. I'm going to go ahead and introduce a new helper method to take care of this for us. Right now we don't have anything in our business model that corresponds to status, so we're going to do all the work right here in the controller and then test it out to see if it works. I'm going to create a new private method that's going to take in the full string of the status and then return a different more detailed status message when appropriate. In the case where it's pending, we're not going to make any change at all. So when that pending status comes in, we just return it as is. In the case where the status is out for delivery, we're going to add an ETA, an estimated time of arrival, and use one hour from the current time. Yes, this means it'll never actually be delivered, but that's okay. Again, it's just a demo. Notice that datetime is underscored. Visual Studio for Mac is smart and knows that we have not yet imported this using statement for system.datetime. So we can right click on this and choose a quick fix and it'll let us know that we can add the using system namespace here. That's just gone and added this line up here on line 6 for us without us having to go and do it by hand. It's also telling us that this method doesn't yet compile. It's warning us that not all code paths return a value. That's okay because we're not done yet. We need to repeat this step for when the order has been delivered. I'm going to use the line numbers to select all four of these lines so I can duplicate it easily and not have any issues with the line wrapping. Now in the case where it's delivered, we're going to specify the status and instead of giving it an ETA, we're going to say it was delivered at, we'll say an hour ago. So no matter what, when you look at this, if the status is delivered, it will tell you that it was delivered an hour ago. Now we still have not all code paths returning a value. In this case, we've used all the different statuses we expect to have. So in the event that something else is happening here, we're going to just return unknown. Okay, now the last thing to do is to call our method. So we're going to wrap this pending string here with our get detailed status call and pass it in pending for now. And that will let us verify that it still works the way it should in the basic case. So now let's go ahead and build our application and we can test that it works just as it did before. We can also modify this by hard coding it and test it with out for delivery and delivered. In the interest of time, I'm going to jump ahead and just start updating our business model so that we can support this feature and have it actually save the values. Let's close the web project and go to the application core, drill down into the entity's order aggregate folder and in there open up order. The order entity currently has a couple of properties and it sets most of its state through its constructor here. For the status, we're going to have the status just automatically default to pending. So we're going to add a new string similar to address. It's going to look like this. Now whenever we create a new order using the new keyword, its status will automatically be set to pending. And since we used a private set, there's no way for any other part of the application to modify the status of an order once it's been created. Now we want to go and set these values somewhere when that order is created. So in order to do that, we'll need to expose a couple of methods that will allow us to modify the status. Let's do that down here at the bottom. These can just be void return methods and literally all they're doing is exposing ways to set the status to particular values. Now you may wonder why it's worthwhile for us to use methods like these to set these values instead of just providing a public setter on status. This gives us a couple of different benefits. One, it preserves encapsulation so that only the order class has control over how and when that status property gets set. It might be that when that status changes, the order needs to do some additional actions. Maybe it needs to raise a domain event or do something else to let other parts of the system know that its status just changed. Maybe it can only move between certain statuses in certain ways. Maybe it doesn't make sense for something to go from delivered to pending, or from any version of pending directly to delivered without going to out for delivery first, for example. So we can control which status changes are valid and which ones aren't if we use methods like these instead of just allowing anyone to set the value. Also, this ensures that we know exactly what values can be set because there's only one place in the system where the order status is being specified. It can't just be set to some arbitrary string. As a future update, we might choose to use an enum value instead of these hard-coded strings, or we could use something like the smart enum NuGet package, which would allow us to use something similar to an enum, but with a little more flexibility and power. Now, with this, we're ready to go ahead and change how the order gets created. That happens inside of a domain service called the order service. Let's open that up and let's see where order is instantiated. It's right here. So we create the new order as part of creating the order from the basket. And it's at this point that we want to go ahead and specify some kind of status so we can test out our UI. Since this is just a demo app, we're going to just randomly set the status to something based on the current seconds on the date time. So we'll create a variable for that. And once we have that variable, we'll make sure we have the appropriate namespace. And then we'll add a couple of if conditions. We're going to modulo on the value of second and change it from pending to out for delivery or delivered based on what that value is. Once we're done, we're going to go ahead and save that order just like we were before using the order repository. All right, now we're almost ready to test the application. The last thing we need to do is we need to actually update how we set the view model. So instead of using a hard coded value, it uses the new status property on order. Let's go back to our order controller in the web project. Here in the my orders list, you can see status is being set to pending hard coded. The O in our lambda expression here represents our order. So we can specify instead of this hard coded pending value, O dot status. And then we'll do the same thing inside of the detail action, where instead of using pending here in a hard coded fashion, we'll again say order in this case, dot status. Now that we've made those two changes, we're ready to test the application. Now we're ready to test the application. We're going to add a few different orders and see if we get different status values. So we're just going to keep checking out, continue shopping. And once we have a few orders, let's view the orders. You can see we have a few different statuses here. We have delivered, we have pending, we have out for delivery. When they're delivered, we can see it was delivered at 1350, which happens to be an hour ago. And if we go back and view orders again, out for delivery, it's at 1550, about an hour from now. All right. So what would be our good next step? Now that we've updated our system with this behavior, something that we could do that would ensure that continues to work even as we make future changes is make some updates to our tests. We could easily add some unit tests to order that would verify that when we create a new order, its status defaults to being set to pending and that when we call set status out for delivery or set status delivered, it sets the status property appropriately. In addition, we could write integration tests that will verify that when we create and save an order and then retrieve it back from the database, that these status values are set and are round tripped properly to and from the data store. Finally, we could add some functional tests that would verify that after we create an order through the web application that that order is displayed correctly with the additional data on the my orders page and on the order detail page. This would ensure that rather than us having to manually test the application by logging in, adding items to my cart, checking out, repeating that multiple times, and then finally viewing the orders, we could have all of that done automatically using some tests that we could run with the click of a button. That's it for this video on how to work with the eShop on web reference application. I hope you've enjoyed this and that you'll take an opportunity to download the sample app yourself and play around with it to get a better idea for how to work with ASP.NET Core. Thanks!