Demo: Adding Navigation and Routes
Now that we are all wizards when it comes to routing and navigation, let's return to Bethany's site. In this demo, we are going to enable routing and configure the different routes. I'm then going to also return to the layout and set up the menu for the site. Finally, we'll also use tag helpers we've just seen to allow us include navigation between the different pages in our site. So far, when we were using the application in the browser, we actually could see pages. So there was already some route active. If I would, for example, go to pie/list, I would get a list of all pies. The reason that this was actually working, was because we added at the very beginning of this course, the UseMvcWithDefaultRoute anywhere. Let's go to the definition of this one. And let's take a look at the comment here. Let's go over here. And you can see that a default route with the following template was added. So the controller defaults to home, the action defaults to index, and the id is optional. If I browse to the root of the application with no controller action or id specified, I will automatically see the home controllers index action. That's what we saw so far. I'm going to replace this. And instead, I'm going to use app.UseMvc(). There's an overload that accepts an action where I can configure my routes. I'm going to do that next. In here, I can now add a new route. Using the routes.MapRoute(). This method now accepts the name of the route as well as the template. So name will be, let's say default. And for a template, I'm going to use, well, let's use a default route again. There we go. Now just using this doesn't really add any extras to my application. I'm going to add another route. But before I do that, I'm going to make a change to my pie controller. I'm going to update the list method, so it accepts a parameter. Let's call this parameter category. Instead of using this hard-coded category that we've been using so far, I'm going to update the code here as well, and paste in another snippet. I'm going to check if the passed in category is null or empty and if so, I'm going to return all pies and set the current category to all pies. If not, I'm going to filter the pies that have the category that was passed in. And I'm going to return that data in a PiesListViewModel again. Let's save that. And go back to the startup file. Let's now add another route. It's very important that we think of the sequence that we put our routes in the UseMvc method here. In general, we'll have to put the more specific routes more to the top because as soon as a match is found it will use that particular route. I've added another route here. I've given it a name categoryfilter, and take a look at the template. The template now contains a static part, pie, then there's the action, and then an optional category parameter. I've also passed in some defaults. The control of it should be used as the pie controller and the action is list. If we look at this list action method in the pie controller, we will be able to use that route that we've just added to invoke this action and we can optionally pass in a category. Let us test our new route. We're still arriving on the home page. So the home controller with the index action is still reachable. That's good news. If I now paste in /Pie/List/Cheese cakes, I will now invoke the list action method passing in the category cheese cakes, and the filtered list is being returned. That's what we wanted. For the second route that we added, it is also doing its job. And the next thing I want to do is to complete the menu at the top. I'm going to fast forward a little bit, and then show you what I've added. I have added a couple of items that I'll show you in the next couple of minutes. Let us now continue by completing the navigation for our site. The first thing I'll do is I'll go to my view imports file, and I'll add support for all the built-in tag helpers that come with the ASP.net core MVC framework. I'm using the asterisk here to indicate that I want to include all tag helpers in the Microsoft ASP.net core MVC tag helpers assembly. So now I can use those throughout all my views. For example, let's go to the shared pie overview summary. When I click on the anchor tag that contains the name, I'll want to navigate to the details action on the pie controller. And I'll need to pass in the id of the selected pie. I'll use for that the ASP controller tag helper. And you'll notice that intelliSense knows about this tag helper since it's highlighting it. I've set this to pie. I'll do the same for the ASP action. And I'll set that to details. And finally, I'll use the asp-route-id tag helper to pass in the parameter value and that will be pie id. So I'll use @Model.PieId. I'll also add the AddToCart button. I've used this
here within there a paragraph, and in there an anchor tag. I've used a Bootstrap class to make this look like a button. The controller points to the ShoppingCart controller, the ASP action points to the AddToShoppingCart action method and again, I'll pass in a parameter PieId______. This will point to the AddToShoppingCart method that I've added earlier to the ShoppingCart controller. It accepts, indeed, the PieId______. It will let us search for the pie using the pie repository and add it to my shopping cart. I will then be redirected to the next action. I'll copy all this code to my other partial view, the PieOfTheWeekSummary. The next thing I'll do is I'll complete a menu of my application. The menu is of course located in the layout file. We've added the navbar already. In here, I'll add my Home link, that's another link with some tag helpers in there. And I will do the same for the Contact Us link. And that one is pointing us to the index action on the Contact controller that we've already added as well. Now I have done a small fast forward earlier in this demo, and that was because I've added another view component. Let me show you that view component very quickly. In my components folder, I've added this category menu. This one is actually going to ask the category repository for all categories and is returning that to the view. The corresponding view can be found in the components category menu sub-folder. And in here, I'm looking over all categories. And I'm adding an anchor tag in there as well. I'm again using my tag helper's ASP controller, ASP action, and ASP route with the parameter "category". Finally, I'll also add another that points to all pies. In my layout, I've now added one more line here that is invoking my category menu so the view component like you've done before. As I run the application again, and there's our menu. There's also a pop-out menu. I will be seeing all the pies with the corresponding category, or I can also ask to view all pies. I can now click on one of the pies, and I will be seeing the detailed page. I can also here click on add to cart and this pie will now be added to my cart. Notice that our shopping cart is now working fine as well. We see one item in the cart, and we also see the shopping cart summary showing that I now have one item in my cart. I think we can be very happy at this point. We now have a fully-functioning website, built entirely with ASP.net core MVC.
This module was very welcome I think. It allows us to navigate between the different pages we have so far created in this course, making our site much easier to work with. Let us quickly summarize what we have looked at in this module. We have started by exploring the routing system that comes with ASP.net core MVC. I've removed the built-in routing system that was in my start-up class until now. And I've replaced it with routes I've now defined myself. We've also added more navigational concepts in the application. To allow ASP.net core MVC to create links, we have used the built-in tag helpers. I hope you'll agree with me that tag helpers really help us with the creation of clean HTML. That's all I have for this module. In the next module, we'll take a look at how we can create a form to place orders in Bethany's pie shop. Thanks for watching.
Ordering with the Form
Hi there, and good to see you back here for yet another module of the Building Your First ASP.NET Core Web Application here on Pluralsight. Our site is not looking great. At the end of the last module, we've included navigation and a menu, and it's now starting to look like a real site. I'm pretty happy already with the result, and if you've been following along, I hope you are happy too. In this module, we are going to be focusing on just one screen, the order form. That intention probably was already clear to you when you looked at the title of this module. Let's start by taking a look at the overview of this module and what you will be learning. The order form is quite logically a form. With the dawn of ASP.NET MVC Core, a lot of novelties were introduced that we can use in combination with HTML forms. And in that area, I'm talking about tag helpers. I wasn't lying when I said that tag helpers were an important asset in the newer version of ASP.NET, and this is already the third time that we're encountering them in this course. So, I hope you believe me now. When we will have created the form, we'll also look at how we can add validation to the model and we'll see how we can improve the form so that the validation rules will kick in when the user has entered invalid data.
Using Tag Helpers to Create the Form
Demo: Creating the Order Form
Now that you have a good understanding of tag helpers that shape with ASP.NET Core MVC, let's return to the demo. We are going to add support for creating orders in the application. I'll quickly show you the order controller and the related domain classes. Then we'll create the order form using several tag helpers. We will also make sure that the navigation to our order form is correctly wired up. Let us now create our order form. I've already created a couple of classes, and I'm going to show you those first. Again, if you're following along, these are available in the snippets for this module. I've created the order class, which contains some basic properties. Each order does have a list of order lines, and these are of type OrderDetail. The OrderDetail class I've also created as well. It contains the forward key to the order, that is the order ID, the pie, as well as the amount that I'm ordering of the particular pie, the price, and then also again some virtual properties to make sure that entity framework core is happy. In my MDB context, I have created two more DB sets, Orders and OrderDetails. I've compiled the application, and I've then added an auto migration, and I've done an update database. I've compiled the application, and I've executed the add migration command as well as the update database command. If you're following along, make sure that you execute these commands as well. I've also taken the liberty to already create the IOrderRepository, which has just one method create. Order, as accepting an order. I've also already created the OrderRepository class, which is using the shopping cart and the MDB context, and implements, of course, the CreateOrder method. In here, I'm adding the order to the MDB context orders, and then I'm looping over all shopping cart items. For each item in the shopping cart, I then create a new OrderDetail and I add those to the OrderDetails collection on the MDB context. Finally, I call these SafeChanges on the MDB context to commit the data to the database. The last thing I've done here is registering the OrderRepository with the Dependency Injection container. Since we are planning to create the order screen, I'll of course need another controller. In the controls folder, I'll add the OrderController. And the OrderController is using the OrderRepository as well as the ShoppingCart class. I'm going to rename the index method into checkout, as that will be the action that I'm using here. It is simply, at this point, going to return the view. I'll create the corresponding view in the views folder. I create the order folder, and in here, I'll create another new view, which is called checkout. It is, of course, the same the name as the action that we've created on the controller. This view will be typed to the order model. Since the user will be entering data, I'll need to create an HTML form. The form tag helper is using the asp-action tag helper that is pointing to the checkout action method. The method is set to post. I'm then going to create a form by adding a couple of divs. In this div, I'm creating, first, a label that has the asp-for tag helper set to LastName. LastName is a property here on my order class. Then, I'm using an input that is also setting the asp-for to LastName. The asp-for tag helper is basically going to extract the name of the property on my order class. At this point, this will still be a last name, but we'll change that later in this module. After, I base it in all other input fields and then labels. All of these are mapping to properties on my order model. I'm also going to add a button here. It's simply an input with the time set to submit and the value to complete order. The form is ready for now. There's one thing I need to do, and that is making sure that I can navigate from the shopping cart to the checkout page. Down here, below this table, I'll paste in another link that is going to invoke the action checkout on the order controller. That is the one that we've just created. Let's run the application again. I'll add another pie to my cart, and then go to checkout now. As you can see, the labels are just using the property names and that's not very clean. I'll need to make some changes to my model to make sure that my form looks better. Let's go back to the slides.
I'm pretty happy about the order form that we have created so far. Although it works nicely at this point, I don't think Bethany will be extremely happy though. It's possible for everyone to just enter incorrect data or even skip several fields. I believe that many orders won't be correctly delivered. To solve this, I'm going to add validation so that we can be sure that the data we'll be receiving is correctly formatted. Before we look at how we can control the validation process, we have to take a look at how ASP.NET Core MVC will match the data coming from the HTTP request with the arguments that are action method needs. This process is called model binding. Using model binding, the objects which are required as input parameters for action methods are created based on the data retrieved from the HTTP request. Imagine that we have an action method that requires an ID of type int s parameter. MVC needs a value to be in there in order to be able to call this method. The process called model binding will try to find a value for this ID parameter. When we do a request for /pie/detail/1 we actually want the one to go into the ID field. Model binding will do this for us. Now, for this purpose, it will use model binders. Model binders are components which will help providing the values from a certain location in the request. For example, there's a model binder that will search in the form data of the request. Another model binder will search the route variables. The third one will search in the query stream. This list of model binders will actually be invoked in this order, and as soon as a match is found, the process will stop and pass the value to our action method. Imagine that we have a route where we have segment ID defined. In this case, the value will come from the route variable and the model binder can provide us with the correct value. Model binding not only works for simple values, but it also works for complex types, such as an entire object. In this case, the model binding agent will look at the target's object properties and it will search for these instead. Again, using the model binding. Imagine that we are creating an order, so we'll be passing several values from the client side such as order ID, total and so on. Model binding will do it best to find all values and create for us the target object, so in this case, model binding will search the incoming values for the properties it needs to create the order instance. If all of Bethany's shoppers would be entering the correct data in the form, the world would be a better place. However, I strongly believe that that won't be happening any time soon. So, we should be validating the data coming from the client. We'll need to perform validation of the data where we are making sure that the data being sent can be used for binding it to the model we are expecting. If that is not the case, we will need to provide meaningful error messages. Now, ASP.NET Core MVC's model binding engine can perform a check to see if the values provided by the model binder meet the requirements of the model object. We can do this using an explicit call in the action method to ModelState.IsValid. This will return to true if the model object has no validation errors and faults, of course, if it has any. Only when the model is valid will it be saving the order to the database, and then we will be redirecting the user. In this case, we will redirect the user to the checkout completed page. If, however, the ModelState.IsValid returns false, we are returning view. Something is wrong with the validation, and so the default view, the same view, is returned so that the user can try fixing any validation errors. Model validation can be done on the entire object instance in one go using the ModelState.IsValid property. This will perform validation on all properties of the object. We also have on ModelState the GetValidationState method, which accepts just a single parameter. This way, we can probe a property to see if it's valid. Finally, we also have the AddModelError method. If we are performing any manual validation rules, we can also manually add model errors when needed, and this method can be used for exactly that purpose. By default, the validation that will be done is pretty basic. Typically, we'll want to add more validation rules on our domain models. For this, we can use the metadata in the form of attributes that we can add on the properties of our model clauses. These attributes allow us to add validation rules directly on the model properties. Quite a few properties are built into ASP.NET Core MVC, including properties where we can specify that a property is required and we can specify constraints for the value, or check a regular expression. It's also possible to create custom attributes, and apply these on the properties. However, you won't be doing that in this course. Let's take a look at the most important validation attributes that we have. Adding the required attribute will raise an error if the value isn't provided. If we require in the form that, for example, the email field is required, we'll add this attribute on the email property. The StringLength attribute allows us to add a maximum, and also optionally a minimum amount of characters that is allowed for the value. If you want to make sure that the length of a field provided isn't longer than what the database can store, we can use this attribute. The range attribute can be used to make sure that the numeric value is within a certain range. To the RegularExpression attribute, it can specify a regular expression, which will be matched by the value of the property. If there's no match, an error will be raised. Finally, the DataType attribute and it's possible values can be used to ensure that the entered value is of a specific type, such a phone number, email or URL. In the code you see here on this slide, we can see a number of attributes being used on some of the properties of the order model class. Required attribute is applied, and an error message parameter is provided. In there, we specify the error that we'll want to display. I'll show you in a second where we are going to visualize all this. The string length attribute is also used here to make sure that the value won't be longer than 50 characters. On the phone number property, I'm also making use of the phone number data type. This will ensure that the entered value is following a certain pattern to match a phone number. We've now seen that using attributes, we can effectively specify custom error messages. These error messages can be displayed inside a validation summary. This validation summary is, again, surprise surprise, a tag helper. In this case, the clause behind the tag helper, the validation summary tag helper, will search for the asp-validation-summary attribute on divs. Any errors that have been found in the action methods will be shown in the validation summary. Here you can see the asp-validation-summary attribute being placed on a div. As value, I've specified all, which will, quite logically, display all validation errors that happen.
Demo: Validating the Form
You've now covered more than enough about the validation process in ASP.NET Core MVC. In the last demo of this module, I'll add validation rules on my domain model classes, and then, we'll update the order form to include a validation summary, so that all errors are shown inside a div. Now, here back in the order class, I'm going to start adding attributes on my different properties. Some of these attributes will be useful for validation. Others will be used to make sure that my form looks better. For example, let's take a look at the FirstName property. I'm adding the display attribute here. Adding the correct using statement first. The display property accepts a string that will be picked up by the asp-for tag helper in my form. When I now run the form, it's not going to be using FirstName anymore, it's going to use first space name. For validation purposes, I'll also specify that the first name should not be longer than 50 characters using a StringLength attribute. Using the required attribute, I'll make sure that the value is provided. If not, the error message, please enter your first name, will be returned. I'm going to paste in the complete order class with all attributes, and I'll point out all the interesting other attributes. The BindNever attribute specifies that this value should not be part of the model binding. The DataType.PhoneNumber is also being used here on the PhoneNumber property. Note that the DataType.PhoneNumbr does not apply validation. If you want to validate that this is a correctly formatted phone number, we need to add a regular expression. I am using the RegularExpression attribute here on the email, passing in a RegEx that is checking if the email is valid. Let's go back to our view. I need to display validation errors here. I can use for that the validation summary. Creating a validation summary can be done using a tag helper, the asp-validation-summary tag helper. As you can see from the hint here, the value can be set to all, ModelOnly, or none. If you use none, none of the validation errors will be displayed. If you set it to all, all model validation errors are going to be displayed. That's exactly what I want here. The summary will display all validation errors at the top. While that is an okay experience, it's not a great one. We'll probably also want to display the validation errors where they are occurring. For that I can use the asp-validation-for tag helper. I place this inside of a span, right next to the input where the validation error needs to be shown. Let me do that for the entire form. Now I've created the form successfully, but now I also need to capture the order data. Let's return to the order controller to do that. I'll create another method called checkout, which is now accepting an order instance. How can ASP.NET now distinguish between these two checkout methods? Well, this second checkout method will only need to be invoked when a post is recurring. I'll attribute this with the HTTP post attribute. When a get occurs, this one will be called. When a post occurs, this one will be called. Model binding is going to its utter best to capture all the form input and create for us an order instance. I've pasted in the code here for the checkout method. First, I'm checking if there's any items in the cart. If that is not the case, I'm adding a model error, saying that the cart is empty, and we need to add some pies first. If, however, the model is valid, then I'm going to ask the OrderRepository to create the order based on the values created by the model binder. I'm clearing my cart, and then I'm redirecting using RedirectToAction to CheckoutComplete. If any validation errors are occurring however, then the same view will be returned and validation errors will be displayed. I'm going to add very quickly the CheckoutComplete action here which is simply going to specify a value in the view bank. I'll then quickly create that view as well. Go to the order folder here in under views, and create a new view, CheckoutComplete, and that will just display that message inside of an h1. Let's now run the application again. I'll start by adding a pie to my cart. I'll click on the checkout now button. I'll enter my data. I've now entered some data, and as you can probably see, the form isn't correct yet. I'll try completing the order, and now my validation messages are appearing. It asks me to enter my country, my phone number, and it also mentions that the email address isn't correct. I'll add Belgium here, I'll add a phone number, and I'll complete the email address as well. Let's now click on complete order again, and I've placed a red point here in the checkout action. Let's take a look at the order, and as you can see, all the data that I've entered is shown correctly here. That's the model binding that did its job for us. As you can see, the order has now successfully gone through. We'll be able to enjoy our pies very soon. That completes the order scenario as well. We're almost ready with our site.
The order functionality is now included in our site. It's now possible to add items to the basket, and then place the order using the form that we have created in this module. Again, we've been relying heavily on tag helpers to create the form and its fields, and again, the HTML that we have created was very clean, thanks to tag helpers. We've also added some rather basic validation on the form. Although for many scenarios, this will definitely be more than enough. We've added the validation through the use of attributes that we've added directly onto our model classes. That wraps up this module. I hope you're happy with the result again, and I hope to see you again in the next module, where we will be adding client-side functionality using jQuery. Thanks for watching.
Adding Client-side Functionality
Hello, and welcome again to this Building Your First ASP.NET Core Web Application course. I'm Gill Cleeren. That's still the same as it was in the last module. We have now already a nicely implemented server-side functionality in our web application. The site looks great already. In this module, we are going to switch gears a bit. I'm going to show you how we can in ASP.NET core, MVC, work with client-side functionality. We'll be calling server-side functionality from the client side, and to do that, we'll have to make some changes on the server side, as well. Let's start the module again by taking a look at what you will be learning in this module. Doing client-side stuff in ASP.NET core will typically require that we'll be using some client-side libraries, such as jQuery. That's exactly what we'll be doing in the first part of this module. I'll be showing you the best way to add libraries to our project, and we'll again be using Bower. When we have added a library through Bower, and that'll be jQuery by the way, we'll also need to be able to invoke an action method from the client-side code. In the second part of this module, I'll be showing you how we can create an API controller, which doesn't return HTML, but instead, returns data in the form of JSON. After finishing this module, you will have seen how to make your site more interactive and responsive through client-side scripts and an API controller. Let's get started.
Adding Client-side Libraries with Bower
Demo: Adding jQuery to Our Site
Let us now return to the demo, and we'll add support for jQuery in our site, using Bower. We'll also include jQuery in the layout file, so that all pages will know about jQuery. So let me show you how we can manage client-side packages using Bower. If you look at your solution, you may not be able to see the bower.json file. If that is the case, click here on the Show All Files button, and the bower.json file will appear. We've added it already earlier in this course, and you see my current bower.json file. We can edit the dependencies directly in this JSON file, or you can also right-click the bower.json file and click on Manage Bower Packages. This opens an interface which is pretty similar to what we get with NuGet. I will add packages here directly in my bower.json file. Now what I'll be adding is jQuery. Now we have, in fact, already support for jQuery in our application, which came because it's a dependency of Bootstrap, but I'll add the latest version of jQuery here manually as well. To do that, I write jquery and then the current version, which is 3.1.1, and I save the bower.json file and automatically, all the client-side packages are going to be installed. As you can see, there's not a lot of difference. jQuery was already there because it's a dependency of Bootstrap itself. If you want to add other client-side packages, this is the way to do it. As you probably also remember, we've added support for jQuery in our layout file. Here you can see the reference to the jQuery library. I've added jQuery here in the layout file so that all my pages that use this template will be able to use jQuery without adding any custom script references. Now I'm going to add the @RenderSection here, passing in the name scripts, and then the required parameter is set to false. By adding this @RenderSection expression, I'm indicating that my pages that are using this layout, so in fact all my pages, can add another section named scripts, and that will be included in the templates or the layout file at this location, so at the bottom of the page. I've specified that required is false, meaning that it's optional for pages to define this section. If I would set requirement to true, all pages that do not have this section defined will cause an exception. In the next demo, we are going add script to the list view. So in the Pie list view, I'll already add support for this new section, after I use the @Section expression, passing in scripts. This script string here is the name of the section that I defined here in the layout file. I'll now be able to add script in here, which will then be inserted in the layout file at the RenderSection location.
Creating an API Controller
And now that we have jQuery support, we can add all kind of fancy client-side functionality to the site. I'm not going to spend time showing you how you can animate things or how you can add client-side event handlers. Instead, I'm going to be using jQuery to implement the ability to load more pies in the overview page, using a Load More functionality, and for that we'll be using an Ajax-jQuery call. This call will then be expecting more pies to be returned in JSON, and this will require us to create an API Controller. You have so far in this core been writing quite a few controllers. One thing that they all have in common is the fact that they all return HTML through the use of one of the built-in view result types. In some cases, for example, if you want to load a list of pies dynamically for client-side script, we're not interested in the HTML code. Instead, we will be happy to just get the list of pies, so the data. This we can achieve using an API controller. In previous versions of ASP.NET that we see, creating an API was only possible using a separate framework, namely the Web API framework. It was possible to have a single web application that could both show web pages and return data. Now with the introduction of ASP.NET core and core MVC, this is now more tightly integrated in a single framework. Typically, when we just want to return the data and not the HTML, we'll be working REST-based, and REST stands for Representational State Transfer. Where we use REST, we're typically going to use the HTTP standards. This means that we'll be using the HTTP verbs, such as GET, POST, PUT and DELETE to indicate the action that we'll want to perform. To indicate which data object we'll want to interact with, we'll be using the request URL. Because of the fact that REST is falling back on the pure HTTP standards, it's a very open technology. REST services can therefore be used from a very broad range of clients, including mobile apps, as well as client-side scripts in our ASP.NET core MVC pages. Let's take a look at the scheme of how we can work with a REST-based API Controller. From the client, a request is launched to /api/pies/22. Note that I am prefixing my URL here with api. This is by no means required, but I find it to be good practice so that I can differentiate between regular controllers and API controls. When the request for this URL is launched, for example, from client-side script, an HTTP verb is going to be specified as well. This can be, for example, GET, but others are possible here as well. The routing engine will make sure that our request will be handled by the correct controller, in this case, the API Controller. Typically, this controller will return a JSON response. Note that it's possible to configure the request so that it will specify the format of the data it's expecting. So once the controller has executed all it needed to do, it will return to the client a response in JSON. The client can then continue working with this response. This can be, for example, passing the JSON, and then client-side script such as jQuery, an update to your Y, to show the newly added data. As mentioned, in previous versions of ASP.NET MVC, working with the Web API was basically working with a different framework. In ASP.NET core, this has now become integrated. There's no long a different base class for API controls. So no longer will we have to set the base class for API controllers to API Controller. Here we can see some code from an API Controller. Note that the base class is indeed set to Controller. I have specified, using a route attribute that this controller should be used when a request comes in for a URL that starts with api and then the name of the Controller. So here, PieDataController. It's not possible to define the route by which the controller can be reached by configuring a route in the startup like we've done for regular controls. Like I've mentioned before, the convention is to prefix route to API methods with api, but that is just a convention. If you don't do this, your application will still work, though. Since this is just a regular controller, I can again use the dependency injection system of ASP.NET core MVC to plug in dependencies. Next, in my controller, I have again action methods. As you can see, the LoadMorePies method has been decorated with the HTTP GET attribute. This is typical for API controls. The action methods need to indicate, using an attribute, which method they accept. So for this method, that would be the GET method. Just like with regular routes, we can include arguments, such as the ID fragment for the LoadPieById method. What this means is that the LoadPieById method can be reached using a GET request to /api/PieData/id and then the value of the ID parameter will then be passed on to the method as parameter value. The whole use case for creating this API Controller is that you will be able to invoke action methods asynchronously from client-side script. When we, for example, have a large selection of pies that we want to display, you may want to return initially only the first batch of 20 pies. When the user is now at the end of the page, we can display a Load More button. Instead of performing a full post back to the server causing the page to reload, we are then going to use client-side script, which will launch an AJAX request to the API controller. The action method can then load more pies from the data source and return the JSON response. When received on the client, these new pies will then be visualized at the end of the list.
Demo: Creating the Load More Functionality Using Script and the API Controller
In the final demo of this module, we are going to implement the scenario I just explained. First, we are going to create the API Controller. Next we'll add client-side code to invoke the API Controller using a Load More button. The received JSON will be used to append the extra pies we've loaded to the overview list. Let's take a look. This course, by no means, was to give you a full overview of everything that is possible with the ASP.NET core Web API, a dedicated course is available here on Pluralsight via the link you see here on the slide. So I start by creating the new controller, the API Controller. Let's go to the controls folder again, and in here I'll add a new controller. I'll call this controller PieDataController, since it will be used to only return data, not HTML. I'm going to use this class for my API, and it also will inherit from Controller. This is different compared to previous versions of ASP.NET MVC and Web API where the base class was different. I'm going to add a route attribute on this PieDataController. While it's not really necessary, it's a convention that API-related routes start with API, so a static part. As you can see, I've defined the api/ and then the name of the controller as the route to access this controller and its actions. The controller code itself is pretty straightforward. I'm going to use another pie repository. I am going to use this PieDataController to load more and more pies, when the user is scrolling, so a dynamically created list. The pie data that I'll be returning needs to be as small as possible. So I'm going to add another view model that is only containing the items I need in the list. Let's add another view model in ViewModels. I'll call this the PieViewModel, and I'm only using here, as you can see, the relevant properties, so the pie ID, the name, the short description, the price, and the image thumbnail URL. Those are the properties I'll use in the list. Here in my PieDataController, I'll paste in some more code that is going to load more pies dynamically. I am returning an innumerable of pie view models. First, I'll load ten pies from the database. I'll then create a list of pie view models, and I'll culvert the pies returned from the database into PieViewModels. Now since this is an API Controller, I do need to add an attribute, and that is the HTTP GET attribute. I'll put it here on the LoadMorePies. Then that result is that when I get requests sent to this API Controller, the LoadMorePies method will be evoked, which is then returning an innumerable in PieViewModels, and it is returning that in the form of JSON. So with that, my controller is ready. Let's now make some changes to the list view, so that it will invoke this PieDataController asynchronously. I'll go ahead to the list, and I'll remove all the code that we had so far. I'm going to add an empty div, and I've named that div, pieDiv. Now I've already created this section before. The next thing I'm now going to do is I'm going to add script code here that is going to invoke my API Controller asynchronously, and it is going to ask to load more pies. The script code needs to go in a script block here. Let's take a look at the code I've just pasted in. I've created a function, LoadMorePies, which is going to do a jQuery-Ajax call. jQuery is supported because I've added it on my layout file. I am going to do a GET request to the URL /api/piedata/. This is going to do a GET request to the /api/piedatacontroller/. What I'm going to get back is JSON. If no data is returned, I'll show an alert. If data is however returned, I'm going to loop over the returned data, and I'm going to invoke this function here, which is going to dynamically create some HTML. If you look at this HTML, it is very similar to the Pie Overview Summary. In here, I used the @ model, but here, I'm not getting my data back as JSON. So I'm simply passing the properties from our JSON data. I'll then search for the pieDiv, again using jQuery, and I'll append this created PieSummaryString. Now when do I want to invoke this function? I'll want to invoke this, when the page is ready, so the first time, and I'll also want to dynamically load more data when the user is at the end of the page. For that, I'll use this script here. First, when the document is ready, I'll invoke the LoadMorePies and then, when I'm scrolling to the end of the page, I'll invoke the LoadMorePies again. Do note that this view is not typed anymore. It does not contain an @ model statement at the beginning. Everything is now done completely dynamic. Let's save everything, and run the page in the browser. Let's go to the Pies, View All Pies, for example, and we see pies being loaded, and note that the scroll bar is now, when we're close to the end of the page, getting smaller and new pies are being loaded dynamically. So you've now successfully added an API Controller, which gets invoked asynchronously using jQuery.
Let us briefly reflect on what we've done in this module. First, I've shown you how we can manage your client-side dependencies. As you probably remember, you can do this using Bower. Bower's now in vista view, the preferred way of managing client-side dependencies. We've then created a specific API Controller. One of the most important things to remember here is that ASP.NET core MVC and the Web API are now sharing the same base controller class. We have then created the ability to asynchronously invoke the API calls from jQuery, so from client-side script. Although this module only showed you the basics about the Web API, it should give you the needed information to extend on this scenario. Thanks for watching this module, and I hope to see you again in the next module, where we will be exploring ASP.NET Identity.
Adding Security Using ASP.NET Identity
Hi there, and welcome to this module in the Building Your First ASP.NET Core Work Application on Security. I'm Gill Cleeran, and you can contact me via Twitter using @gillcleeren. Let me know if you have any questions about this course. Our application is now pretty feature rich, but it currently has one big issue. If you think back of when we were creating the order form, we didn't have to login to place an order. I don't think it's wise to put an application online like that. In this module, we are going to add some security related features to the site for guest authentication and authorization. Let's start by exploring what you will be doing in this module. When we want to authenticate users or when we want to authorize users to execute certain actions within our site, we will be working with the ASP.NET Core Identity platform. To kick off the module, I'm going to give you an overview of what ASP.NET Core Identity can do for us. Next, we will be starting to add Identity to our site. At this point in the course, it shouldn't be a surprise that we'll need to do some configuration to add Identity to our application, and once configured, we can start using it. So, we'll create a login page where users will have to login before they can place an order. And we'll finally be adding authorization as well, so that we can deny certain actions in our users to non-logged in users. I hope this sounds interesting to you. Let's do this.
Introducing ASP.NET Identity
Before we start using ASP.NET Core Identity, I think it's a good idea to explore what it really is, and what we can do with it. Let's start with that then. ASP.NET Core Identity is a membership system which allows us to manage users. Also, the API allows us to create login functionality, so using the ASP.NET Core Identity platform, we can add the missing functionality to our application. That's exactly what we were looking for, isn't it? The ASP.NET Core Identity API can be used to authenticate users, as well as do the authorization part. Basically, using the Identity API, we can allow the users to login via a login page. This is the authentication part. We are going to check with the system if the user is known. Once the user has successfully logged in, the user will get certain permissions in the system, different than those on the default, let's say, non-logged in user. This permission part is the authorization part and it will be used, for example, to allow the user to navigate to a certain controller. In fact, I should perhaps say, to allow or deny the navigation to a certain controller. Identity also supports working with rows, so the user can also be part of a row. The permission will then be applied on a row. If you have been working with earlier versions of ASP.NET, you are probably familiar with the Membership API. This API has been in ASP.NET for a long time, and it is generally considered good practice to use the system to handle the security in your application. The good news is that the ASP.NET Core Identity system is actually based on the Membership API. Using this Identity API, we can allow users to login using the traditional username/password combination. However, when using this approach, it is our responsibility to make sure that access to sensitive information is well secured. If we do not want to take that risk, we can use an external provider. Identity comes with support for external providers built in, such as Facebook, Google, and Twitter. By default, ASP.NET Core Identity works with a SQL database. If you have worked with Membership, you probably remember the typical ASP.NET Membership tables which will store user accounts, passwords, and much more. These tables will by default be stored in a SQL database, but if you want, you can use another system here, as well. This could be, for example, Azure Table Storage.
Configuring the Application for Identity
Now that you have an idea about Identity API, it's time to start using it. This way, we'll discover several of its features. The first thing I will show you is how we can add support for Identity in the application. Setting up Identity will, as you'll see in a minute, require us to follow a number of steps, such as creating models, adding the correct packages, and configuring Identity. Let's take a look at what steps we'll need to take to get things up and running. I think the following should now already start sounding a bit boring. Just like anything in ASP.NET Core, and we see Identity is a package, and I'm convinced that when I say it's a package, you automatically know what needs to happen. Indeed, we'll need to include the required packages in our product.json file. Here in the slide, you can see that we'll need to add the Microsoft AspNetCore Identity EntityFrameworkCore package to our application, and saving the file will cause Visual Studio to download the dependency. Typically, managing the configuration of the application, so making some changes in a startup class will be the next thing to do. However, I'm going to do something else first, already setting up how Identity should work with the database to store its data. Remember that I said earlier in this module that you have support for working with SQL Server, and that in that database, Identity will store the user information, the role information, and so on. Soon, there will be database interaction. I'll need to create a context again, which will act as link between the code and the database. Now, I have two choices here. Either I create a separate database for just the Identity information, or, second option is that I add the Identity tables to my existing database. If you want to use a separate database, you will also need to create a separate context class. For our application though, I have opted to place everything in just one database. And so, now, I'll need to make some changes to my already existing context class. What you see here is the code for the AppDbContext. Previously, if you remember, this class inherited from DbContext, but I want to add support for Identity. This class will now need to inherit from IdentityDbContext. Doing so will give IdentityFrameworkCore Identity specific features. A start parameter have used IdentityUser here. IdentityUser is a class that comes built in with ASPNET Core and represents a user. If you want to store more information about a user than what IdentityUser does by default, we can create our own class. Such a class would, of course, inherit then from the built in IdentityUser. IdentityUser already has quite some properties to represent a user, such as username, ID, email, roles, phone number, and so on, so all of them properties we give access to typical user information. Any other properties we want Identity to store about user can be added on this custom user class here. I won't be doing that in the demo of this course, though, as it would take us too far. Now that you have the context setup, let's take a look at the configuration changes we need to make to include support for Identity. From the code you see here on this slide, the highlighted part is what I added. The services.AddDbContext was already there, but I've repeated it here to show the registration of the DbContext with the service collection. In the next lines, or the highlighted one, I'm using the AddIdentity method to add the default Identity service using the built in classes for both user and roles. The AddEntityFrameworkStores method belongs to the AppDbContext to store the Identity information. Do note here that if I would have opted for a separate database to store Identity information, I would be registering another context using the AddDbContext, and I would then pass this context to the AddEntityFrameworkStores method, and in the Configure method, I have added the UseIdentity method. This simple call will enable ASP.NET Identity for our application. When we follow these steps, ASP.NET Identity should be correctly configured. These are the minimal settings that we'll have to configure to make Identity work. Identity does have a lot more configuration options on board, though. It's, for example, possible to set various options regarding the password policy that will be enforced when users registered. This includes settings such as the required length for the password, whether or not an alpha-numeric character is required, and so on. We can also use options to configure how security cookies should behave, such as the expiration time. We can also configure user options, such as the fact that the email used upon registration should be unique, and the lockout settings allow us to configure, for example, how long the user should be locked out when too many failed login attempts have taken place. There are more options, but let's see how they work in tote. In the snippet you can see here, we are passing to the Configure method, a lambda expression. The parameter options here is of type IdentityOptions. This class defines, for example, the password property, which, in turn, defines the properties, such as the required length, required digit, and so on.
Demo: Adding and Configuring ASP.NET Core Identity
In the first demo of this module, we are going to add ASP.NET Core Identity to our site, so we'll include the packages. And once that is ready, we are going to setup Identity like you see in the slides. All right, let's configure our site to support ASP.NET Core Identity. I'll start by adding the correct packages, of course, again. By default, it is not supported in my ASP.NET Core website. I think you know the drill by now. Let's go to the project.json file and add another package here. To support ASP.NET Core Identity, I'll need to add the ASP.NET Core Identity AddEntityFrameworkCore package. Let's save this, and Visual Studio will restore the package. I now have two options to support ASP.NET Core Identity in my application. I can use a different database for all the Identity-related data, but I'm going to use the database I have already created. Both options are equally valid. To do that, I'll go to my AppDbContext, and instead of having it inherit from DbContext, I'll have it inherit from IdentityDbContext in IdentityUser. Let's add the correct using statements here. By inheriting from IdentityDbContext, I automatically get support for the Identity-related features for EntityFrameworkCore. The parameter, IdentityUser, is the built in type to represent users. I can use my own type to represent users, but the built in type already has a number of interesting properties. If you look at the definition in the Framework, you'll notice it already has most of the common properties you'll typically use, such as email, username, password hash, phone number, and so on, so for us, that will do. I, of course, also need to configure the use of Identity in my startup class. Using the AddIdentity method, I'm specifying that I want to use Identity service with the built in classes, IdentityUser, and IdentityRole. The storage will be handled using the AddDbContext database and that's what I'm specifying with the AddEntityFrameworkStores method. In the Configure method, I'll use the UseIdentity method to configure the use of Identity in my application. Let's now build the application. Identity uses its own tables. To add its tables to the database, I'll need to add a migration. We'll go to the Package Manager Console again, and we'll type, add migration, Identity. When that is finished, we'll call update database. At this point, Identity is correctly configured in our application, but we aren't actually using it. Let's go back to the slides, and then, we'll return to make use of what we've done in this demo.
Adding the Login Page
Now that you have Identity configured in our application, we can start using its benefits. We'll start with the creation of the login page first. You'll see that it's actually pretty simple to use the Identity API for features which aren't always as straightforward if you would have to do them yourself. If we think about the login page that we'll want to create, it's, in fact, a separate view, nothing really special there. So, we'll have to create a view using tag helpers again, where the user can enter the relevant user information. Typically, we'll not only have the login view, but we'll also have the ability to register new users, and other related items, such as the forgot password functionality. These views will then be controlled using a controller that we typically include to manage all login-related functionality. This will be my account controller. And finally, we'll have to make some changes to the model and the view models as well. If you think of the account controller that we'll want to create, it will actually be just a regular controller, so any AccountController, of course, will need to inherit from Controller. On this controller, we will have at the bare minimum, in my opinion, these methods that you see here defined. We'll have a login method which will show us the login view. We'll have another login action method here as well. This one will be accepting, in this case, a LoginViewModel instance. The latter will be a ViewModel class that we'll create as part of the model changes, and it will thus be triggered when the user is sending over his credentials to perform the actual login functionality. A Register method will be needed here, as well, as well as a logout method. We'll see the API implementation in the upcoming demo in just a minute. In the implementation of the AccountController, we'll be using some important Identity API classes. The UserManager class is used to manage all interaction with the user objects in the data store. You should be thinking of this as your front to create users, delete users, and in general, do all interaction with user objects. It will also take care of all relevant changes in the data store, so updating the SQL database is done by the UserManager class, as well. Next, the SignInManager class will be used for user authentication, and all related actions. It defines methods such as PasswordSignInAsync, which accepts a username and password. When we trigger this method, we will try authenticating the user, and it will return a sign in result. Within there, a succeeded property, indicating whether or not the authentication attempt was successful. Many other methods are available in this class, such as SignOutAsync, ChangePasswordAsync, ConvertEmailAsync, and many, many more. What you need to remember here is that these two important classes of the Identity API are offering us an abstraction of the details of working with authentication and user management. The Identity API makes this sometimes difficult task a lot easier, and since underneath it's built on top of Membership, you can rest assured that the implementation of your security-related features is done in the right way. There is one more thing I want to point out here before we go back to the demo, and that is the LoginViewModel class. This class, I have added to capture all the information related to a login attempt from a user of Bethany's Pie Shop. I have the UserName property, and a Password property. The username is made required using the required attribute. And then, I have added the display attribute here as well, passing in the value that I want to show in the UI. If I omit a letter, my UI would be showing username. Next, I have attributed the Password property, with a data type, password. Doing so is an indication so that when this input will be generated in the UI, its contents should be hidden.
Demo: Adding the AccountController and the Login View
We'll now go back to our demo, and we'll do what I just explained. We'll create AccountController, and the Login View. Doing so will allow the user to login to Bethany's Pie Shop. All right, let's now take a look at how we can allow our users to login to Bethany's Pie Shop. To save us some time, I've already done a couple of changes. Again, you can copy all these in your own application, if you're following along, from the snippets. To manage everything that is related to logins, I've created a new controller, the AccountController. In here, I'm making use of two very important classes in this context, the UserManager and the SignInManager. The UserManager, as the name implies, contains all APIs to manage the users in the database, and the SignInManager contains all the APIs to allow the users to sign in, log off, and so on. In my constructor, I'm again using the dependency injection system of ASP.NET Core to get in an instance of both the UserManager and the SignInManager. The login method has just one parameter, returnURL. That is going to be the URL I want to redirect the user to after a successful login. The login method, itself, returns the view, which get in, as data, a new loginViewModel. Let's take a look at this LoginViewModel now. This is a simple class that has the username, password, and returnUrl property. The required attribute will be used to indicate that when we are entering the user's data that both properties will be required before we can continue. I've changed the display property to User space name for the username property, and using the data type, Password attribute, I've indicated that the password data should be hidden while the user is entering the data. I have a second login method. As you can see, this second one is attributed with HttpPost, and it is going to receive a LoginViewModel. This one will be called when the user has entered his login data in the view that we'll see in just a second. What you see if our loginViewModel that is built up by the model binders, and it is not valid to be our return to the same view. Using the UserManager doc, FindByNameAsync, we can search in the data store to see if we already have a user account with that particular name. If that is the case, we'll use the SignInManager class and try to sign in the user using the PasswordSignInAsync. We'll pass in the user and the password. If that is successful, we'll return the user to the passed in return URL if we have one. If not, we'll return to the Index Home. If however, it couldn't find the user, will return a ModelError saying that the username/password combination wasn't found, and we'll return to the LoginView again. I also have two Register methods. One will simply return the RegisterView. The second one will be called when we do a post, but again, it's passing in a LoginViewModel. We'll check if the model is valid. We'll then use the UserManager to create a user using the username and the password, and if that is successful, we'll return to the homepage. We also have a logout action method that is signing out the user, and then, returning to index home. This one also will be called using an HttpPost. Let me show you the views very quickly. We have a LoginView, which is a form where the user can enter username and password. At the bottom, we seem to have a button that will submit our form to the Login method of the AccountController, and it's doing a post in that case. The Register code is very similar. Again, a username and password can be filled in and this will post to AccountRegister. Logout view, itself, is empty. If you look back at the AccountController, this will simply redirect me to the index home. I've also added this LoginPartial partial view. This partial view will either show a login method and a register button if we're not logged in, and a log off button if we are logged in. To do this, I'm writing some razor code in my view directly. I'm using the SignInManager build IsSignedIn, passing in the current user. To make use of the SignInManager directly in my view, I need to make it available in the view. I need to basically plug in an instance of my SignInManager into my view. Remember that the SignInManager is also managed by the dependency injection system, and using the @inject expression, I can inject, using the same dependency injection system, the SignInManager directly into my view here. If you now find that the user is logged in, we show the log off button. If the user isn't logged on, we show the Register and the Login link. I now need to use the partial view from the layout file. I'll use the HTML with PartialAsync, so an HTML helper, to include the login partial in my layout file. This will ensure that this login functionality is shown on all pages that use this layout. I think everything surrounding Identity is now in place. Let's take a look. Notice there at the top right, we have the Register and Log in button. Let's click on Register. Now, we're seeing the Account Register view. I can register here, giving in a username and a password. This is using the attributes I've defined on my LoginViewModel. I'll then Register. After registering, I can now go to the login page, and log in with the same credentials. If I had incorrect credentials, you see an error. This is because of the fact that the Sign In Manager couldn't find this username/password combination. If I add correct credentials, I'll be logged in to the site, and now, we can see the Log off button here at the top. I'm now logged in. I can now add another pie to my cart, and I can now check out, but take a look at what will happen now. Click on the Check out now button. I'll copy this link, and I'll log off. I'll paste in that same link, and I can still check out. There's basically no check in place that only logged in users can do a check out. We'll need to fix that, and we'll do that in the next demo.
We have now added the login page correctly, and it's possible to login to the site. However, if I browse to the Order page when I'm not logged in, I can still place an order, and no one is going to stop me. Well, let's fix that, shall we? Let's see now that the authentication part is done how we can add authorization to the site. With the authentication in place, I can start adding an authorization parser. I'll need to indicate ASP.NET Core which parts, so basically, which controllers or which action methods I'm willing to protect. I'm going to start with the most basic approach, and that is controlling access on the fact if the user is authenticated or not. I can do this using an attribute, the Authorize attribute, that I'll want to add on the Controller or methods that I'll want to open up only for logged in users. Although this approach is a bit rough, it's actually something you use quite often in your NPC applications. For example, here in the snippet, I have added the Authorize attribute on the entire AccountController. Now, only when the user is logged in can action methods of this controller be used. Now, if you let that sink in, you'll come to the conclusion that that might not be a good choice. The AccountController also has the actual methods to perform the login. If you block the entire controller from anonymous users, how will they be able to log in then? Well, another attribute comes to the rescue here, the AllowAnonymous attribute. Place this attribute on the methods of the protected controller, and this will override the authorization policy. The Login method, in this case, is now again available for non-authenticated users, and that's exactly what we needed. The Authorize attribute with no parameters might, in many cases, be a bit rough. Imagine that you would add to Bethany's Pie Shop some administration pages, where she can manage the orders or the price. If you would only be able to use the Authorize attribute, it would not be possible to only allow some users, typically the administrator to get administration pages. For this reason, we can include Roles, and use these roles also from the Authorize attribute. You can see that I've passed that the Administrator role is allowed to use the methods of this controller. Users are placed in one or more roles, and when logged in, Identity will look for the logged in user. Only if the user is part of the specified role or roles will he or she be able to call action methods in this controller.
Demo: Adding Authorization
We're now going to return one last time to our demo and add the authorization part. We'll be adding the correct attributes onto our controllers. After this demo, our site will be capable of blocking non-authorized users of activating specific actions in our site. Now, to fix the problem that we had in the previous demo, I'll make some changes here in both the AccountController and the OrderController. First, the AccountController needs to get an Authorize attribute. We add the correct using statement here. This will make sure that all actions within the AccountController are now only available to logged in users. Now, wait a minute. If I only allow logged in users to do stuff with the AccountController, how can users then still login? That's a very good question. I'll need to add another attribute here on the Login method, which is AllowAnonymous. This will override what was defined on the controller, and thus, allowing anonymous users to invoke this action. I'll need to do the same on the second login method. I'll also need to do the same on the Register methods. So now, we cannot invoke, for example, the log out action if we're not logged in, and that's good. Now, not only the AccountController needs to be secured this way. We'll also need to make some changes on the OrderController. The checkout functionality should only be available to logged in users, so I'll put an Authorize attribute on both checkout methods. Let's see the changes that we've now implemented, ensure that only logged in users can place an order at Bethany's Pie Shop. Let us login. Let's add another pie to our cart. Checkout now. Copy that link again. Log off. I'm going to now browse to that same link again. I will be redirected to the login page. That's exactly what I wanted. So now, we've successfully added Identity to our application.
In this module, we have focused heavily on the use of ASP.NET Identity. Identity comes with ASP.NET Core, and is just a preferred way of adding security features to our site. I started this module by exploring the Identity framework, and you've seen what options we get with the Identity framework. We have then looked at how we need to configure our application so that it supports Identity. We have used Identity to perform both the authentication of the user, as well as the authorization, so making sure that certain actions, such as placing an order, could only be executed by logged in users. In the setup that we have used here, we've used a default configuration using EFCore. Our site is now ready. In the next and final module, we'll look at how we can deploy the application to Azure. Thanks for watching.
Deploying the Site to Azure
Hello, and welcome to the last module of the Building Your First ASP.NET Core Web Application course here on Pluralsight. Time flies when you're having fun, isn't it? It's already the last module. In this last module, we are going to make Bethany very happy. Our hard work has paid off and the site is ready, ready to be shown to the world, so she start can selling her fantastic pies to her customers all over the world. Of course, before everyone can browse Bethany's pie shop, we need to deploy the site a server for everyone to enjoy it. Because we're convinced that there will be a lot of traffic on her site, we'll need the scalability of the Cloud, so we will deploy the site to Azure, and remember .NET Core was built with the Cloud in mind, so the match between our ASP.NET Core site and Azure will be a good one. Let us start this last module like we've done with all others so far in this course, that is, by looking at the module overview. This last module is actually pretty concise, but nonetheless, it'll teach us how we can deploy the site to Azure in the correct way. I will start by explain you the support you are getting in ASP.NET Core to work with different environments. I will then explain the different options, let's say at least the most important ones that are available to us to deploy our application and make it available publicly. Finally, we'll round up the module by doing the actual deployment of the site to Azure, more specifically, I'll be deploying the site to an Azure app service. Let's get started.
Configuring Multiple Environments
As promised, I'm starting this module with yet another new feature of ASP.NET Core, and that is the ability to work with multiple environments and how we can interact with these environment from codes. Different environments come into play when creating a new software project. Typically, it all starts with the development environment. We are in this phase or environment when the software is being written. In this environment, we typically need access to all the input information. This could mean that when the application is running in the browser that will need as much information as possible, if something goes wrong. That means including stack trays, and so on. When we are ready with the development of the software and it is ready for being tested by the customer, in our case it would be Bethany, we'll push the code to the staging environment. While this is still a closed environment, we will be mimicking the real world situation; debug information is not to be shown anymore. In terms of physical characteristics, the staging environment should also be as close as possible to the production environment, since this way we can catch any issues that may arise from the combination of our code and the configuration with the production environment. Finally, after the customer has given us the final approval, we can move the application to production. Any issues that we may have had are already solved, and Bethany's customers can finally start ordering pies online. This flow is so typical, that it's now even built into ASP.NET Core. These three environments are known to ASP.NET Core, and we can even write code that checks in which stage or environment the code is executing. Based on this value, different settings or let's use the term configuration again, can be used. Now when we go to the properties of our project in Visual Studio and we open the Debug tab, we'll see the following window here. Take a look at the highlighted part, where it says environment variables. Environment variables can be used to indicate to the code in which environment it is running. ASP.NET Core comes with one special variable named ASP.NET Core underscore environment this one is used for this very purpose; it allows us to check what is the current environment, and then in the code, we can enable or disable certain functionality based on the value of this variable. We set the variable to just any value we want, but it comes with three values that are known, let's say by convention, and those are: development, staging, and production. We change the value here in this window. By the way, the value is not case-sensitive. When we make changes in these settings, automatically yet another adjacent file comes into play, namely, the launchSettings.json file. You can find this file in the Properties folder of your project. Now you know how we can change the value of the environment, but of course, just changing this value doesn't do anything. We can now start writing code that makes the application behave differently based on the value of this variable. For this, the iHosting environment will be important. This is a service which is part of ASP.NET Core, and it give us access to working with environments. For example, using this interface, we can find out what is the name of the environment using the EnvironmentName property. Also, several extension methods are available. There are three extension methods which are available for the three known environments, namely IsDevelopment, IsStaging, and IsProduction. If you want to use our own naming convention for the different environments, that is fine as well. However, in that case, there won't be a utility method and we'll have to use the IsEnvironment method, which accepts the name of the environment and returns true if we're running on that configuration. Working with the IhostingEnvironment is again something we'll be doing in the startup of the application, more specifically, in the configure methods. You are getting an IHostingEnvironment instance in via dependency injection. In the implementation of the configurement. that you see here, I'm using the IsDevelopment method first. If this returns true, I'm indeed in development mode, and so I want as much debug information as possible, as well as meaningful error pages. I therefore will be adding some middleware components, such as UseDeveloperExceptionPage and UseDatabaseErrorPage. These will effectively result in error pages with trace information being shown in the browser in the case something goes wrong. And this is of course something I'll want during the development. If however, the app isn't running in the development environment, it should not show these pages, and therefore, I'm on adding these components. Instead, I use another middleware component, UseExceptionHandler. This allows me to redirect the user to a custom error page, let's say a friendly error page. In the background, this page may ransom entries to the log, but I won't show an ugly error to the user. If you've used other versions of ASP.NET you'll probably remember that this used to be code that typically went into the web config file. That is not the case anymore with ASP.NET Core. I can use the environment name property in other parts of my application as well. Take a look at the screenshot here. I have another app settings file, namely appsetting.production.json. This file, as the name is already giving away, contains the production connection string. Again in a startup clause, I can then change the code so that a correct app settings file will be used, based on the environment. As you can see here in the highlighted code, the AddJsonFile now accepts a string where the hosting environment.Environmentname is used as part of the file name.
Demo: Creating the Error Page and Configuring the Environments
Let's go back to the demo. We'll create first a custom error page, which should appear in Bethany's pie shop if something goes wrong, such as the database not being available. Next, we'll also configure the different environments in the startup clause. So first I'm going to create the custom error page in our application. Now to do that, start with another new controller. I'll call this controller the appexception controller. This is very simple controller, I'm not going to make any changes. I do have to add the correct view. So in my views folder, I'll create another subfolder, AppException, and I'll create a very simple view in there, which will just show a friendly error message to the user. That's our exception page, we'll see the action in just a second. I'm going to show you first the available environment variables. In the Project Properties, under debug, we'll find these environment variables, and by default, there's one in there, the ASPNETCORE_ENVIRONMENT, which is currently set to development. I can change this to staging or production, these are the known values in ASP.NET Core. I can give you just any value, but development, staging, and production are known. And I can use these in my application, I'll do that next. I'll go the startup file again, and in the configure methods, I'll make a change. Instead of always using the developer exception page and status code pages, I'm going to replace this code by a small check. I'm going to use the iHosting environment variable here, and if the value is set to development, then I'll use the code that was there before. If not, so if my application is in staging or production, I'll use the custom exception handler, using the app.UseExceptionHandler passing in /AppException, that will invoke the index action on my AppException controller. The IsDevelopment method will check the value of the ASP.NET Core environment variable. Now what I'm going to do is I'm going to create an exception in my code. For example, let's go to the PieController, and in the list methods, I'll throw an exception. There we go. I'm going to run things as is, so that it's still in the development setting. And let's see what happens. Let's go to the View All Pies page, and an exception is being shown here, and the browser shows the developer exception page. So nothing has really changed at this point. Now let's go back to the Properties, and change this value into production. Make sure that you save things, and let's run the application once more. Click on View All Pies. Exception is happening, but to the user we're now showing the friendly error page. So now we're effectively using our custom exception handler only in the production environment.
To deploy ASP.NET Core applications, we now have a lot more options compared to the previous versions of ASP.NET MVC. Let us explore these different options. The first and probably the most interesting option is the deploying the site to Azure, the Microsoft Cloud platform. While we look at Azure, in fact, we have multiple options to deploy our site. The first option that we can use is deploying the site to an Azure app service. App Services is a collection of types of services of which Web Apps is the one that we are interested in for our site. A web app is a scalable solution to host Bethany's Pie Shop, and it's entirely managed by Microsoft, so we don't have to worry about installing updates on the machines, or even installing any server side software. We just deploy the application, and we're up and running. As mentioned, this option allows us to scale. We have several tiers of which we can choose. The higher the tier we select, the better the underlying hardware will be, and thus, the better performance we'll get under heavier loads on the site. As mentioned, we will deploy our site to an Azure web service in the next demo. Azure offers other options on which we can host our site as well. We could create a cloud service, or even a virtual machine in Azure, and host the site on there. In the case of a virtual machine, it would actually be required that we install and configure and IIS instance. Running an ASP.NET Core site on IIS just works. It works in Azure, and can also be done in your own premise environment. So if you are hosting a sight on your own hardware, where IIS is currently perhaps hosting already, a regular ASP.NET MVC site, you can simply keep using that same IIS to host your ASP.NET Core applications. Another completely new option for hosting is using Docker. Docker is a lightweight container engine which you can use to host applications and services. Docker is similar in some ways to a virtual machine. I won't go into details of Docker here; just remember that ASP.NET Core works great in combination with it. Finally, ASP.NET Core apps can also be hosted in the Linux environment. This is of course the direct result of the fact that ASP.NET Core is cross-platform. This effectively means that if you have a Linux server up and running, you can now run Bethany's Pie Shop from this server as well. Isn't technology a great thing?
Deploying the Site to Azure
Like I said in the previous slide, we are going to be hosting Bethany's Pie Shop on Azure. In the last part of this course, we'll set this up. We'll take a look at the deployment of the site in the next and also final demo of this course. However, I want to give you the first steps that you'll need to follow. First and foremost, you'll need to create an Azure account, if don't have one already. You can get started for free, the registering can be done using portal.azure.com We will be deploying the site to an Azure App Service. More specifically, we'll be hosting everything in a web app. We'll also be needing a SQL Server database in Azure, since that's where we have stored all the data for our site. The actual deployment will be done from Visual Studio, using the publish option in the Solution Explorer.
Demo: Deploying the Site to Azure
The time has come that we are deploying Bethany's Pie Shop. In this final demo, we will perform all the steps outlined in the previous slide to deploy the site to Azure using Visual Studios. I am now in my Azure account, so in the portal, and the first thing I'm going to do is I'm going to create a new SQL Database. So I'll go to New, search for SQL, and SQL Database is the thing I need. I click on SQL Database, and then click on Create. Let's give my database a name, I've called my database Bethany's Pie Shop Demo. I can then select my subscription, use a new resource group, or use an existing one. I'll use one that I've already created. A resource group is simply allowing me to group certain resources for easy management. I'll want to get started using a blank database. I can then select an existing SQL server, or create a new one. Let's create a new one, here. I'm giving it the same name as the SQL database, of course you can select just any name you want. And a username and password, and for me the location is Western Europe. You can of course select a region that is closer to your own location. Make sure that check box allow Azure services to access server is already checked, this will make sure that the database is reachable for my application. I'll then click Select. So our database server has been set. I can select a pricing tier here. After a couple of seconds, the prices are loaded. I'm going to select the basic tier, since that is more than enough at this point. I'll then click on Create, and sit back and relax while Azure is creating my database server, as well as my database. Over here, we can see that the deployment has started, and there we go, the deployment was successful. Let's go to the database. When looking at the SQL database, go to the Set Server Firewall. And in this case, I'm going to add my own IP, to be able to access my SQL server. I'll click on Save, and then the firewalls rules will be updated. I'll do this because I'll want to allow my own machine to create the database in Azure. And the next thing I'll do is, I'll go to Visual Studio and manage my database from there. In Visual Studio I'll go to the Server Explorer. Now, to follow along with what I'm doing here, make sure that you have the Azure SDK installed. To download the SDK, go to Azure.Microsoft.com/enus/downloads and there you'll find the correct SDK for your environment, in that case that would be Visual Studio 2015. Under Azure SQL Databases, you'll find the database that we have created earlier. I can right-click on my database, and select the Open in SQL Server Object Explorer option. This will open directly in Visual Studio, an Object Explorer to see all the tables, the views, and so in, in my database. It might be so that you get a window to enter the credentials for your database. So it seems that the database is up and running, as I'll continue to work to make sure that our application gets deployed correctly. Do not forget to remove that throw new Exception if you're following along, because otherwise we won't see all the pies showing in the live database. The next thing I'll do, is I'll copy the connection string from the Azure Portal. Click here on Show Connection Strings. And there you have your connection string, of course without user name and password. Copy this one to the clipboard. What I'll now do is I'll create a new App Settings file containing my production connection string. So I'll go to my project, Add New Item, and I'll select here, ASP NET Configuration File. The file I'll create is the app settings.production.json. In here, I'll replace the connection string with the one I've copied from the Azure portal. Don't forget to replace your username and your password with the actual username and password of your database. I'll do that next. Now I've created this App Settings production of json file, but by default, it will not be picked up. I'll need to make a change in my startup again. By default, we asked it to read out the appsettings.json file. I'll remove this line, and I'll replace it with the concatenation of app settings and then the hosting environment.environmentname.json. With the settings set to Production, this will result in the appsettings.production.json being used as the App Settings file. At this point, we'll do another build. The next thing I'll do, is I'll now call the updated database command in the package manager console to update, using the migrations that I've already created, the production database in Azure. I'll use the following command, here. So Update Database, I'll specify the context to be up db context, and then the environment parameter is set to production. Hit enter, and then the production database in Azure will be updated with the migrations I've already created earlier. And we see Done, that means success. All right, our database is now successfully deployed. We can actually explore that here in the SQL Server Object Explorer. Open Tables, and there we go, we have our orders, pies, shopping cart items and so on, so all our tables have successfully been deployed to the Azure database. And there's one more thing to do, and that's one small change in the project json file. In the Publish Options, we need to include the root folder, the views, the config, and the json files. Save this, and the only thing that's left is now to deploy the actual website. Now for that, I will use an Azure Web App. I can't create the web app directly here in the Azure Portal, but I can also use the Publish option from Visual Studio. In my opinion, using the Publish Wizard from Visual Studio is much simpler for our case. So let's do that. I will right-click here on the project, and then select Publish. I'll select Azure App Service. Select the New option here. Enter BethanysPieShopDemo as my web application name. I can add it to an existing resource group. Click on Create, the Azure App Service has been created at this point, but my application hasn't been published yet. So, at this point, the Publish Wizard is now showing me a summary of what it will use as settings. I'll click on Next here, I'll build my application for release, I do not have to include another database name. I click on Next, and then Publish. And after the Publish Wizard has done its work, it will open the website running live in Azure. Congratulations, you have successfully created your first ASP.NET Core website, which is now running in Azure.
Summary and Course Closing
To finish this module, let's summarize what we have learned. We started the module by looking at how we can set the value of the environment from variable, and you have used this value to check from code where the application was executing, so in which environment. Based on this value, we could then in production show the friendly error page that we have added. In the second and probably most important part of this module, I've taken you through the steps to deploy Bethany's Pie Shop to Azure, more specifically, to an Azure app service. And that concludes our time together. I hope that you have had a great time learning with this course. All that's left for me is to congratulate you on finishing this course. I encourage you to keep exploring ASP.NET Core MVC and building great applications with the future of .net. Thanks for watching this course, and bye for now.