0% found this document useful (0 votes)
468 views80 pages

Building An Enterprise Application With ASP Dot NET Core MVC

This course builds on a previous course that created a basic ASP.NET Core MVC web application for a pie shop. The goal is to extend the application with enterprise-level features. Topics covered will include security, identity management, administration interfaces, data validation, caching, logging, and continuous integration/delivery. By the end of the course, students will learn how to transform a basic website into a full-featured enterprise application using ASP.NET Core MVC.

Uploaded by

Subodh Singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
468 views80 pages

Building An Enterprise Application With ASP Dot NET Core MVC

This course builds on a previous course that created a basic ASP.NET Core MVC web application for a pie shop. The goal is to extend the application with enterprise-level features. Topics covered will include security, identity management, administration interfaces, data validation, caching, logging, and continuous integration/delivery. By the end of the course, students will learn how to transform a basic website into a full-featured enterprise application using ASP.NET Core MVC.

Uploaded by

Subodh Singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 80

Course Overview

Course Overview
Hi everyone, my name is Gill Cleeren, and welcome to my course Building an
Enterprise Application with ASP. NET Core MVC. I'm a solution architect for web and
mobile projects.. NET Core is the future of the. NET framework. It's where all
investment from Microsoft will go to from now on. Since its inception about 15
years ago, this is the biggest change ever made to. NET and ASP. NET. If you're
interested in learning how a real life line of business enterprise application can
be created with this new version of ASP. NET Core MVC, this course will be your
best friend. You'll get to see from a practical perspective how the common
concepts, such as security, logging, caching, testing, and much more are
implemented in a real life and fully working application. Some of the major topics
that we'll cover include security and identity in ASP. NET Core MVC, testing your
code with unit tests, adding logging to your ASP. NET Core MVC pages, improving the
site's performance using caching, and continuous delivery and integration with
VSTS. By the end of this course, you'll know how a real life enterprise application
can be built with ASP. NET Core MVC. Before beginning this course, you should be
familiar, however, with the basics of ASP. NET Core MVC. I hope you will join me on
this journey to master ASP. NET Core MVC with the Building and Enterprise
Application with ASP. NET Core MVC course here at Pluralsight.

Introduction
Module Introduction
Hi there, and welcome to this course named Building an Enterprise Application with
ASP. NET Core MVC. My name is Gill Cleeren, and it's great to see that you want to
learn some interesting stuff about ASP. NET Core MVC together with me. You can
always contact me with any questions you may have about this course or ASP. NET
Core via Twitter or via a discussion board for this course here on the Pluralsight
website. In the next couple of hours that we'll spend together, I'm going to try to
teach you some of the more advanced things about the shiny new release of
Microsoft's web development platform that is ASP. NET Core MVC. We're going to do
this by starting from an existing web application and we're going to extend it with
features that are typically used in a development of enterprise applications. So by
the end of this course, you will have gathered a lot more knowledge that is
indispensible when building real life enterprise applications with ASP. NET Core
MVC. Every module in this course will start with a small overview of what we are
going to do in that very module. So let's start with this tradition right here in
the first module of this course. This module is an introductory module to the
course, so we'll start with a short overview of the course and what you'll learn in
the next couple of hours. Next, we'll take a look at the finished application that
we'll be using and working with throughout this course. Finally, to finish this
module, we'll spend a few minutes making sure that you have everything ready to
follow along with me in this course in the topic getting your machine ready.

Course Overview
So, first things first. Let's take a moment to see what you'll be getting from this
course in a brief overview. Now building a web application isn't rocket science.
When we are building enterprise web applications, we'll come across some challenges
that we'll need to solve, and the goal of this course is helping you understand how
you can solve typical problems that you'll encounter when building an enterprise
website. Now we'll do all this using ASP. NET Core MVC and the tooling that we'll
use is the ASP. NET Core tooling that comes with Visual Studio 2017. And this
course won't be building an application from scratch. Why not, you may be asking.
Well, because I have already created that in a separate course here on Pluralsight
titled, "Building your first ASP. NET Core application. " In this course, we'll
start from the blank slate and we'll build together a fully working, but still
basic web application with ASP. NET Core. You can find the course using the URL
that you can see here at the bottom of the slide. In that course, and therefore
also in this course, we'll be building the web store application for Bethany.
Bethany has a pie shop, and she wants to sell her pies via a new web store front
end. The application is entirely built in ASP. NET Core, and includes a shopping
cart, a couple of other pages, a registration system, and much more, and the site
is also deployed in an Azure app service, which is the final part of the first
course. Now this course, as mentioned, will build on the foundation that we have
laid in the aforementioned course. We'll basically start from the "basic" website.
Throughout this course, we're going to write quite a lot of code, and thus add a
lot of extra functionality, but also a lot of basically invisible features. All of
these will level up Bethany's pie shop from a basic web store with no
administration interface to an enterprise level web application ready for
primetime. The value for you, dear viewer, is of course that you'll learn about
enterprise level features in an ASP. NET Core web application. So, what exactly
will you be learning in this course, you may be asking. Well, let me give you a
short overview of some of the most important topics that we'll be covering in much
depth in this course. We'll dive deep in the ASP. NET Core Identity system. This
was already covered in the first course, so the introductionary course, but we only
have scratched the surface there. I will dive deep in the many options the system
offers here. Next we'll spend quite some time adding security related features to
our site. Any enterprise web application should be armed to withstand the dangers
of the internet. I'm going to show you some of the things that we can do in this
area. We'll be adding a full administration back-end to the application, allowing
the users of the application to manage products, here that would be the pies,
manage the users, and so on. In these type of pages, there will be a lot of data
that is entered by the user. Data entry equals errors, and it's vital that we
validate the data before sending it off to the data store. ASP. NET Core comes with
a lot of options in this space that we will explore. Tag helpers and view
components are probably one of the most touted features of ASP. NET Core. We'll go
deep in both of these features here, explaining the many options they offer beyond
the basic demo. We'll also look at how we can increase the performance of the site
using caching. ASP. NET Core has a lot of new features in this area. I will also
look at the different options that we're getting to log information using the
built-in log system. Finally, we'll look at setting up an automated build using
VSTS, or Visual Studio Team Services. How it is automated built, we'll also deploy
automatically to Azure, so we're setting up continuous integration and continuous
delivery. That's quite a lot of ground that we have to cover, isn't it? Now just to
be on the safe side here, let me set the expectations for this course from my side.
This course is expecting some basic knowledge about ASP. NET Core MVC. I'm not
spending time on explaining the basic concepts in this course. Of course, we're
going to write all of our code in C#, so basic knowledge of C# will do. You do not
need to be a super ninja expert. And yes, we are building a web application, so I
am assuming that you have some basic understanding of HTML and CSS here as well.
Before continuing, I'm going to show you the finished application with some of the
features that we'll add in this course. Let's take a look, shall we? In the first
demo of this course, we are going to take a look at the finished application. As
mentioned already in the slides, this course builds on the application that was
constructed in the Building your first ASP. NET Core Application. You can take a
look at that course here on Pluralsight as well. Simply search for Building your
First ASP. NET Core Application. Now, in this course, we are going to extend the
site both visually and non-visually, and I'm going to take you through the end
result of this course. So the homepage contains a banner, so a sliding banner with
some images, and then a selection of pies of the week. I can click on one of the
pies, and then I will see the details of that particular pie. One of the things
that we'll add in this course are reviews, and you may already notice that someone
has already tried hacking our site, but we'll try to secure ourselves from that as
well. It's possible to add this pie to your cart, and then you will go to this
shopping cart page. You will see at the top a shopping cart icon that contains
currently 1 item. I also have this progress here that we'll construct later as a
custom tag helper. I can then click on the Check out now button. That will take me
to the login page at this point, because I'm not logged in, so I'm going to log in
with my account, so Gill, and enter the password. Notice that it's now also
possible here to log in using Google. I will add that later on as well. So now I'm
logged in. You can see that I now have more features in the menu at the top, and
here I can also complete the order. Let's go back to the homepage for a second.
This version of Bethany's Pie Shop now also supports languages. It's possible to
translate a site, for example, in French. If you understand any French, you'll
notice that tartes de cette semaine, it's French for pies of the week. Now let's
put it back in English, so that hopefully everyone understands what it says on the
screen here. You also have the ability to see a selection of pies per category, so
for example, all cheesecakes. There's a new option here on the site as well called
Send a pie, which will allow us to send a pie and we'll notice later on in this
course that this page opens our site for cross-site request forgery attacks, which
is not good news anyway. There's also a Contact us page, which allows me to contact
Bethany. There's also a Promotions area, which we'll talk about when we discuss
areas. The site now also contains some administration pages. We have the ability to
manage the users, manage the roles, and also create new pies, and we'll discuss
these pages in much detail later in this course. Now behind the scenes there's also
quite some changes that have been done to the site compared to the site that we
create in the introduction course. I'll discuss things like caching, logging, and
continuous integration build using VSTS. So as you can see, it's a pretty complete
site at this point. Now if you want to follow along with everything that I'm doing
in this course, and I encourage you to do so, please download the source code
directly from the Pluralsight website. You can find everything under Course
Downloads. You'll find a starter project per module so that you can follow along.
And also for each demo, the finished project is included.

Getting Your Machine Ready


Now that we have seen what you'll be learning in this course, it's time to get you
set up. Let me give you a brief overview of what you should have already installed
on your machine before continuing with this course. Now for this course, we are
using ASP. NET Core 1. 1. 1, which at the time of recording was the latest
available version. Therefore, this course is already using the new project
structure using the csproj files, so we won't be using the project. JSON approach
anymore. This course has also been recorded using Visual Studio 2017, which is the
first version of Visual Studio that comes bundled with. NET Core. Some of the
topics that we'll discuss in this course are specific to this version of. NET Core,
or even Visual Studio. Also, since Visual Studio 2017 is the first one to come
with. NET Core support out of the box, it's also the first version to support the
real tooling for. NET Core. When you have Visual Studio 2017 installed, there's
basically no need to install anything extra. And finally, you'll need a browser, of
course. But I think that was pretty obvious already. This is the setup that I am
using in this course as well. Now. NET Core is all about cross-platform
development, and fully supports building and running applications on Mac and on
Linux as well. Next to Windows, of course. So in terms of tooling, you're also not
tied to using Visual Studio. If you want, you can do all your. NET Core coding
using Visual Studio Code, which is, of course, available for all these platforms.
Also, any OmniSharp-ready C# editor will also work. This includes Atom, Sublime,
and even Vim. That means that basically no one is excluded from following this
course. How great is that! I think, or I hope, I've whet your appetite to learn how
to build an enterprise application with ASP. NET Core MVC in this module. Yes,
ready? Let's get started.

Authenticating and Authorizing Users with ASP.NET Identity


Module Introduction
Hi there, and welcome to this module titled Authenticating and Authorizing Users
with ASP. NET Identity. My name is Gill Cleeren, and I'll be guiding you through
this module. If you have any questions about this course, feel free to contact me
via the message board here on Pluralsight. The title of this module is pretty long,
and in fact, the module is a pretty long one as well. We'll be covering quite a lot
of topics in the area of Identity, the part of ASP. NET Core that makes it easy for
us to work with and manage users in our enterprise web application. The framework
has so many options on board that you'll need to have a very good reason in order
not to use it. Now let's take a look at what we'll be looking at in this module.
We'll kick off the module by exploring how ASP. NET Identity can help us with user
management in our site. We'll explore how we can use the built-in system to create
users and manage them from within the application. By default, ASP. NET Core uses
the built-in IdentityUser class as a way to represent a user in the system. This
class is pretty limited in terms of available properties of data that we can store.
However, it is an extension point, and we'll see how we can create our own
implementation of the Identity user class and thus store more information than just
the default. And next to authenticating, ASP. NET Identity also allows us to manage
the authorization of users, so basically anything that has to do with the
management of user roles. We'll explore how we can use roles and role-based
authorization. Now, ASP. NET Identity also supports different types of
authorization, namely claims-based authorization, and policy-based authorization.
Now we'll be exploring both of these in this module as well together with some
demos of how we can add this to the site. Finally, we'll also extend our site so it
will support third-party authentication, meaning that I can use, for example, my
Google or my Facebook account to register and log in to Bethany's Pie Shop.

User Management
Now, first things first. We'll start with the authentication port, and more
specifically, we'll take a look at user management. Now, Bethany's Pie Shop is
live, and she's been selling pies like crazy. So, business is great for her. Her
site is getting a lot of new registrations on a daily basis. Also, Bethany has
decided that she can't keep doing everything by herself, and so she has hired some
extra staff to work with her. Now she's come to our office with a rather simple
question: "I need to be able to manage all these new users from my site. Is that
possible? " We are lucky that ASP. NET Identity has great support for this. It will
actually be rather easy to build this for Bethany. Let's take a look. ASP. NET
Identity is an API that comes with ASP. NET Core. It is the API that we'll be using
for authentication and authorization. Anything that has to do with the user
management can be done with ASP. NET Identity. We can do all kinds of actions on
users, such as enumerating users, creating and updating users, and deleting users,
so the typical CRUD operations, but also much more. The class that makes this
possible is the UserManager. This class handles all the interactions behind the
scenes with the persistent store. So in general, that would be entity framework and
the underlying database, in our case, will be SQL Server. To enable the usage of
ASP. NET Identity in an ASP. NET Core application, we need to perform a few steps
to configure it. First, we need to reference a package. Since the release of Visual
Studio 2017 and. NET Core 1. 1, packages are no longer managed in the project. json
file. Instead, we can add them by editing the re-introduced csproj file. You'll see
me editing this file in numerous times in this course. After add support for
Identity, we need to reference the Microsoft. AspNetCore. Identity.
EntityFrameworkCore package. This is now, as you can see again, XML code. Now with
a reference to the package ready, we need to configure Identity in the Startup
class for our application. In the code that you see here on the slide, which by the
way we created step-by-step in my first ASP. NET Core MVC course, we first
configured application to work with the database of which the connection string is
available in the appsettings file. Next, and more relevant to what we are looking
at here, is the. AddIdentity call, to which we are passing IdentityUser and
IdentityRole. These two built-in classes will be used as configuration for the
Identity system. Using the. AddIdentity framework stores call, we enable the use of
Identity on the backing data store. Next, we also need to add one line of code in
the Configure method here, still part of the startup class. The UseIdentity call
finally enables the use of Identity in our application. Now, if you need more
detailed steps on configuring Identity in your application, take a look at my first
course where I am doing all this in many detailed steps. Now with Identify
configured, we can now start using it. Now, Bethany has asked us that she needed a
way to be able to manage all the users inside of her application, so basically all
users which are registered in the site. Most actions, including enumerating users
in the backing store, are done using the userManager class. It has an IQueryable
property called Users that will give us access to all users in the application.
Here I am returning these users to a view, which can then be used, for example, to
visualize all users inside the application, for example, in an administration page
of the site. Now not only can be enumerate users using the userManager class, we
can also use it to manually create users. Imagine that you want to create a user
administration page where the administrator of the application can create new user
accounts. This will come in handy. Here we can see that we simply call the
CreateAsync method on the userManager class, and then Identity will create user in
the persistent store for us. All the nitty details of how this is handled on a
database level are abtracted away. We really don't need to bother. The first
parameter that we're passing is a user with data such as the name and a second
parameter is a password that we'll want to create the user with in a database. Now
remember that Identity takes care of securely storing passwords in the database,
including salting, so we really don't need to worry about this; it's all taken care
of for us. Now talking about passwords, in today's world, we need to be sure that
our users enter strong passwords. With strong I mean enough characters, at least a
non-alphanumeric character and so on. Identity has the ability to enforce rules on
passwords which are created in the application, where the user registers via the
public registration, or when we will want to create a user manually in the
administration of the application, the used password will then have to follow one
or more rules specified by us as the creators of the application. And we can set up
these rules during the configuration of ASP. NET Identity. So again, in the Startup
class. In the snippet that you see here on the slide, so in the. AddIdentity call,
I'm passing Identity options, and I'm specifying different requirements for both
the password, as well as the username. At least 8 characters are required for the
password, for example. We'll take a look at more rules that we can enforce in the
upcoming demo.

Demo: User Management


You've now seen that User Manager is the entry point to working with the
authentication part of ASP. NET Identity. We will now go to the first demo of this
module where we'll take a look at the user administration pages in Bethany's Pie
Shop, allowing us to see an overview of the users of the application, as well as
managing users from the admin part as well. In the first demo of this module, I'm
going to show you the user administration page. I'm now logged into the site, and I
see this Admin menu where I can select User management. On user management page, I
see an overview of all users in my site. I can add a new user. I'll create a user
with the username Demo. I'll give him an email address, and I'll also set the
password, of course. I can now also edit the user, as well as delete the user.
That's now see in Visual Studio how this was created in ASP. NET Core. The code for
this functionality is located in the AdminController, which is a new controller in
my controllers folder. As you can see, this AdminController is attributed with the
Authorize attribute, meaning that only authorized or logged in users at this point
can work with this controller. The AdminController is using the userManager class.
This class allows me to work with users in my site; for example, I can use it to
create users, search for users, and so on. The userManager is injected using
dependency injection into this controller. The UserManagement action method here is
retrieving from the userManager a collection of all users, and as you can see, it
returns an IQueryable of all users in my data store. This collection is then
returned to the view. Let's take a look at View. So we're now looking at the
UserManagement view. The model for this is an IEnumerable of IdentityUsers. That's
the list, of course, that I've just returned to this view. An IdentityUser is the
built-in class from ASP. NET Core to work with users. If there are no users in the
collection, I'm going to simply say No User Accounts. Otherwise, I'm showing this
table here, which is going to loop over all the users in the model. I'm going to
show the user ID, username, email, and then I have also added these buttons here.
There's a form that I've created for these buttons. The action will post to
DeleteUser, which is an action method I'll show you in just a second on the admin
controller, passing in as a route parameter, the user ID. I then have the Edit
button, which is going to invoke the EditUser action method. And then I have the
Delete button, which is going to first ask me if I really want to delete user using
a simple confirmation dialog, and if that is the case, then it will post to the
DeleteUser, which is defined as the action on the form. I also have this button
here at the bottom, which is going to go to the AddUser view and AddUser action
methods. Well, let's start with the AddUser. The plain AddUser will simply return
the AddUserView. The AddUserView is just a simple form, which is going to allow the
user to enter the data for creating a new user, including username, the email, and
the password. Nothing special is going on here. In the HttpPost version of AddUser,
I'm expecting an AddUserViewModel. Now let's get back to the view for just a
second. As you can see the, AddUser is indeed typed to AddUserViewModel. So this
view is actually going to return an AddUserViewModel instance. And that's going to
happen when the user is hitting the Submit button at the bottom of the page. Let's
take a look at the AddUserViewModel. It's a simple view class, which contains some
validation attributes, which we have already covered in the introduction course,
and we'll come back to validation later in this course. I'm expecting username,
email, and password. There's a model that's not valid. I'm simply going to return
the same view, returning again the same UserViewModel, so that the user can correct
the data. If everything is okay, well, then I'm going to continue creating a new
IdentityUser. The IdentityUser comes with a number of properties, including the
username and email, so I'm going to set these. Then I'm going to ask the
UserManager class to create a new user asynchronously, passing in that just created
IdentityUser, as well as the password. The result that's going to be returned is of
type Identity result, and I'm going to check if everything is okay. If that is the
case, I'm going to return to the UserManagement page. If not, I'm going to loop
over all errors in the Identity result, and I'm going to add them to the model
states. In that case, I'm going to return again to the same AddUserView. And I want
to add a new user, I'm again going to use the userManager to find a user in this
case. I'm passing the id and the userManager class is going to search in the data
persistent store for the correct user. If I don't find the user, well, I'm not
going to return anything; otherwise, I'm returning the edit view, passing in that
user. The Edit user view is pretty simple. It's typed in Identity user, as you can
see at the top of the page, and then it simply displays the same fields for the
user. The EditUser method is pretty similar. In there, I'm going to again search
for the user. If I find the user, well, I'm going to set the new email and
username, and I'm going to use the UpdateAsync method of the user manager to update
the user. Deleting the user is done by another HttpPost attributed method called
DeleteUser, and I'm passing in the user ID. Just to be sure, the user ID is going
to be passed using this user ID route parameter that you see here on the form in
the overview of the users. So when I find the user, I'm then going to use the
userManager. DeleteAsync method to delete the user from the persistent store.
That's basically all the code, which is now at this point in the admin controller
to control the user management. I've made the changes in the startup code as well.
In the Startup class, I already had the AddIdentity, but I've also added some
options here on the AddIdentity method, which control how the user can be created.
For example, I specified here that the password should have a required length of 8
characters. It should contain a no-alphanumeric character, it should require an
uppercase character, and the email for the user should also be unique. There's
quite a few options that we have here. We can simply take a look at IntelliSense,
and you see quite a number of options that we can set on the password. And, well,
let's run the application again, and I will see how these are enforced. So when I
now create a new user by going again to the administration page, let's set the
email, and then I set a password. For example, simply the letter A, and I hit
Create user, I will see some validation errors here that match with the options
that I had set in the Startup class. This will enforce that when a user is created,
these rules are followed.

Extending the IdentityUser


So far, we've worked with the built-in IdentityUser class for the public
registration and for the manual registration in the admin part as well. The
IdentityUser class comes for free, but it also is limited in the amount of
properties that it defines. Typically in real-world applications, we'll want to
capture more information about the user. Can't we use the IdentityUser in this
case, then? Well, yes and no. What we'll need to do is extending the IdentityUser.
Let's take a look at how we can do that. Here we see the properties of the built-in
IdentityUser class. It contains properties for typical information we'll want to
capture in most applications, such as the username, the email, the password, the
phone number, and quite a few more, as you can see. For an application such as
Bethany's Pie Shop, we'll typically need to know the user's address. How else are
we going to deliver those delicious pies to the customers? The Identity system
supports inheriting from the base identity user, as we can see here. This
ApplicationUser class adds the properties that we'll need in our application, such
as the birth date, city, and country. Now because ASP. NET Identity is based on
Entity Framework Core, and it defaults to using Identity User, we'll have to make
some changes in the code that we already have in our application. In the Startup
class where we are registering the different services, we now need to specify that
we'll want Identity to work with our custom ApplicationUser class. Basically, in
every location where we may have been using the default Identity user, we now need
to use ApplicationUser. Now one more thing that we need to do is asking Entity
Framework to generate the corresponding fields in the database. We'll just have to
do a database migration to update the underlying database schema.

Demo: Extending the IdentityUser


Let's take a look at this in the next demo. I'm going to create a user class which
defines some more properties in the application, and I'm going to show you what we
need to do inside the application so that this new user class will be used.
Microsoft has given us by default. In this demo, I'm going to show you how we can
use a custom class for working with users that contain more properties than the
built-in Identity user. The built-in Identity user class comes with a number of
properties, such as the email, the password, the username, but it of course doesn't
contain anything such as city, country, and so on. So if I want to capture these, I
need to add them myself. I've already done that. I'll show you the code in just a
second, and I'll first show you how it works. So I'm again in the User Management
page, and I can click on the Add new user button here. And as you can see, I now
have the ability to capture more data for the user, such as the birth date, the
city, and the country. These will now also be persisted to the data store when I
create a new user. So let me quickly create a new user. So I've now entered the
data for the user, I click Create user, and the user is added to my overview. And I
now go to the Edit page. I will also see this newly captured data. Let's see how
I've done that in the code. Well, it all evolves around this new ApplicationUser
class, which you can find in the Auth folder. The ApplicationUser is inheriting
from the built-in Identity user, and adds the properties that I need in my
application, being birth date, city, and country. And the first thing I need to do
to work with this application user is updating the database using another
migration. So I can go to the Package Manager console and add another migration
using the add-migration command. I can give it a name, such as
ApplicationUserUpdate. When that has executed, I need to do an update-database. And
this will update my data store to use my ApplicationUser and its properties
correctly. If we now go and look in the database, I will take a look at the
AspNetUsers table, we'll indeed see that the birthdate, city, and country
properties were added. Now basically wherever I was using IdentityUser directly, I
now have to update it to use ApplicationUser. For example, in the Startup class, I
need to register Identity now using the ApplicationUser class instead of the
IdentityUser. In the AccountController, the UserManager and the SignInManager are
now using the ApplicationUser as well. In the Register method, for example, I now
need to create an ApplicationUser instead of an IdentityUser as well. With the
AdminController, it's basically the same thing. I'm now using the ApplicationUser
as a type for the userManager, as you can see here. The AdminController already had
the AddUser method, which is indeed again going to create a new ApplicationUser
using the new birthdate, city, and country. I also, of course, have updated the
AddUser view, which now also contains fields for the birthdate, the city, as well
as the country. Also, the AppDbContext, which inherits from the IdentityDbContext,
is now working with the ApplicationUser. And also in the Layout class where I
previously already was using the SignInManager, I'm now going to use the
ApplicationUser. As you can see here, I'm injecting the SignInManager and
UserManager into my Layout view using inject, and they're also going to be typed in
ApplicationUser. I'm using the SignInManager here to check if the user is signed in
already, and then decide whether or not I need to show the administration menu. The
SignInManager, of course, now also should work with the ApplicationUser I've just
created. So basically when you want to have more properties than what IdentityUser
offers you, create a new ApplicationUser, and wherever you were using IdentityUser
before, replace it with your own ApplicationUser class. Don't forget, as soon as
you add new properties on your ApplicationUser that you should be doing another
database migration.

Role Management
We have deployed the application again. Bethany has been using our newly
implemented user management for quite some time. But she has an addition request in
this area for us. She has defined a number of administrators in the application,
but with her growing business, she needs to be able to manage all these users in
groups. Typically groups of users will have the same permissions in the site. Let's
see how we can fix this for her. The requested feature of so-called groups of users
will be handled for Bethany by introducing roles into the application. In the
introduction course, we have already added the administrator role. But real life
enterprise applications will require a more fine-grained control of permission for
groups of users. Role management will make this possible for us. Let's take a look.
ASP. NET Identity has numerous classes on board. We've already seen the
UserManagement as the class to work with users. Well, similarly, a RoleManager
class exists, which, surprise, surprise, will allow us to work with roles in ASP.
NET Core. This class will allow us to create roles in the system. Just like with
users, it will automatically handle the details of storing the information in the
persistent store for us. We don't really need to bother again with the nitty
details. We'll also be able to attach users to roles. Identity in itself therefore
allows us to create roles and attach users to it. However, it doesn't know what a
role really means. That will still be part of the actual MVC code where we will
again work with the authorized attribute. We can use this attribute in combination
with role membership to check if a logged in user has the ability to execute a
given action. Here you can see this in action. We're looking at the AdminController
here. And it's been decorated with the Authorize attribute. We've effectively
authorized users based on their membership of a role. Hence, we refer to this type
as role-based membership. I have, however, added a parameter roles on this
attribute with the value Administrators. The Identity system will now check if the
logged in user is part of the administrator role, and if so, only then will the
user be able to access the actions on this controller. Of course, if you'd only be
able to specify a certain role to be able to access the actions of a certain
controller, you'd end up creating a lot of different roles, perhaps one role per
controller in the worst-case scenario. That is definitely not very productive, and
would lead to a lot of overhead of managing all these roles in the application.
It's therefore possible to add multiple instances of the authorize attribute onto a
controller, each specifying a different role, which has access to the actions of
the controller. In this snippet you can see here on the slide I specify that the
AdminController's actions are accessible to users in the Administrator role, and
also the role SomeOtherRole. It's an or or case here. If you, as a user, are a
member of the Administrator or the SomeOtherRole role, or both, you will have the
permission to call the actions on this controller.

Demo: Role Management


Now that we know how roles are managed in ASP. NET Identity, and that we have seen
the Role Manager already, let's go back to the demo. It's time to add role
management in the application. So we'll look at how it will be possible to manage
users, then, we'll see how we can manage the users within these roles, and finally,
we'll work with the authorization attribute in combination with roles, and we'll
see how we can get some fine-grain control over which role gets which permission in
the application. In this demo, we are going to take a look at the role management
that we get with the ASP. NET Identity framework. So I'm back here on the landing
page, and I'm going to log in again with the user we've created earlier, so the
Demo user. And when I'm logged in, you can see that this user is not seeing any
administration menu. I'm now going to log in with the administrator, so Gill, and
of course, then I see the administration menu, I go to the role management page,
which is now a new page that we'll take a look at in just a second. It shows me the
roles that I currently have in this system. I have a couple of roles here, the user
role, the administrators role, and also a test role. When I want to make my demo
user an administrator, I can now go to the Edit page, and here I now have the
option to add a user to a role. I can select the Demo user, Add to role. And I'll
take a look now at the administrator's role. I see that indeed the Demo user is in
this role. So let's log off now and try to log in with that Demo user once more.
Hit Log in, and now I do see the user management and the role management as well.
This is, of course, all due to the fact that we now have role management added to
the site. Well, let's take a look at the code how we've done that using ASP. NET
Identity. The entire role management part in the application is managed through the
AdminController. Notice first that I do have the Authorize attribute here, and it
is now expecting that the user that is trying to access the actions on this
controller, is part of the administrator's role. Role management is done using a
class called the roleManager in IdentityRole. It's very similar to userManager in
that it allows us to manage roles based on the built-in identity role. The
roleManager will also be passed to this controller using the dependency injection
system that comes with ASP. NET Core. So I've now added a couple of action methods
to manage the entire role management system. First I have the RoleManagement action
method, which is going to ask the role manager for all roles and is going to pass
these to a new vie called the RoleManagement view. So here we are looking at that
RoleManagement view, and it is typed to an IEnumerable of IdentityRole. Very
similarly, I loop over all the roles in the model, I showed ID and the name, and I
then also have a form to delete a role, as well as a button to edit a role. Both of
them will call an action method, delete role or edit role, and will pass the role
ID as a route parameter. At the bottom of the page, I have another button that
we'll call the AddNewRole action method. All of these methods are part of the
AdminController. So here we have first the AddNewRole action method, which will
simply return the plain View. That will be the AddNewRole view. That's a very
simple view, which is typed in a view model, the AddRoleViewModel. We're just going
to post to the AddNewRole action method, and it simply accepts the role name. At
the bottom we have a button that we'll post to that AddNewRole action method. So
when a new role is done being created, this addRoleViewModel will be passed. As
mentioned, it just contains the role name, which is required by the way, and will
be displayed as Role name. If the validation fails, then we're going to return the
same view again, passing in that RoleViewModel. If everything goes well, then we
are creating a new identity role, and we're using the CreateAsync method of the
roleManager to create the new role within the persistent store. And it's going to
very similarly do what we had with the user manager return us an Identity result.
I'm going to check if the result has succeeded, and if that's the case, I'm going
to return to the RoleManagement view. If not, I'm going to show the errors that
were encountered. The EditRole method, the one that is simply doing a get, will be
returning a role based on the ID. Again, very similar to what we had with the
userManager, the roleManager has a FindByIdAsync method that will return the role.
If you don't find it, we go back to the RoleManagement overview. If you do find it,
I'm going to create an EditRoleViewModel. The EditRoleViewModel contains the ID, a
role name, and also a list of users that are within that role, and I'm simply going
to return them here as strings. I then used the UserManager to check if a user is
in the given role. And if that is the case, I'm going to add that user to the list
of users in the EditRoleViewModel, which is then returned to the view. Here is that
EditRole view, which is indeed receiving the EditRoleViewModel. The first part of
the page is pretty simple, but I do want to point out this Users in this role
section, which is going to loop over the users which are part of this role, and I'm
going to display them in an unordered list. The EditRole is again pretty similar.
I'm searching for the role based on the ID, and I'm going to update it if I do find
it using the roleManager. UpdateAsync method. Deleting a role, again, pretty
similar. I'm going to find a role using the FindByIdAsync, and I'm now going to
delete the role using the DeleteAsync method of the roleManager. Now working with
roles is pretty useless if we can't add any users to the roles we are creating.
That's why I have the next part within my admin controller that allows me to add
users to particular roles. So here in the AddUserToRole action method, I'm passing
in the roleId, I find the role, and then I will create a new UserRoleViewModel.
This UserRoleViewModel contains a UserId, a RoleId, and a list of all
IdentityUsers. I specified RoleId as the one that I want to start editing. I then
asked the user manager to loop over to users, and I will try to give the user as
part of the given role and if that is not the case, I'm going to add it to the list
of users part of my UserRoleViewModel. I then return that to the view. Just as
small reminder, this is going to be used for this particular view here. So I'm
going to get a list of all users which are currently not part of the given role.
Let's take a look at the actual view code. So the Add user to role is indeed
receiving a UserRoleViewModel. I passed the roleId as a hidden input, so that I can
afterwards retrieve it. I then built up the select HTML element, which is going to
use the user ID to check which item was selected, and the items are going to be
bound to a new SelectList. That really hasn't changed from ASP. NET MVC, so that
SelectList is something that if you've been using ASP. NET MVC before will look
familiar. And I'll pass it as the data the users collection within my
UserRoleViewModel. The ID is going to be the value that is going to be used behind
the scenes, and the username is going to be displayed. When the user then adds a
user to the given role, we will search for the user, as well as for the role, and
then we try to add the user to that particular role, using the AddToRoleAsync
method, part of the userManager class. The application also contains the
DeleteUserFromRole, which is pretty similar. I'm not going to show you all the code
for this in this demo. You can take a look at it in the code downwards. And there's
one very important part that I still need to show you. And that was the hiding or
showing of the administration menu in the layout file. Let's go to the layout, and
in here, I'm now going to check that the user is signed in, as well as part of the
Administrators role, and only then I am going to show the AdminMenu, and I'm doing
that using the SignInManager, which is going to check if the user is signed in, and
if the user is part of the Administrators role using the User. IsInRole method.
That's how we can work with roles in ASP. NET Identity.

Claims-based Authorization
ASP. NET Identity is in fact the evolution of ASP. NET membership. In membership,
the application itself was basically the only source for all information about a
user, so we could only get information about the user from the application itself.
Now in this scenario, as we've done so far as well, we have basically only allowed
authorization and authentication based on the information stored in our own
database. For many applications, this approach is perfect, and they don't require
anything else. Now ASP. NET Identity does allow a different, less-closed approach.
In this approach, the application itself is not the only source of information,
allowing for a more flexible approach than what we just saw with just roles. Now
the information can come from an external source, and can thus be used in the
application to see on that information what is allowed in the application and what
isn't. And this alternative approach is using something called claims, and it's
also referred to as claims-based authorization. Let's first take a look at what
claims really are. If you look up the word claim, you will typically find something
like saying that something is true. Well, that is not very far away from what we
are using as claims in ASP. NET Identity. A claim is, in fact, a name value pair. A
piece of information, really, that specifies what the subject is, not what it can
do. A claim is typically issued by a trusted third party, although it is very well
possible to work with an internal claim as well. Your travel visa will contain your
date of birth. The date of birth here is the claim, and it's issued probably by
your government, which is the trusted party here. They specify that you were born
on that particular date. That's the name value pair. The claim here is then used
externally. Claims are policy-based, meaning that we as developers will have to
register one or more policies in code. A policy will define the claim requirements.
For example, an example policy could be we need to have the claim date of birth
before we give access to a particular action method. Another policy could be the
date of birth claim not only needs to be present, but the value must be larger than
a given value. Now what does this have to do with ASP. NET Identity then? Well, in
claims-based authorization, we're actually going to get in one or more external
claims that we are going to assume are true, since they are provided to us by a
third party, a trusted third party even. Based on the value they contain, for
example, your date of birth, we are going to give you as the user permissions to
access a certain resource in the system, which could be, again, accessing an action
method of a certain controller. Let's see how we can start introducing claims and
policies in ASP. NET Identity. Now the first step is actually defining the policy.
We'll need to define what claims are required to meet the requirement of the
policy. Typically this is done in the ConfigureServices method of the Startup
class. Take a look at this snippet here on the slide, which contains code that, as
mentioned, should be part of the ConfigureServices method. To the AddAuthorization
I'm passing an options parameter, which is of type Authorization options, and on
that options parameter, I can call the AddPolicy method to add one or more policies
in code. The first parameter is simply the name that I'll be using to refer to this
policy later on. Now the second parameter is an action, in which I define that the
Delete Pie claim should be present on the current identity. So how should you
understand this, then? Well, I'm creating here a policy that I'll use later on and
that policy specifies that the Delete Pie claim should be present in order for it
to allow the requested action. Now that we have defined the policy, we can use it
to authorize. In the snippet you see here on the slide, I'm again using the
Authorize attribute. But instead of defining role, as we did before, I'm now using
the policy parameter, and as value, I'm specifying the DeletePie, which was the
value I have defined in the previous snippet as the name of the policy. So, in
order to execute any actions on this controller, the Identity will have to follow
the requirements specified in this claim. And that was having the DeletePie claim
to be present; otherwise, the logged in identity will not be able to call any
actions on this controller. Know that the authorization system is pretty flexible
in ASP. NET Identity. Here I'm combining several policies. Now pay attention. All
policies must be met in order for the user to be able to call an action on this
controller. So, there must be a claim that satisfies the DeletePie, as well as a
claim that satisfies the AddPie policy, whatever that may be. Now on top of that,
it's also possible to combine these with role-based authorization, so I can even
add an authorized attribute that specifies that the user must be part of the
administrator role.

Demo: Adding Claims-based Authorization


Let us now return to the application and add support for claims-based
authorization. In this demo, I'm going to show you how we can work with claims,
claims that we're actually managing ourselves from within the application still.
The first thing I'm going to show you is logging in with that Demo user once again.
So when I log in, I now see a page called Pie Management. But when I click on it,
I'm seeing a message that I don't have any permissions for this particular action.
Well, let's log off again, log in with the administrator user, so Gill, and I'm now
going again to User Management. I'm now going to edit that Demo user, and now I
have this claims for this user section here at the bottom. I click on it, and I'm
now going to a view called Manage claims for user, where I can add different claims
for this particular user. In this case, I have a claim called Delete Pie. You can
name them whatever you want. We'll see that in the code in just a second. So I'm
going to add this claim for this particular user. Let's check that this claim was
successfully added. Now we see the Delete Pie claim is active for the Demo user.
Let's log off and log in again with the Demo user. When I now click on Pie
Management, I see the Pie Management page. So using claims, I'm now capable of
managing whether or not the user has access to this view. Let's see in the code how
this was achieved. Now the Pie Management is actually controlled using the
PieManagementController. And as you can see, this controller now has two Authorize
attributes. Both of them need to be satisfied for me to be able to use the action
methods within this controller. So only when the user is part of the administrators
role and has a Delete Pie claim, we will be able to access the action methods part
of this controller. Initially, we did not have the Delete Pie claim, so that's why
we weren't permitted to do anything on the Pie Management view. Now I'm not going
to show you the rest of the controller in detail, it contains a couple of methods
to work with pies, to add pies, to edit pies, and so on. You can take a look at
this code yourself. Now let's take a look at how we can work with these claims
then. The first thing I've done is I've made a change in the Startup class. In the
Configure Services, I've made a change to the way that authorization works, using
the Authorization options and adding a couple of policies. Using the AddPolicy
method, I first specify the name and then the authorization policy. The policy in
this case is an action in which I specify what needs to be done to satisfy this
policy. In this case, I'm specifying that when the DeletePie policy is applied that
to satisfy it, a claim DeletePie is required. This DeletePie name was the name of
the policy that has been applied on the PieManagementController. I've made some
changes to the EditUser View. I'm going to show all the claims which are currently
applied on the given user. And then I also have the ability to change the claims
for the user using the ManageClaimsForUser action method. Let's take a look at the
controller that manages all this. I'm now here in the AdminController in the
EditUser action method. I first searched the user using the FindByIdAsync method.
Then, I used the userManager once again to ask for all the claims that this user
already has, and these claims will then be passed to the EditUserViewModel. I've
made some changes to it so that it now also contains a list of user claims. And I'm
passing all this data to that EditUserViewModel, which is then passed to my view.
And I also need to be able to manage the claims, which is what I showed you in the
demo. To the ManageClaimsForUser view, I'm going to pass another new view model,
the ClaimsManagementViewModel, which is going to contain the user ID, as well as
list of all possible claims within my application. In this case, it's a hard-coded
list of strings, basically claims that I have within my application. And this will
then be passed to the ManageClaimsForUser view. In the post version of the
ManageClaimsForUser, I'm going to add a claim onto a user. Let's first take another
look at the view, so the ManageClaimsForUser view, so in here I have the UserId,
and I had that select, which as its value contains the ClaimId of the claims that
I'm passing to this view. And the select will return the ClaimId for the selected
claim. So in the code, I'm first going to search for the given user, and then I'm
going to create a new IdentityUserClaim. And I'm going to specify the claim type
and the claim value to be equal to that ClaimId, which is going to be returned from
my view. I then add to the claims collection of the user my new claim, and I update
the user using the UpdateAsync method of the user manager. That's how I can add a
claim onto my user and how I can basically work with claims within the application.
And only when the user has the required claim will he be able to access the action
methods of the PieManagementeController.

Creating a Custom Policy


So far, we've seen that we can create a policy which will then require that a claim
is present, or that it returns a certain value. So, in fact, the built-in, claims-
based authorization makes use of a requirement, a handler for that requirement, and
a pre-configured policy. This way we can use the RequireClaim, for example, so that
we specify, for example, that a claim is present for a given identity. Now it's
also possible to customize the system. We can create a custom policy and add one or
more requirements to that policy. This requirement is then a custom class, which
inherits from a base requirement. Let's take a look. Imagine that Bethany doesn't
want any trouble in her web shop. She doesn't want that children start ordering
pies. How can she do this? Well, we can create a minimum age to order requirement.
This will be a class that contains the data parameters that a policy can then use
to evaluate the current user. So in our case, this will become a class called
MinimumOrderAgeRequirement, which needs to implement the IAuthorizationRequirement
interface. This interface doesn't contain any methods, so we don't need to
implement anything. Next, we also need to create the authorization handler, which
will take care of the actual evaluation of the properties of the requirement. One
requirement can have multiple handlers. For our case, we'll define just a single
handler. The handler must inherit from the base AuthorizationHandler of T, where T
is then the requirement it is handling. In this class, as we'll see in the demo, we
will decide based on in our case if the user is old enough or not, whether he or
she can order a pie on Bethany's web shop. The handler that we have created to work
with the custom requirement can now be registered at the configuration of the
application. In the requirements for this policy, we will specify the newly created
requirement, passing in a value for the MininumOrderAge, and here that would be 18.

Demo: Creating a Custom Policy


Instead of talking about these custom policies and requirements, let's return to
the demo and see things in action. We will be looking at creating a custom
requirement and using this in a custom policy-based system to authorize certain
actions in our application. In this demo, we are going to work with a custom
policy, so that we can check for a custom claim value. So, I'm going to log in
again with that Demo user, and I'm going to create an order. I'm going to add a pie
to my cart, check out, enter some data here. When I now hit the Complete order
button, we will get an error saying that we do not have permissions for this
action. Now let's take a look at the code why this happens. ASP. NET comes with a
couple of built-in requirements, which we can use to check certain values, but it's
not always possible to go a step further. Whenever we want to start checking custom
claim values, the default requirements won't be able to handle that. It's possible
to extend the policy system with custom requirements, and a custom requirement is
basically a class that implements the IAuthorizationRequirement interface. And we
can also specify custom handlers, AuthorizationHandlers, I should say, which can
then be used to evaluate the requirements. So what I've done here is I've created a
custom requirement, which indeed implements the IAuthorizationRequirement. And my
requirement is the MininumOrderAgeRequirement, which, as the name implies, requires
that a user has a certain age before being able to place an order within Bethany's
Pie Shop. So the minimumOrderAge has an integer value called minimumOrderAge, and
it also inherits on the authorization handler, which is then the handler method for
the requirement. And in here, I'm going to check first if we have a claim of type
date of birth. If that is not the case, well, then we won't be able to check the
age of the user, so we will in any case deny being able to place an order. So I'm
returning Task. CompletedTask. If the claim, however, is available, I'm going to
check for the value of the date of birth, I'm going to calculate the age of the
user in years, and if that is larger than the mininumOrderAge, then I'm going to
return success using context. Succeed on this requirement. That's not just a
requirement, we also need to use it. Let's go to the Startup class, and now I've
added a new policy here, the MinimumOrderAge policy. And to this policy, I'm adding
a new requirement, being the new MinimumOrderAgeRequirement, and I'm specifying
that 18 should be my minimum order age. Now when this policy is now applied on a
given action method, the requirement or requirements that we specify will be
checked. And I'm doing that in my OrderController. So in the OrderController, I've
specified a new authorization policy here on the Checkout method, which has the
MinimumOrderAge set. So whenever the user wants to place an order and the Checkout
action method is invoked, the MinimumOrderAge requirement will be checked. And at
that point, we're going to check if the user has indeed that specific claim, and
secondly, if the user is old enough to place an order, so in this case, older than
18 years.

Adding Third-party Authentication


Bethany wants to optimize things around authentication and authorization in her web
application, and she's right about doing so. She has returned to our office once
again with another question. She has some complaints from users who are asking her
why they have to create an account on her website, which requires them to remember
yet another password. I think it's something we can all relate to. So now Bethany's
asking us if it would be possible to allow users to reuse their existing Google or
Facebook account on her website to authenticate. This way they can reuse their
credentials, and it will also relieve us from having to store sensitive user
information, such as the username and the password in our own database. Again, good
news for Bethany, as well as for us. ASP. NET Identity has the ability to do this
on board. As the last part of this module, let's add support for third-party
authentication in our site. I'm going to build in support to authenticate with my
Google credentials. Other third-party identity providers will work in a similar
way. Now before we take a look at how we can do this, let's take a step back to
explore this thing called third-party authentication. We've covered claims earlier
in this module, and we've seen that we can use ASP. NET Identity to validate claims
coming from an external source. Now, the claim can even be the identity of the
user. This way the user is authenticating with another third party, such as Google,
Facebook, Twitter, Microsoft, et cetera. These are trusted identity providers, and
we can assume that we are getting back from them a claim containing the identity of
the user. The user will be who he or she is claiming to be. Of course this approach
has several benefits. For end users, this relieves them from having to create yet
another account. They can use one of the accounts they already have to authenticate
to your site. For us as application developers, it relieves us from the burden of
having to store passwords in our application. That is now the responsibility of the
external party. When the user has successfully logged on with the external system,
we can be sure of the identity of the user. You're also now getting more advanced
things that require quite some work to enable in your own site, such as two-factor
authentication. This is a consequence for us as application developers for not
being required anymore for having to write actual authentication codes. And
finally, ASP. NET Core comes with support built-in for the most commonly used
third-party providers. It's really not a lot of work to get this to work in your
application, as you'll see in the slides and the demo. In the example, I'm going to
show you how you can add support for Google for authentication. As mentioned, other
providers are supported as well, but we'll limit ourselves to just adding support
for Google. The first step is adding the correct package to support all this. In
this case, we're going to need to add a reference to the Microsoft, ASP. NET Core.
Authentication. Google package in the csproj file. Next, as always, we'll need to
configure the application to use the Google authentication middleware. When we do
this, we'll need to pass some parameters, such as the ClientId and the
ClientSecret. You will get these when you register your application with Google,
and I'll show you how you can do this in the upcoming demo. Now with this
configured, we should now be able to write code that basically will redirect a user
during the authentication flow to Google and back. Here's the flow that will
typically follow. We'll have the ability from our application to redirect to
Google. There the user will log in using his or her Google credentials, including
the password. Upon successful authentication with Google, a callback will get done,
invoking code again, now from Google in our application. Google will pass the
required information, such as the username, to our application. At this point, we
can now be sure that the user is who he or she is claiming to be. Based on this
information, the authentication is finished, and we can use this now to continue
with the authorization part, which is not covered by all this, by the way. Now one
more thing before we go to the demo. Working with a third-party identity provider
such as Google does require that our application runs using SSL. In Visual Studio,
it's easy to enable this. Go to the project properties, and under the Debug tab
simply check the Enable SSL checkbox, which will use a self-signed certificate to
enable the use of SSL during debug of the application.

Demo: Adding Third-party Authentication


For the last time in this module, let's return to our application and take a look
at how we can enable Google authentication in our application. In this demo, I'm
going to show you how I'm using third-party login providers; in this case, they're
going to work with Google. So I'm going to go to my login page once more, and now
notice that it is possible to use another service to log in to my application. So I
click on the Google button here, and now I'm redirected to Bethany's Pie Shop, and
I'm already logged in. So what effect of it has happened is that I am now logged in
to Bethany's Pie Shop using my Gmail account. The user did not have to create a new
user account on Bethany's Pie Shop, and we as developers also don't need to worry
about storing these credentials. Let's take a look at how I've done that. First, as
mentioned in the slides, for this to work, we need to work with HTTPS, so SSL needs
to be enabled. You of course can work with a self-signed certificate for the
purpose of this demo, but do make sure that HTTPS is enabled. Now to integrate
Google's third-party authentication, first go to the link you see here on the page.
You will then be redirected to the sign in page for Google's Cloud Platform. Here
you can log in with your Google account, and your password, and optionally receive
an SMS code for two-step verification. When that's finished, you'll see the API
Manager Library, and to get started, we need to create a new project. So click on
Create here, and we're going to give the project a new name. For example, BethDemo.
Indicate that you've read all the required terms of service, and then click Create.
It'll take a couple of seconds before your new project has been created. Now you're
on the library page, and now you need to add the Google+ API. So search for Google+
API, click on it, and then click Enable. You now should get a warning that is
asking you to create credentials. In here, selecting the Google+ API, then select
web server, because you're going to use these front end web application, and also
indicate that you're going to work with user data. Next, click on the What
credentials do I need button. You can give the old client a name, or you can leave
it at default for now as well. Then we need to enter the authorized URIs that are
going to be redirecting to this page, which is the address of your local host,
including HTTPS, and append that with sign-in Google. So in my case, that will be
this localhost/signin-google. Of course, when you now deploy the site later on to a
live server, you would need to change this URI. Click on Create client ID next. Now
enter your email address and the name of the product shown to users. That is going
to be Bethany's Pie Shop, of course, and click on Continue. And now you can see the
credentials that you'll need. Click on download to save these credentials as a JSON
file locally, and now you can click on Done. I guess we're ready here. Now I've
opened the JSON file that I've downloaded, and notice in here we have the client id
and the client_secret. We'll need those in just a second. Now we're back in Visual
Studio, and the first thing I now need to do is add a NuGet package for supporting
Google authentication. So we can either do that by editing the csproj directly, and
notice that I've added here at the bottom a package reference to Microsoft.
AspNetCore. Authentication. Google. And it's currently at version 1. 1. 2.
Alternatively I could have used NuGet's interface directly, and searched here for
the AspNetCore. Authentication. Google package, which will also update the csproj
file. With support for the Google authentication added, let's now go to the Startup
class. And in here, I've added support for Google authentication. And I'm passing
the client id and the client secret I got from the JSON file. Notice that these are
different than what you just saw in the JSON file, because this is using a separate
registration that I've done beforehand. Now at this point, we've added support for
Google authentication, but we're not using it yet. So for that, let's go to the
Login. cshtml. Down here at the bottom, I've added this new div here, and
specifying that a user can also use another service to log in. First I'm going to
use the SignInManager if any external authentication schemes have been enabled. If
that is not the case, I'm showing that none are enabled. In our case, I've enabled
Google, of course. And I've added this link here, which is going to redirect me to
the GoogleLogin action method on my account controller. Let's take a look there
next. So here's the AccountController, and let's now go to the GoogleLogin action
method. As parameter I'm receiving here the return URL, which I'm going to use to
build up the link that Google can redirect me to after successful login. So I'm
using the URL action here to build up the URL correctly. We'll see later in this
course how URL action is used in more detail, but for now, we remember that this
will basically build up a URL to an action based on the values that I'm providing
it. The values in this case are the name of the action method, the name of the
controller, and any parameters that I want to pass along. Then I'm using the sign
in manager again, and I'm asking it to configure the GoogleProvider using that
redirectUrl that I've just created. Finally I'm going to return a challenge result.
A Challenge result is an IAction result, and it's going to post to the
ExternalProvider. So at that point, the user will be redirected to Google. The user
can then sign in there, and when Google is ready, this GoogleLoginCallback method
will be invoked, because, of course, it was part of the redirectUrl that I just
created. If there was an error, the user will be redirected to the login view. If
no error was encountered, then we're going to use the signInManager again to ask
for the external login information. At this point, we can get access to information
being passed from Google to our application. If no information was retrieved, well,
then we can basically continue, and we're going to redirect the user again to the
login action. If it did get some information, well, then we're going to ask the
signInManager to sign the user in using the external login information. If it was
successful, that means that the user was already in the system, so we're going to
redirect to the homepage. If not, well, that means that the user wasn't known in
our system yet, so we need to create a new user. And I'm going to create a new
application user that's our own custom user class again, remember from earlier in
this module. I'm going to ask the external login info for the ClaimsPrincipal that
is associated with this login, and I'm going to search for the first claim with
type email, and then I'm going to use in my application as email, as well as
username. I'm going to ask the user manager to create a user then. If that doesn't
succeed, well, that means that we have an AccessDenied. If that succeeds, well,
then we are going to log in the user and then finally sign in at user and redirect
again to the home view. And at this point, we've now successfully added an external
provider to our application, making it possible for users to reuse an already
existing account now in Bethany's Pie Shop.

Summary
Whew! That was a long module! But I hope you now feel more comfortable when you
need to add Identity-related features to your own ASP. NET Core application. You've
seen that ASP. NET Identity offers quite a long list of options. It has built-in
support for working with roles, and can combine this with claims. These claims can
then be used as well in combination with a third-party Identity provider to allow
the user to authenticate using, for example, Google instead of our own application.
I hope you enjoyed this thorough discussion of ASP. NET Identity. In the next
module, well, we will basically continue a bit in the same area, but we will focus
more on how ASP. NET Core will protect us from attacks from the outside. I hope to
see you there as well, and thank you for watching this module.

Hardening Your Site Against Attacks


Module Introduction
Hello there, and welcome to this module on Hardening Our Site Against Attacks, part
of this course on Building an ASP. NET Core Enterprise Application. I'm Gill
Cleeren, and I'm excited to see that you're joining me for yet another module. Now
in the previous module, we have covered a lot in regards to allowing the user to
authenticate and to authorize in our application. Those features are, of course,
related to security. However, there's much more to securing our application than
just requesting that the user will be using a strong password, although that is
definitely important. Now in this module, I'm going to discuss which measures we as
developers can take to make sure that we don't open the application for some of the
most commonly used types of attacks. So by the end of the module, you'll know how
to secure your ASP. NET Core MVC application. As said, it's all about securing our
site in this module. By no means will this module, or an extent, this course, try
to give you all the measures that you should take against all kinds of attacks that
might happen once your site is live. Instead, what I'm focusing on are two very
common types of attacks that we often become a victim of, and for which the
solution has changed quite a lot with the introduction of ASP. NET Core. So first,
I'm going to explain about sanitizing input in order not to get caught by the XSS
attack, or cross-site scripting attack. Well, as we have seen how we can do that,
we're going to learn how we can also counter CSRF attack, so a cross-site request
forgery attack.

Sanitizing Input
So the other day, Bethany came to our office again. She wants to expand her site
with yet another very cool new feature allowing users to leave a review for a pie
that they have previously purchased via the site. That's a great idea, and it will
definitely help people find the right pie for the right occasion. Now from a sales
point of view, I would definitely go for it. However, from a developer's
perspective, there are some alerts that go off in my head when I hear a customer
ask about this particular feature. Although I thoroughly believe that we should add
this feature for Bethany, is does require some careful thinking and planning about
how we are going to add it. The main reason is that this way we are letting a lot
of data come into our system. Not only that, but in the case that we will be
displaying other user's reviews, the data will also be displayed in other people's
browsers, and that's exactly where things can go wrong. When we are accepting any
time of input in our application, be it entering address information, uploading an
image, or writing a review, the data will enter our system. Before we do anything
with that input, we should definitely clean it, so that any possible harmful
content is removed. This is often referred to as sanitizing input. Let's take a
look at this in some detail before we look at how we can secure our site this way
in the next demo. I've given you a brief intro about the problem already, but let's
dig in in some more detail. Let's take as example the review option that Bethany
has requested for her site, so we have as visitor of the site perhaps a detail page
of a pie and the ability to write the review on there. So there's an HTML input
field. We get into some text there for the review. Now in the end, the data that
was entered by the user will be stored in the database. Next, another visitor goes
to the same pie detail page, and the application will show all reviews of that pie.
All seems good at this point. The user has entered a review and a second user will
be able to read that review. We're all happy at this point. Now in a perfect world,
nothing ever goes wrong, but sadly, there's no such thing as a perfect world, and
so Bethany's Pie Shop can become the victim of an individual who has other
intentions with her site. Since we have allowed people to enter a review in the
form, a hacker has the ability to enter code, typically a script in the review
form. This data will also be stored in the database, of course, and when another
review now visits the same pie detail page again, this malicious review, so
including perhaps JavaScript code, will be executed in his or her browser as well.
Now when the affected user loads the page, the script will then execute, and this
opens a lot of options for the attacker, such as stealing cookies, redirecting to
another perhaps fake login page, and much more. Now in the end, the affected user
doesn't know what happens, and will effectively blame Bethany's Pie Shop for any
caused misery. It's not Bethany's site that actually caused the misery, but
indirectly it actually was. Why? Because the developers of the site didn't check
the input for malicious input. The input wasn't cleaned, it wasn't sanitized, and
thus the hacker had all the freedom to execute whatever code he wanted to execute
on the victim's machine. This type of attack is very common and it's called XSS, or
in full, cross-site scripting. XSS basically allows an attacker to inject malicious
code into a page, which will then be executed by another user which is visiting the
page. This type of attack is possible because a developer of the page hasn't spent
time sanitizing the input before storing it in the data store. It all comes down to
what I've just said. The input that's entered by users is untrusted. All input
should be seen as untrusted, and should therefore be cleaned before it's stored in
the database of the application. If you want to tackle this problem easily, you
should start at the root of the problem. The data entered in our case in the review
input field should be sanitized before going any further in the system, so before
it will be stored in the database or before it is shown anywhere in the site. And
that will definitely solve the issue. Now which data is untrusted then? Well, in
fact, all HTML input should be seen as a possible source of malicious code. Of
course, an HTML input is a standard way to enter data into an application. But
there are other sources possible as well, such as HTTP headers that we pass in a
page, query strings, which are passed in the code, and much more. When we are
uploading an image and we are passing the attributes, such as the EXIF information,
we should see this information as untrusted. It's possible that an attacker
includes malicious code in all these types of input, and when we use this input in
our system, in an untrusted way, it can cause harm to the application and its
users. So what can we then do in ASP. NET Core to prevent XSS from happening in our
application? HTML encoding is the first measure we can take. If we want to display
untrusted data, so data that is somewhere in the system entered by users inside an
HTML element, for example, we'll want to HTML encode it. The net result of this is
that characters which have a special meaning in HTML will be encoded, taking away
the option for them to cause the execution of code. For example, the greater than
symbol will be replaced by >. This has no special meaning in HTML, and can't
trigger the execution of code. HTML encoding should not only be done when simply
displaying a value, but also when placing untrusted data in an HTML attribute. Also
when we use untrusted data in JavaScript, we should apply the same principles.
Here, too, the data should be encoded. The good news is that Razor is doing
automatic HTML encoding already for us, unless we will disable it explicitly. More
on that in just a minute. Another way to fight XSS from happening is applying a
regular expression when accepting the input. Using a regex, we can check if the
user is trying to enter malicious code or malicious characters into the system. We
can, for example, check the presence of the greater than or the less than
characters, and when we find any of these, we should block the system from
accepting that input. Both options are possible with ASP. NET Core, and we'll soon
see how we can practically apply these in code. Now in previous versions of ASP.
NET, we could use a library called the anti-XSS library, a library from Microsoft
which had on board several ways to sanitize input. Now this library isn't available
for use within an ASP. NET Core application, sadly. At the time of the creation of
this course, Microsoft hasn't announced any plans to support this library for the
new version of ASP. NET, so ASP. NET Core. Finally, request validation. That was a
feature which has been in ASP. NET for a long time. Using request validation, ASP.
NET itself would check the incoming data, for example, entered in an HTML input.
Using request validation, ASP. NET itself will check the incoming data, for
example, entered in an HTML input, for potential threats, such as again the
presence of certain characters. When these were detected, an error was thrown, and
the input was blocked from entering the system. While it would be possible for
Microsoft to create this as a middleware component that we could then add to the
execution pipeline, Microsoft has recently announced that it will not bring this
into ASP. NET Core. This results in the fact that we as developers will have to do
more of the work ourselves. On the other hand, we now have full control, and that
opens doors as well. As mentioned, ASP. NET Core's Razor engine will already take
away a lot of the burden for us. Take a look at the code here on the slide. Assume
that we have a string which contains characters such as the greater than and the
less than. If we were to display this content, the output would be HTML coded, as
you can see at the bottom of the slide here. In most cases, Razor will
automatically perform the encoding for us as soon as we start using the @ symbol.
Although Razor will protect us, there are definitely cases where we'll need to
perform the encoding from the controller code ourselves. ASP. NET comes with three
built-in encoders that we can use to perform the encoding, namely the HtmlEncoder,
the JavaScriptEncoder, and the UrlEncoder. We'll see in the upcoming demo how we
can use these. Now these encoders, just like pretty much everything in ASP. NET
Core, are accessible via the dependency injection system. Here in the code snippet
you can see on the slide, we're looking at a sample controller where we will be
needing access to the HtmlEncoder. As you can see, we aren't instantiating the
HtmlEncoder ourselves. We can simply ask dependency injection system to pass us an
instance using constructor injection.

Demo: Preventing XSS with ASP.NET Core MVC


Now let's make things practical. In the next demo, we are going to grant Bethany
her wish to add the possibility to add reviews to the site. I'm going to make sure
that the site isn't subject to hackers who wish to exploit a cross-site scripting
vulnerability. Let's take a look. In this demo, I'm going to show you how you can
avoid being hit by a cross-site scripting attack. So we are now in the detail page
for a pie, and Bethany has asked us to allow users to be able to enter reviews for
the pies. So we have added this as a list of reviews, which will be shown, as well
as the ability for the user to enter a review in this input text here. So I'm going
to enter a review, What an awesome pie! Send that review, and we'll be shown at the
bottom of the list of reviews. Now when we allow external data to come into our
system, we should be careful, because it might be so that an attacker is trying to
inject malicious code into this page. When we now, for example, paste in some
JavaScript code, which is simply going to show an alert, and are now sent to
review, things may go wrong. Let's try. I'm going to hit the Send review button,
Chrome is going to give an error, but when I reload the page, you'll see that alert
popping up, and the attack was successful. Now this code wasn't really harmful, but
I could easily have used a script that redirects the user to a different page or
sends the cookies to somewhere else. Let's see how I've done that. Well, actually,
I haven't been doing a good job. Now let's take a look at the database first. So as
we can see, I have indeed directly been able to insert the script into the
database. Now this is because I haven't been doing a good job in the details view.
I've used the Html. Raw HtmlHelper, which will one-on-one directly display the
value as it was given to it. In this case, including the script, as well as the
Html characters. Now typically using the Html. Raw HtmlHelper is not a good idea.
Razor does automatic HTML encoding, so let's try that. So I'm going to comment this
one out. And so now I'm going to simply display the review value in the list. Save
that, go back to the demo, and let's reload that page, and now we see that indeed
the script code is still being shown, but it is showing as plain text. The alert
didn't show. If we take a look at the source code, you'll notice that the review
including the scripts tag was correctly HTML encoded. And that's exactly what we
want to happen. If I now try to enter that script again, send it, nothing happens.
Exactly the same thing. But if I look again at the database, we indeed see that it
is still possible for users to insert scripts in our code. Now it's not a good idea
to still allow people to inject HTML into your database, because it might very well
be that on a different page you're using this without Razor, thus opening the doors
on another page. So, what we should actually be doing is HTML encoding the values
before they go into the database. So I'm now in the PieController and in the
Details action method. I'm now simply adding the pie review, just as it was entered
by the user. But let's remove that, and let's replace it with this code here. So
what I'm now going to do is I'm going to HTML encode the review and store that one
in the database instead. Let's run that again. And if we now go to the detail page
of the pie again, we try to enter another script, you'll now notice that the values
which are going to be displayed are these HTML encoded characters here. If you now
take another look at the database, you'll notice that the value that is being
stored here is also the HTML encoded version. So this way we are safe, making sure
that nowhere are we going to be storing still that script code. Now the HtmlEncoder
that I used here is declared here at the top, and it's being injected into my
controller using a dependency injection system from ASP. NET MVC.

Preventing CSRF
We've now solved the danger for cross-site scripting in our application. Although
we have solved a very common attack, we're far from finished. In the second part of
this module, we're going to look into a very common attack that is often used on
websites, namely, the CSRF, or the cross-site request forgery attack. Of course,
we'll also prevent this attack from happening, as well as discuss which measures
ASP. NET Core has on board. If you've never heard of the concept of a CSRF attack,
it's definitely useful to start by taking a look at how OWASP defines this attack.
OWASP is a not for profit organization, which maintains a very large site regarding
security on the web, and you can find it at OWASP. org. What you're looking at here
is the definition of a CSRF attack as given by OWASP. Basically, CSRF is an attack
on a site that will force or trick the end user to execute an unwanted action on a
site or application in which they are currently authenticated. So if you think
about it, it comes down to tricking the user into executing an action that he or
she didn't want to do on a site where they have already been logged into. OWASP
continues to say that CSRF is typically a state-changing request, since it's not
possible for the attacker to get access to the response. This all may be still a
bit abstract, so let me explain things with an example. Bethany has again returned
to our office with another new feature request. She's come up with the idea to add
some type of "Send a pie" feature to her site, and using this feature, a logged in
user gets the ability to send a pie to a friend. For this friend, only the address
data will need to be entered in the site. The already linked payment information
for the logged in user will be used automatically, so this should actually be a
simple thing to build. However, if you don't watch out as developers of this
feature, it's very well possible that we expose a CSRF vulnerability this way. This
feature will probably again be a simple form. On the form, it must be possible to
select the pie, and then enter the address for the friend we want to send the pie
to. If you look at this, this is a very simple thing to build. Remember, and this
is very important, the user using the feature in the site is already logged into
the site. The user therefore has a cookie on his or her machine that keeps the user
logged in, and this cookie will travel along with every request that is made. The
form then sends some data to the back-end using a POST request. All is good. The
pie will be sent to the requested address. Now this thing here is actually open to
a CSRF attack. Imagine a hacker which is hungry for pie, actually, free pie. He can
easily detect on Bethany's Pie Shop how this form works, and which request it is
actually building. What he can do now is try to trick a logged in user to execute
the same request, but now with his own address as the data to send the pie to. He
can trick the user, for example, by placing this request, this URL basically, on
social media, and hoping that someone who's already logged into Bethany's Pie Shop
will click the link. If that happens, well, then the request will be sent, the
cookie is sent along, and the server doesn't know that this request is actually
forged. It's fake. The only one who will know is the tricked user, who will have to
pay for the pie that in the end ends up at the doorstep of the hacker. Although
this example might seem a little bit playful, with the hacker trying to get free
pie, imagine that this would be a banking website, where money transfers happen in
the same way. That would, of course, be even more painful. You may be asking, now,
how is this possible? Well, CSRF has a couple of pre-requisites that it needs in
order to succeed. First, the victim needs to be logged into the site. Now
typically, we all remain logged into a site for a long time due to an authorization
cookie. Now, when the attacker sends a forged request, and the browser basically
doesn't know that this request is malicious, in this context, the browser is often
referred to as the confused deputy. It's enabling the malicious request, but it
doesn't know that it's helping. It's confused. Now the second ingredient for CSRF
is social engineering. It's one thing to build up the request; it's another to get
the user to click on that link. In this context, social media or email are often
used to try to trick the user into clicking a link, which behind the scenes will
then try to send the forged request. The user may not even see anything from
happening. Alternatively, and this is even more scary, CSRF is sometimes executed
in combination with XSS where the hacker will inject a script into a page, which
then forces the browser to execute the forged request. Although the payload from
CSRF is often a lot of misery, it is as you can see, not that difficult to set up
for a hacker. How can we solve this danger from CSRF then? Well, the OWASP
organization has a guide called the Cheat Sheets, which give you a number of
solutions for a threat. The one specific for CSRF is available on the link that you
see here on the slide. Now according to this cheat sheet, there are a number of
things that we as developers should do to solve CSRF in our application. First, a
header validation. This solution basically comes down to validating the HTTP
request headers. Headers, of course, can be spoofed, but in the case of CSRF, is
the victim's browser, which is sending the request, which cannot be changed by the
hacker, unless it's combined with XSS. So although it helps, is not a guarantee.
Secondly, we should use the synchronized token pattern. In this case, a random
string is sent back from the server. The client then needs to send back that same
string to the server with the next request. Only if this value is sent back to the
server will the action be executed. The ID here is that this value is not
accessible for the attacker, thus making CSRF impossible. Finally, the cheat sheet
also mentions the double submit cookie. It's pretty similar, although it uses a
random string. In this case, a value is sent back to the client both in the cookie
and a request parameter. Now, when a request is sent to the server, these values
are compared on the server, and only once successful will the action be executed.
Now that we know how we can theoretically prevent a CSRF attack, let's see how ASP.
NET Core can help us solving this problem. ASP. NET Core has the ability to apply
the synchronized token pattern we've just discussed in the form of an attribute
called the antiforgery token. Let's take a look. Upon first time requesting the
page, a unique token is sent back to the client, which is associated with the
user's identity. When the user now wants to place an order in our case, the request
is made, and the token is sent back to the server. The server will then validate
that the token is present and also matches the identity. If that is the case, the
request is allowed. Now if an attacker is trying to trick the user by forging a
request, the request will still be sent. However, the token is unknown to the
hacker, so his request will be sent without a token, or perhaps with an invalid
token. The server will now reject the request. ASP. NET Core comes with this
mechanism built in, known as the antiforgery token. Typically when we want to add
extra functionality to our ASP. NET Core site, we need to add another package.
Well, for a change, this isn't really necessary when we want to add support for
antiforgery in an ASP. NET Core application. Antiforgery is available in a separate
package, Microsoft. AspNetCore. Antiforgery, but this package doesn't require any
manual registration; it is already registered for us, and thus available via the
dependency injection system. It is, however, possible, to add extra configuration
to its behavior in the Startup class. Antiforgery is available to us mostly in the
form of an action filter that we can apply on an action method, on a controller, or
even on the entire application. Applying this token to an item basically means that
ASP. NET Core will perform the check that the request is valid. It should contain
the token and the token should also be valid. Otherwise, ASP. NET Core will
automatically block the request for us. If we have a large application, we
typically will want to protect all POST requests in order to be sure that CSRF
isn't possible in our application. This may for a large application result in a lot
of places where we need to apply this attribute. It's possible to use the
AutoValidateAntiforgeryToken, which will protect all Post requests by default. It
won't apply for safe requests, such as Get or Options, by the way. Finally, the
IgnoreAntiforgeryToken will remove the need to validate on a certain action.
Imagine that you have applied the ValidateAntiforgeryToken on a controller. In this
case, the IgnoreAntiforgeryToken can be used to skip validation on one or more
action methods within the controller. In ASP. NET when a form is generated, MVC
will generate the antiforgery tokens. This is the default when we use the new tag
helpers in ASP. NET Core. If you have been using ASP. NET MVC before, you will
probably remember that you had to manually add the HTML helper antiforgery token.
That's not the case anymore when we use tag helpers. This will result in the
generated code containing an extra input with the name _RequestVerificationToken.
This field will then be used by ASP. NET Core to validate that the request is made
by its user identified by the session. And if that's not the case, the request will
be rejected. In the case that this request was forged by an attacker, this value is
unknown to the attacker, and he therefore is blocked from creating a fake request.

Demo: Protecting the Site Against CSRF Attacks


Let's now return to the application and learn how we can protect our site against a
CSRF attack from happening using the tools handed to us by ASP. NET Core. In the
final demo of this module, I'm going to show you how we can secure our site against
a cross-site request forgery attack. Now, Bethany has asked us to create the Send a
pie feature in her site. Using the Send a pie feature, it's possible to send, as a
logged in user, a pie to someone else by just entering the name and the address,
and the bill will automatically be sent to the logged in user. How great is that?
So I'm going to use this to send a pie to my friend John, who lives in London. So
when I click on this button, the pie will automatically be sent to John, and I will
be billed for it. That's great. Now, let's take a look at that once more. I'm going
to click on Send gift now again, and then we'll take a look at the request in
Fiddler. So here is that request that we've just executed, so we're doing a POST to
PieGift, and we're passing name and address along with the request. Now as we can
see, it's not difficult to recreate this request, and so it is possible for a
hacker to recreate this request and trick us into clicking on a button to execute
that request again, and that's basically what CSRF is all about. So when I show you
how this is done, I have another site here, and in this case, I'm going to be the
hacker, and I've recreated the Bethany's site a little bit with the logo and the
same background, and I've posted something on Twitter to trick people into thinking
that they're going to get a pie for free via Bethany's Pie Shop. I get them to go
to this page, and here they simply have to click a button for free pie. They click
on it, and so they're now redirected to Bethany's Pie Shop, so the original URL,
and they see that they have place an order, not knowing, in this case, that they
have actually sent a pie for free to the hacker. Now how has that happened? Let's
take a look at the code for the other side in this case. So here is that HTML page
that you just saw, and in here as a hacker, I'm trying to recreate that same
request, so I'm posting to the same site, so doing a post request to PieGift, and
in this case, I've added my own name and my own address. People clicking on this
link don't really know what happened. They're clicking on the link and then being
redirected to Bethany's Pie Shop, who sees this as a valid order, and so they will
send the pie, but they will bill it to the original logged in user. So the page on
Bethany's Pie Shop at this point is vulnerable, it's open for CSRF attacks. Now we
need to fix that. So I'm now back here in Visual Studio, and I now need to protect
the site against CSRF attacks. What I can do is enabling the antiforgery token
validation. In this case, for starters, we are going to add the
ValidateAntiforgeryToken attribute on the send a pie page, so that is on the Index
action method of the PieGiftController in this case. Let's run the application
again, and for us as a regular user of the site, nothing has really changed, I can
still send a pie to John in London. Now, for the attacker, however, things have
changed. Let's try getting some more free pie here by clicking on this button here,
and now as you can see, the original site, so Bethany's Pie Shop itself, has
rejected this request. Now why is that? Well, let's take another look at the
original site. If we go and take a look at the source, we will see here that
automatically with the form, an input of type hidden has been included with the
name _RequestVerificationToken, and that's a unique token that is going to be sent
along with the form submission. Now, also what's happened is that a cookie was
generated, and if we go and take a look at the included cookies, we indeed see that
an antiforgery token cookie has been included. Now these are automatically
generated by ASP. NET Core whenever we start using a form. However, only when we
enable the ValidateAntiforgeryToken in our code, so like I did here on the Index
action method, will ASP. NET Core validate that these values are what they should
be. It will actually validate the value of the request verification token and the
cookie and see that they are equal. Now you may be thinking, can't the hacker then
just include both the hidden input, as well as the cookie? But it could include
both these values, but he doesn't have access to the actual values which are
expected, because they are only exchanged between the browser and the server, and
the hacker does not have access to that. So, as soon as these values are not coming
along with the request, the request will be blocked by ASP. NET Core. Now let's
take a look in the code what I actually need to do to work with the antiforgery
token. Now, I've already shown you this one here, the ValidateAntiForgeryToken can
actually be used to protect an action method from a CSRF attack. When I add the
ValidateAntiForgeryToken, ASP. NET Core will perform the validation between the
value that is coming along with the hidden input and the cookie. Now when these
values aren't there or they aren't valid, the request through the Index action
method will be rejected. That's what we saw in the demo. In previous versions of
ASP. NET, we also have to use an HTML helper in the views for the antiforgery token
to be generated. If we take a look at the view for the PieGift, you'll notice that,
well, there's basically nothing being included here. Well, this is new for ASP. NET
Core. In ASP. NET Core, as soon as we have a form where we are using tag helpers,
automatically ASP. NET Core will generate the cookie, as well as the hidden input,
so the request verification token. It doesn't, however, validate them
automatically. For that, we need to include the ValidateAntiForgeryToken. We can
also work with antiforgery from the Startup class. For example, we can add the
AddAntiforgery services to our application and we can pass extra options using
these antiforgery options parameter here. What we also can do is enabling
antiforgery on an application level using something called a global filter. Now
we'll talk about filters later on, but here we already see an implementation of one
of the built-in filters, and the filter here that's being used is the
AutoValidateAntiforgeryTokenAttribute. This basically means that on all unsafe or
potential unsafe requests, such as a post and a put, antiforgery validation will be
included automatically. So that means that I don't need to include this attribute
anymore on individual methods. Now if there are methods where I do not for some
weird reason to have the antiforgery token check enabled, I can disable the check
using the IgnoreAntiforgeryToken, as you see here.

Summary
I think it's time to wrap up this module. We have seen how ASP. NET Core MVC can
protect our applications against two very common attacks that happen on a daily
basis against enterprise applications. We started this module by looking at what
XSS really is, and how we can solve it by sanitizing input. You've also seen that
quite a few things here have changed in comparison to regular MVC. In the second
part of this module, we've discussed another very common vulnerability, namely,
CSRF, and ASP. NET MVC tackles this risk by means of the AntiForgeryToken. Well,
that concludes this module. In the next module, we will shift gears a little bit
and we'll start looking at the different ways that we can validate complex models
sent to our application in ASP. NET Core. I want to thank you for watching this
module, and hope to see you in the next one. Thank you. Bye-bye for now!

Leveraging and Validating Complex Enterprise Data Models


Module Introduction
Hi there, and welcome to this Pluralsight course on Building an Enterprise
Application with ASP. NET Core MVC. My name is Gill Cleeren, and together we will
be learning in this module about Leveraging and Validating Complex Enterprise Data
Models. In many demos, most enterprise or line of business applications work with
data. I think that is rather obvious. In many demos that you'll typically come
across when you're learning about ASP. NET Core MVC, you will see a single string
being entered in your view, and that string then arrives on the controller site.
Now in real applications, things tend to get more complex typically. In this
module, I'll be showing you the various ways you can get complex data models from
the client to the controller, and also how to validate that the user has entered
valid data. I will kick off the module with a short overview what you will be
learning in this module. As mentioned, we'll learn about model binding. During this
part of the module, you'll see the many types and many ways of model binding, which
are supported by ASP. NET Core MVC. Secondly, we'll explore the options we can add
on top of the binding engine to perform validation to ensure that only valid data
will be entered in the persistence store.

Model Binding
Let's start this module as mentioned with a thorough explanation of the model
binding features which are available in ASP. NET Core MVC. Now, before we start
exploring the concepts of model binding, I want to make sure that you have an
understanding of what model binding really is. Through the concept of model
binding, data that is sent from the client to the server in an HTTP request will be
used to create. NET objects. These objects will then be used as parameters for the
action that we are invoking. It's through the process of model binding that these
objects are created automatically for us, and they are passed to the action methods
automatically as well. Basically, all data entered on the client is sent by the
browser in the request. But if you would have to search all places from where the
data can be sent to the server for every request, that would be a time-consuming
and tedious task that we as developers would have to do every single time, again
and again. A tedious task is abstracted away through the use of model binding.
Model binding comes with ASP. NET Core MVC, and it works with simple types, such as
strings or integers, complex types, and even arrays. For all of these, model
binding will do its utter best to create automatically the required objects. It's a
gift, basically, that comes in very handy. Now if you're still a bit unclear on the
process of model binding, let's take a look at the concept in a bit more detail.
Imagine that we're browsing to the detail page of a pie, which is accessible
through the URL, you can see here on the slide. The ID of the pie we want to look
at is 30. There's an action method on the controller called Details, which is
accepting an ID as parameter, and this is of type int. If you want to invoke this
action, we'll need to pass it a value for the id parameter. Now getting a value 30
into that parameter is done by model binding. It will provide the correct data for
these parameters that we require. In this case, the value is a simple type, but
we'll soon see that we can use much more complex types as well. Now the whole model
binding system is actually based on something called model binders. As the name
already implies, these binders will be objects responsible for providing the model
binding system with data from a particular part of the request. Model binding in
general will try to find data values it needs in several locations in the request.
It's actual the model binders that search the values, each in a specific part of
the request. By default, the model binding that comes with ASP. NET Core MVC comes
with binder with three types of values, form values, routing values, and query
string values. ASP. NET Core MVC will also use these three types in this sequence.
First, it will check in the form values. If it can't find the required value there,
it will continue to search in the route values. Only after that will it search in
the query string values. Now that we know how model binding works behind the
scenes, let's take a look at what types of data we can bind, and well, let's start
with simple types. I've already shown you a simple example where we were passing
the value 30 here, which will be passed to the parameter of the action method. This
works as mentioned for simple types, such as numeric values, Boolean values,
strings, and even date values. So by default, ASP. NET Core MVC's model binding
system will create the corresponding object or objects that are required as
parameter for the action that we are invoking. Now you will need to pay some
attention here as well. Take a look at the following URL, where the value in the
URL is now set to ABC. Assume that there's a route that specifies this segment to
be the ID. In this case, of course, the cast will fail, and it actually won't find
a value for the id parameter, thus resulting in this value to be 0, so the default
value. Now this may incur a problem if the value 0 actually means something in your
application, and you need to differentiate between the value 0 and the default
value passed by the model binding system. If that is the case, it's best to
introduce a nullable parameter, which will then default to null, allowing you to
differentiate between the two, so between 0 and null. Now simple types are simple.
If we talk about simple types, it means that there must also be something more
complex as well. Well, indeed. Model binding is actually capable of much more than
just mapping an integer or string value. Assume, for example, that our Action
method is the EditPie action method, which is something you'll typically encounter
in our administration pages. This action method is expecting a pie instance. Model
binding will use reflection on the pie type to identify which properties it will
need to fill. Now once that is finished, it will start searching for the
corresponding values as it did before, so using the model binders again. So in the
format you can see on the slide here, we are, for example, passing a value for
Name. If the pie defines a property name, the model binding system will pass this
value to that property. This way all properties of the pie are given a value and
the object is thus created. Now you may be thinking, what if we're using
composition? So, for example, here we have an EditPie action method, but now it's
expecting a PieEditViewModel. The latter in turn wraps a pie instance, as you can
see here. How can model binding now know which properties it needs to use? It could
very well be that we have in our view model a pie and a customer, which both define
a name property. In this case, we will actually have to help the model binding
system a little bit. In the view code, notice that we now have specified Pie. Name,
which actually specifies that this field is for the Name property of the pie. The
model binding system comes with a number of attributes that we can use to influence
the binding system. The Bind attribute is the first one. It allows us to bind
properties selectively. I'll show this in the next slide with some more detail. The
BindNever attribute can be placed on a property of a model object to indicate that
this property should not get a value through model binding. And the BindRequired
attribute does exactly the opposite. When validating, it will actually cause an
error if no value can be found for a given property. Now model binding is also very
aggressive. It will try to bind everything it finds. Assume that you have an object
where I may not want to get the value for all properties of the type. Model binding
will still try to bind everything, unless I instructed not to do so, and I can do
this using the Bind attribute that we just saw. In the sample here, I can then
specify the property or properties I want to bind. Other properties are ignored.
Here you can see an example of the BindNever attribute. Using this attribute, we
can again on the type indicate that you will never allow model binding to get a
value for the given property. For example, we typically won't allow that the ID
property gets a new value from model binding, and so we can use the BindNever
attribute for this. The last thing before we go to the demo is binding a collection
or an array. Model binding supports binding request data to an array, which is
actually pretty cool. Take a look at this Razor code here, where we are binding to
a list of pies. We're then looping over the items in the array, so the individual
pies, and for each we're displaying a text input. When we submit the form, the
BulkEditPies method will be invoked. Now this method is accepting a list of pies as
its parameter. Model binding will again do all the hard work for us. It will
recreate the list for us, giving us access to the data entered by the user in this
view.

Demo: Binding Complex Types and Lists


Let's now go back to the demo application and we'll take a look at how data binding
works for both complex types, as well as for a list of objects. In this demo, I'm
going to show you complex type bindings, as well as bindings for lists. And we're
going to start with the complex types. I'm here in the Pie Management page for
where I can add, edit, or delete pies. Let's click on the Edit button here, and
this will take me to the edit pie page, and here I can change, for example, the
SugarLevel, the category, and click Update pie. We're now hitting a breakpoint here
on the controller, and as you can see, the EditPie action method is being passed a
pieEditViewModel. The pieEditViewModel contins as nested type the pie, it also
contains a list of categories, and a category ID. If we drill into the
pieEditViewModel, we can effectively see that CategoryId, as well as the fields of
the nested pie type, have been filled in, including the sugar level that we just
changed. And this is model binding doing its job. It will not only search on the
pieEditViewModel, but also in nested types. If you take a look at the Razor code,
notice that we have indicated to model binding that the PieId is to be found on the
pie type. Same goes for the name, the short description, and so on. I also noticed
that for the CategoryId, I haven't done that. This is why the pieEditViewModel also
has a value for the CategoryId at the root level. We'll let it continue now, and
now I'm going to make a small change here. So in the EditPie I'm going to change
this to Pie. CategoryId, let's try that again, make another change here, update the
pie, and now you'll notice that the CategoryId at the root level of that type
hasn't been filled in. I've indicated to model binding that I want the
PieEditViewModel. Pie. CategoryId to be filled in. I'm going to make another change
here. I'm going to comment out this code and I'm going to let this code execute.
Notice what I've now done. I've used the Bind attribute here specifying Pie. I
specified the pie as property of the PieEditViewModel being the property I want to
be filled in. I'm going to make another change in the EditPie again. I'm going to
remove this again as well. So typically CategoryId would now be filled in, but if
you run the application now, we'll see that is not the case. Let me show you. Let's
click on Edit again, and make another change, update the pie. And if you now drill
down into the PieEditViewModel, the CategoryId is effectively null. We've indicated
to model binding that only the pie type should be bound. Let us now take a look at
model binding for a list. I'm going to click on the Edit Pie names here, and this
will bring me to the quick edit page, where I can basically quickly change the name
of the pies in bulk. I'm going to make this into Apple Pie 1, and Cherry Pie 1.
Let's hit Update. And we're now here in the PieManagementControllers QuickEdit
action method, and here we are being passed a list of pie names, and you can
effectively see that apple pie has been renamed to Apple Pie 1, and the same goes
for cherry pie, which has now been renamed into Cherry Pie 1. So I'm getting in
these new names. Let's take a look at the view code for this. So this page is now
bound to an IList of strings. I'm going to loop over the list, and for each of the
items in the list, I'm going to display a label containing pie name with the ID,
and then the pie name in an input. And that is what I'm doing here. The ASP. NET
tag helper is bound to Model i, and Model i is of course a string, so I'm using an
indexer here on the list of strings that I'm using as the model for this view. I
went ahead and submit. Model binding will update the list of strings, and pass that
to my action method here in the controller with the correct values. So that was
just a list of strings, but we can also work with the individual items. So here
we're now displaying a list of pies. I'm going to show you the code in just a
second. So I can now also change the names here and click on submit again. We'll
hit another breakpoint, and notice that the action method is now expecting a list
of pies, and if we drill down in the list of pies, we'll notice that the names have
indeed been updated. So model binding not only works for a list of strings, but
also for a list of objects. If you take a look at the view code for this, we'll
notice that this view is bound to a list of pies indeed, and we are again looping
over that list, and I'm going to use an indexer, so model i here, and then we can
ask for the PieId, the name, and so on. And when we hit the Submit button, model
binding will search for all the pie instances again and pass them to our
PieManagementControllers BulkEdit action method.

Specifying the Binding Source


As we have already seen, model binding in ASP. NET Core MVC is by default searching
for data in a number of places, and it does this in a certain sequence. It may very
well be that we come across a situation that we want to specify that a certain
place should be searched that isn't going to search by default. Or that we want
ASP. NET Core MVC not to follow the default sequence. We can do this using one of
the attributes that we'll look at, which allow us to specify the binding source.
The FromBody attribute can be applied on a parameter to specify that a source for
the binding data should be to request body. This is quite commonly used in
combination with API controllers, by the way. The FromQuery attribute allows us to
indicate that value for the binding should be searched in the query string. The
FromHeader attribute does the same as the FromQuery attribute, but in this case, it
will search in the headers of the request. Another attribute is the FromRoute
attribute, which again does the same thing, but it will search the value based on
the routing system. And finally, the FromForm attribute will search in the form
data for the wanted data. Now how can we use these attributes then? Well, here you
can see a signature or a sample action inside of a controller. Assume that I want
to force ASP. NET Core to get the value for the pieId parameter to be coming from
the query string. I can do this by placing the FromQuery attribute before the pieId
parameter. And I'm doing something similar here with the Accept parameter. Here we
are using the FromHeader attribute to indicate that the value should be coming from
the header values. However, I'm not asking to search for a header with the name
Accept to the name of the parameter. I specified that the value for this parameter
is to be retrieved from the Accept-Language parameter.

Demo: Specifying the Binding Source


In the next demo, I'm going to show you how we can hook in the binding process by
using these attributes in action. The system of model binding uses a number of
model binders that will bind default and in sequence return values to the model
binding system. But if you want, we can also basically get a hook into the model
binding process and override where the values will be coming from. Let me show you
that in this demo. I'm going to click here on the Edit button, and I'm going to hit
a breakpoint. Notice that I've now added a couple of attributes that override where
model binding should be getting its value from. In this case, I've specified that
the pieId should be retrieved from the query, and the accept parameter should be
bound to the Accept-Language header using the FromHeader attribute. So both the
pieId and the accept parameter have now received a value. If we look at the query
string, pieId was indeed specified in the query string. Let's try something else.
I've now specified the FromRoute attribute, and let's run the application again.
Let's hit the Edit button once again. And now pieId is null; it's not being filled
in. Now because we have specified from route, we're actually searching in a route
value. And if we take a look at the defined routes, we'll notice that in the route
that is being followed, that would be this one, we don't have a pieId specified, we
have an id specified. That's, of course, why model binding cannot find a value for
pieId. This is how we can use the attribute to specify the binding source. In the
samples that you can download with this course, you'll find a couple of other
examples that you can use to play around with these attributes.

Validating Data
At this point, we've already covered a few options to make sure that model binding
is happening the way that we want it to happen. Although this way we have a nice
and easy way to get data from the client into our server-side code, what we haven't
covered yet is the ability to validate that the data that we are retrieving is
actually valid. And so Bethany has returned again to our office. She's asking us as
the developers of the application if it's somehow possible that we prevent her
users from entering invalid data into the system. Of course, Bethany. We'll show
you how we can fix that for you, we said. Now that we've made a promise to Bethany,
let's dive into the validation options we're getting with ASP. NET Core, to
validate the data that's coming from the client. We're going to start by looking
how we can make sure that the received data can bind to the model, and secondly,
we're going to make sure that we can help the user with correcting the problem.
ASP. NET Core already has some options on board, but we can extend on these to give
an even better experience. Let's take a look. The basic validation options were
already covered in the introduction course. But for completeness, let's take a
quick look and then we'll look at the advanced options in ASP. NET Core MVC. In
this snippet you can see here on the slide we can see an action method called
AddPie. It's expecting a view model, and this is of a class named PieEditViewModel,
which will typically be created by model binding as we've seen in the previous part
of this module. Model binding has done its very best to give a value to all
properties, including nested types, and thus the PieEditViewModel should be ready
for us. However, this has not done any validation yet. We have control over how
this is done. First, we can do validation manually, and that's basically what I'm
doing here in this snippet. For example, I'm going to check that the user hasn't
entered any negative values for the price. If that is the case, then I'm adding an
error to the model state dictionary instance that I get via the model state
property of the controller. The model state dictionary is a dictionary that we can
use to check the state of the model. In this case, we're adding validation errors
to that dictionary. At the point we have done all our manual validation rules in
the controller, we can use the ModelState. IsValid property. This will return true
if there are no validation rules in error. In the snippet that we're looking at
here, I'm going to save the data using the repository, and then redirect the user
to the index action. If, however, something went wrong, we are showing the same
view again, and typically, this will then show what is wrong with the view. I'll
show you how to do that in just a second. Next in manually performing the
validation, we can also use validation attributes on our model properties. Again,
these were already covered in the introduction course, so I'm not going to spend
too much time on these here. ASP. NET Core MVC comes with the following properties
that we can apply on the model properties. The Required attribute allows us to
specify that the value needs to be defined for the property. The StringLength
attributes can be used to make sure that the entered string has a certain length.
The Range attribute is typically used for numeric values, and allows us to specify
that the value needs to fall within a certain range. The RegularExpression
attribute can be used to apply a regex on a property, and thus check if it has a
certain format. Finally, the DataType attribute allows us to specify that the input
needs to be in a certain format. They, however, are not real validation attributes;
they merely give a hint to the browser about the type that is expected. And it can
be set to phone, email, and URL. Here we can see an example of the attributes that
we can use on a model. I'm showing the Order class here, and a couple of
properties. Assume that we are allowing the user to place an order here. specifying
the FirstName property first, and we want to make sure that it's going to be
provided. For that reason, I have applied the Required attribute, and I'm also
adding an ErrorMessage that needs to be displayed when it is not provided. Also, we
want to make sure that the entered data isn't too long, so we're also applying the
StringLength attribute. For the phone number, I've also added another attribute
here, the DataType attribute, and it's set to phone number. It's, of course, of no
use if we are performing validation in the code, and we're not alerting the user
about the fact that something is wrong. For that very reason, we can add a
validation summary to the view. There's a tag helper that comes with ASP. NET Core
MVC called the validation-summary tag helper, and it will detect the asp-
validation-summary attribute. When applied, it will show validation errors added by
the action. The value of the asp-validation-summary attribute can be set to ALL,
model only, or none. All will show all validation errors, model only will only show
the errors which are recorded on the model, so not the individual properties, and
none quite logically will disable the tag helper.

Demo: Model Validation


In the next demo, well, let's take a look at validation. I'm going to add first on
validation rules, and then we are going to show these to the users. In this demo,
we are going to take a look at some options that we have with validation of the
model. Let's first take a look at validation of the order. I am in my shopping cart
here, and when I click on the Check out now button, I go to the order page where I
can enter my details so that my order will arrive at my doorstep. When I click on
Complete order at this point, a post back will be done to the server, and so the
order will be passed along because of model binding, but you see that all the
values are null, or default value. And now at this point we're going to check if
the model says that it's valid. It is not, so it will be returned to the user, and
the user will see validation errors appearing onscreen. This happened because of
the fact that the order type has a couple of attributes set. Let's take a look at
type. So here's the order class, and as you can see it has quite a number of
validation attributes, such as required, the string length, and the regular
expression for the email. Because we just clicked on the Complete Order button with
any values specified, most of these gave an error. In the view, so the Checkout.
cshtml page, we're actually seeing these validation errors appearing at the top in
this validation summary, which is added using the asp-validation-summary tag
helper. I was also using the tag helper asp-validation-for on a span to display the
error message next to the input where necessary. This is basic validation. Now not
everything can be covered with attributes. And now here again in the pie management
part of the application, I want to create a new pie. And I've already prefilled
some values here, and notice the value of price, which is -12. Of course, a pie
with a negative price is not what we want, because then we would have to pay the
customer for buying this pie. That's not what we want. So, I could cover this also
with an attribute, or a range attribute would work here, saying that we can only
accept positive values, but like I said, not everything can be covered with
attributes. So I'm going to show you here how I can do manual validation. Let's
click on the Create pie button here, and now we're going to hit the breakpoint here
in the AddPie action method. And in here I have some manual validation rules. The
first one we'll say that if the price is negative, I'm going to add a model error
saying that the price should be higher than 0. I also have another business rule
here that says that if we specify a pie to be the pie of the week that it should be
in stock. If that is not the case, I'm going to give another error here. We now
step through this, the model error is indeed added. The second one has not been
violated. And now at this point we've added model errors, so the model state isn't
valid, and we returned the same view model to the view. And indeed we're now
getting the error message. So this was an example of a manual validation that
allows us to cover scenarios which we cannot cover with the built-in default
attributes.

Creating Custom Validation Attributes


So far, the attributes that we've looked at were pretty basic. They cover a number
of scenarios, but you'll quickly run into situations where you'll be doing a lot of
manual validation. That is, of course, not a real issue. However, if there are
cases where you're performing the same validations several times in several places
in your code, you're duplicating that, and that is not a good thing. If we have a
reusable block of validation code, it might be a good idea to create a custom
attribute, and that then contains a custom validation rule. So typically just to be
clear, you'll want to create this when you some validation logic that you think can
be reused multiple times across your application. Here we're looking at a part of a
custom validation attribute that we'll be creating in the next demo. A custom
validation attribute can be created by creating a class that implements the
IModelValidator interface. This is a very simple interface with just one method
called Validate. And in the implementation of this method, we will perform our
validation code. We are returning from this model an IEnumerable in
ModelValidationResult instances. This means that each instance in this IEnumerable
will contain a validation error.

Demo: Creating a Custom Validation Attribute


Let's go back to the application and we'll create a custom validation attribute in
our application. In the previous demo, we've seen that manual validation can
basically help us to cover scenarios where the default attributes can't help us
anymore. Now there are types of validation that we, however, can write once and
reuse across the application multiple times, or perhaps even across multiple
applications. In this sample, I'm going to show you how we can write a custom
validation attribute that we then can reuse across our site. So I'm here on the
page where I can create a new pie, and as you may notice, I've made small error
here for the ImageThumbnailUrl, so I've forgotten to make it a fully qualified URL.
Let's try creating this pie, and we'll hit a breakpoint, and if we now check, the
model is indeed not valid, so we will be returning to the same view that we're
getting in that same PieEditViewModel. Now we see what is wrong, we're getting a
validation error that is saying that is not a valid URL. See how I've done that in
a custom validation attribute? I've written a custom validation attribute called
the ValidUrlAttribute. And this attribute implements the IModelValidator interface,
which has one method, namely the validate method. And the name already gives away
what this will do. You can imagine that this will contain the actual validation
code. I'm getting in a context here, the model is actually the value that we are
validating. So in our case, that would be the incorrect URL. I'm then going to
check if this URL is indeed a well-formed URI. If that is the case, I'm going to
return an empty list of validation errors. If that is not the case, I'm going to
return a list containing the validation errors here. Notice that on my attribute
I've also specified a property called ErrorMessage here. So take a look at the pie,
and notice that here for ImageUrl and ImageThumbnailUrl, I've used the valid URL
attribute and I've also specified an error message, and that's the one that we saw
when we ran the page. So I've now captured my validation logic inside and
attribute, and I can then reuse across my application.

Client-side Validation
So far, the validation that we have seen all happens entirely on the server side.
This means that every time that the user has entered a value, we will need to send
off the data to the server for validation. Only after receiving the response will
the user know if the sent data was okay. Of course, in many occasions, the user
will be getting a better experience in the application if the validation can be
done on the client side, giving direct feedback to the user. This, of course, will
be based on the use of JavaScript, allowing us to perform validation before the
data goes off to the server. Let's take a look at how ASP. NET MVC supports this
out-of-the-box client-side validation. Of course, we can start writing JavaScript
code ourselves, which can then do validation on the client-side forest before the
data is sent to the server. That actually isn't necessary, since a very commonly
used package is available for this very purpose, which is called jquery-validation.
Now ASP. NET Core MVC supports something called unobtrusive validation. Basically
this means that ASP. NET Core will create on the server some HTML attributes, which
will then be interpreted by another library called jquery-validation-unobtrusive.
Because ASP. NET Core MVC includes these HTML attributes, it becomes possible for
this package to configure jquery-validation so that the correct client-side errors
are then generated for the users. Now to get started with this approach for client-
side validation, we need to first add a number of packages to our application.
Since these are client-side packages, they are managed by Bower. You can see in the
code here on the slide that jquery, jquery-validation, and jquery-validation-
unobtrusive have been added to the application. With the packages added to our
code, we now need to start using the code in these packages. To get started, on the
page where we want to perform client-side validation, we'll need to include a
number of scripts. We can see here in the code that I've added jquery, jquery-
validation, and jquery-validation-unobtrusive. Just a small tip, these files need
to be added exactly in this sequence for things to work correctly. Now with the
generated code that comes back from ASP. NET Core MVC, we will see that data-
attributes have been included. Now how did they arrive there? Well, this is thanks
to the tag helpers. The input tag helper that generated the input tag, in the
generated HTML, has noticed that we had specified one or more validation attributes
on the model, and has therefore generated the corresponding data-attributes, and on
the client, these will be picked up by jquery. validation. unobtrusive, resulting
in well-functioning client-side validation.

Demo: Validating on the Client


In the next demo, we are going to include support for client-side validation in our
application, giving the user a better user experience with the application, since
he or she will get direct feedback about possible validation errors in the model.
In this demo, we are going to take a look at how we can work with client-side
validation. And as always, I'm going to show you first the working sample, and then
we'll take a look at the code. So we are again in the shopping cart where I have
one pie in my shopping cart. I'm going to click on the Check out now button, and I
then arrive on this page where I need to enter my details. Imagine that I don't
feel like entering all of data, and I just hit the Complete order button. With the
validation that we had so far, we'd have posted back to the server, done the
validation there, and then get the same validation errors as we've seen now. But
you may have seen now that we didn't do a post to the server, and I can prove that
we haven't done a post, because there's a breakpoint here in the Checkout method,
and we didn't hit that breakpoint. So all the validation at this point was done
completely on the client side. Now how did this work then? Well, let's take a look
at the bower. json file, and we can see that some extra packages have been added
here. Namely jquery-validation and jquery-validation-unobtrusive. The versions that
you see here being used are the latest ones at the time of the creation of this
course. And let's take a look at the running application once more. And when we get
a generated source, we'll notice that ASP. NET Core has generated quite a few data-
val attributes. These are being generated because of the tag helpers in ASP. NET
Core. ASP. NET Core has noticed that we have specified validation attributes on our
properties, so it will automatically also generate these data-val attributes. And
these will then be picked up by jquery-unobtrusive to enable client-side
validation. If we go and take a look at the Views, Shared, Layout, we indeed can
see that I've added support for jquery. validate and jquery. validate. unobtrusive
in the layout, so it is automatically included in all pages that use this base
layout page. And that is why all the validation that I've specified here are
automatically also being translated to their client-side counterpart and does
enable client-side validation automatically for us.

Remote Validation
We've now seen the model that ASP. NET Core MVC uses, and we've seen how we can add
both server-side and client-side validation to our application. We've seen that
client-side validation gives the user a better experience, and we should aim to
include as much client-side validation to our applications as possible. This, of
course, will need to be combined with server-side validation since client-side
validation can always be disabled, it's just JavaScript. However, there are
situations where server-side validation is still required. For example, imagine
that you're building an application where the user can sign up with his or her
email. Of course, we can only validate on the server side if that email address is
already in use or not. It would be a horrible idea to send the list of all
registered email addressees to the client, so that the client-side code can then
check if the email address is already being used. However, it is still possible to
create a client-side experience in this case. ASP. NET Core MVC allows us to
perform something called remote validation. The name is already hinting at what
this will be doing. We will invoke a method on the server-side from client-side's
script, and this can be done using the Remote attribute. Let's take a look at an
example here. When we are building the administration pages for Bethany's Pie Shop,
we don't want two pies with the same name being added to the system. So we could
typically validate this in server-side code. However, we can add remote validation
here, so we can invoke server-side code from client-side code. Here we are going to
see the Remote attribute in action for this very purpose. We are asynchronously
going to invoke an action method called CheckIfPieNameAlreadyExists on the
PieManagement contoller. Also, we've included the error message that will need to
be shown if the validation fails. However, it is still possible to create a client-
side experience in this case. ASP. NET Core MVC allows us to perform something
called remote validation. The name is already hinting at what this will be doing.
We will invoke a method on the server side from client-side script, and this can be
done using the Remote attribute. Let's take a look at an example here where we are
building the administration pages for Bethany's Pie Shop, we don't want two pies
with the same name being added to the system. So we could typically validate this
is in server-side code. However, we can add remote validation here, so we can
invoke server-side code from client-side code. Here we are going to see the Remote
attribute in action for this very purpose. We are asynchronously going to invoke an
action method called CheckIfPieNameAlreadyExists on the PieManagement controller.
Also, we've included the error message that will need to be shown if the validation
fails. In this case, this will be if the entered name for the new pie already
exists in the system.

Demo: Using Remote Validation


In the last demo of this module, we are going to learn how we can add remote
validation in ASP. NET Core. In the final demo of this module, we are going to take
a look at remote validation. A remote validation will enable us to invoke custom
validation logic on the server side, but still give it a client-side feel, because
it will automatically be invoked for us. Let's take a look. I'm going to go to the
Add new pie page again, and I'm going to try adding a new pie with an already
existing name. Of course, this is server-side validation logic. We need to go to
the data store to figure out if that pie name already is in use. So typically this
would only be validated upon posting the page back to the server. Now, using remote
validation, I can invoke this dynamically from the client-side. So I'm going to try
adding a pie with the name Apple Pie, which already exists. And notice that as soon
as I tap out of that field, I will be going to my PieManagement controller, and I'm
invoking the CheckIfPieNameAlreadyExists method. In here, I'm going to use the Bind
attribute and search for the pie name and put that in the name value here. And the
name is then going to be validated with the repository to see if we can find a pie
with that name. If that is not the case, so the pie cannot be found, well, then I'm
going to return Json true, meaning that while this is okay, you can continue;
otherwise, I'm going to return an error message. I'm going to let this run now, and
now we see that on the page the validation error is automatically being shown.
Let's take a look at the remote validation in a bit more detail. I'm here on the
pie class, which was a type that we were binding to page 2. And I'm using here for
the name property the Remote attribute that receives a couple of parameters. The
first one is the name of the action method, that was the
CheckIfPieNameAlreadyExists method, and the second one is the name of the
controller, the PieManagement controller. I'm also capable of passing an error
message, in this case, that name already exists, that's the one that we saw
appearing on the screen. So the Remote attribute is the built-in attribute that
will invoke this method using client-side script on the specified controller. In
the controller we already saw that action method being invoked dynamically. I
typically return here Json result, since this is a call that will be invoked from
client-side. And that is basically how simple it is to invoke validation logic on
the server-side using the remote validation option in ASP. NET Core MVC.

Summary
And another module is finished. Congratulations! This module has taught us quite a
lot about how ASP. NET Core MVC handles the data for our application. We started
the module by exploring in a lot of detail how the binding engine works in ASP. NET
Core MVC. Without it, we would have to write a lot more code to find in the
incoming request the data that we need on the server-side. We've then continued to
the validation options that ASP. NET Core MVC has on board out of the box. We've
covered the manual validation options, the validation attributes, as well as how we
can display validation errors in the view using a validation summary. Finally, to
close the module, we've seen how a validation mechanism can be extended to the
development of a custom validation attribute. Now since this module was more about
what happens under the hood, we'll shift gears for the next module, and we'll
explore the many options that ASP. NET Core MVC offers us to build clean view code.
Thanks for watching.

Creating Clean and Maintainable View Code


Module Introduction
Hi there, and welcome to another module of the Building an Enterprise Application
with ASP. NET Core MVC course here on Pluralsight. My name was Gill Cleeren in the
previous module, and I've decided to keep it that way for this module as well. And
feel free to reach out to me with any questions you may have about this module via
the discussion board here on the Pluralsight website. Now, the focus for this
module is the view. We will be looking at quite some advanced topics that you'll
come across when you build a real live enterprise application with ASP. NET Core
MVC. Let's dive straight in. So as mentioned, we'll be spending time learning about
several things that have to do with the view of the application. And probably one
of the most interesting features that is new in terms of ASP. NET Core MVC is tag
helpers. Now I won't be spending a lot of time teaching you about the basics of tag
helpers; that was already covered in the introduction course. However, we will go a
lot deeper in the options that we have with tag helpers. We will start the module
by looking at some advanced built-in tag helpers. And after that, we'll go and
create some more advanced tag helpers ourselves. And this we'll be doing mostly in
demos. Next, we'll take a look at how we can create some asynchronous view
components, and we will finish the module by exploring how it can translate our
application into different languages, making it possible for the user of the
application to switch between UI languages.

Advanced Tag Helpers


We'll start the module as promised by exploring tag helpers in great detail. They
are my favorite feature in ASP. NET Core MVC, and certainly deserve quite some
attention. Now let's start the exploration with a brief overview of what tag
helpers are, and then we'll take a look at the advanced concepts around them. Tag
helpers allow us to enable C# server-side code to help actively participate in the
creation and the rendering of HTML elements in our Razor view code. Basically, they
are just a way of invoking C# code from the Razor view code, and the net result of
using them in your code is that HTML will be generated, so basically by the use of
C# code. They are thus a view feature. Tag helpers are new in ASP. NET Core MVC,
and they replace a well-known feature from previous versions of ASP. NET MVC called
HTML helpers. HTML helpers are still available in ASP. NET Core MVC, and even some
HTML helpers haven't been replaced by a tag helper. You can continue to use HTML
helpers, but there are quite a few reasons to make the jump into tag helpers. For
one, tag helpers are much more HTML-friendly. I'll show you a small example in a
second, but rest assured, the resulting HTML that we get from using tag helpers is
much cleaner. Also with tag helpers, we're getting good support from IntelliSense.
We'll see that live in action when we look at the demos in just a minute. ASP. NET
Core MVC comes with quite a number of built-in tag helpers, and we'll take a look
at some of the more advanced built-in tag helpers in this module first, and then
we'll continue to work with the creation of some more advanced tag helpers as well.
As mentioned, ASP. NET Core comes with quite a few tag helpers built in. Here we
see some of the basic tag helpers, which by the way, we have all used in the
creation of the basic version of Bethany's Pie Shop. So, in the introduction
course. If you need any help in working with these, feel free to take a look there.
This is definitely also not a complete list of tag helpers which are built in ASP.
NET Core, more are available. Now the closest quick recap on tag helpers, here you
can see a sample of tag helpers in Razor code. First we have a form tag helper. As
we can see, this is pure HTML and very easy to read. If you have been doing ASP.
NET MVC before, you can easily see that this code is much easier to read than with
its HTML helper counterpart. Then we have the asp-action tag helper, which in
itself is also a built-in tag helper. It can be used to specify the action that we
want to invoke when the form is submitted. Other functionalities, such as including
the antiforgery token with this request, can also be enabled simply by using yet
another built-in tag helper for this specific functionality, the asp-antiforgery
tag helper. Keep in mind that the net result of using any of these tag helpers is
basically invoking C# code. That will generate in turn HTML in the resulting
response. Now that we have seen what the first about tag helpers is all about,
let's spend some time taking a look at the more advanced tag helpers that come with
the platform. These are tag helpers that will definitely be useful when you're
building more complex enterprise level applications with ASP. NET Core. Up first,
the JavaScript tag helper. The tag helper itself is set to enhance the script tag,
and it has several attributes that we can use on it. For example, take a look at
the screenshot of the project here on the left. We have inside of the scripts
folder a number of scripts in the root, and we have two subfolders, one of them
called MoreScripts, and another one called TempScripts. When I want to include
several JavaScript files into my view, I can use the asp-src-include attribute.
Using this value, I can define which ones I actually want to include. Assume I want
to include all JavaScript scripts, so the ones in the root, as well as the ones in
the subdirectories. And I can do that using the value for the attribute that you
see here on the slide. This pattern, so this wildcard pattern that you see here,
will actually make sure that all files with a. js extension are included, including
also the ones in just any subdirectory. But what if I want to exclude one or more
scripts? Well, similarly, there's an asp-src-exclude attribute available, and I can
pass it a value of scripts that I want to exclude after all. Here I'm specifying
using the value that I don't want any files ending in. js that live in the
TempScripts folder. As mentioned, the JavaScript tag helper comes with a number of
attributes. We've already seen the asp-src-include and the asp-src-exclude, which
we can use to indicate which script files we want to include or exclude in the
generated view. The asp-fallback-src attribute is another available attribute. It
allows us to specify which script to include as fallback if the content delivery
network is not available. So we can use this to point to a local fallback file, and
related to that one, we can also use the asp-fallback-test attribute, which allows
us to specify a piece of script code that will be loaded to check if the scripts
were correctly loaded from the content delivery network. Next to the JavaScript tag
helper, also a CSS tag helper exists. When we want to include a CSS file in a page,
we have to use a link tag. Well, in ASP. NET Core MVC, we get the ability to
control how the inclusion of CSS works using the link tag helper, which therefore
will work with the link tag. It's again thus a built-in tag helper. The attributes
that we can use on this tag helper are actually pretty similar to the ones used on
the JavaScript tag helper. Take a look at the snippet you see here on the slide.
The tag helper is the link tag, and it defines first an asp-href-include attribute,
where we specify that all minified CSS files living in the /lib/bootstrap/dist
folder should be included. Also similarly, it's possible to use a fallback should
we be using a content delivery network. Using the asp-fallback-href attribute, we
specify which file to use when the CDN isn't available. Testing whether or not the
CDN is reachable can also be done using some attributes. For example, we can
specify the asp-fallback-test-class attribute to see whether or not the value,
hidden in this case, is available. If not, well, I have to use the fallback file
specified earlier. The CSS tag helper, as mentioned, defines some very similar
attributes compared with the JavaScript tag helper. The asp-href-include and asp-
href-exclude can be used to include or exclude one or more CSS files in the
resulting view. The asp-fallback-href-include attribute can be used to specify
which CSS we'll want to use if the CDN isn't available, and we just need to use a
local fallback file. To test whether or not the CDN is available, we can specify
which class property or CSS value we want to test, and based on this result, you
will then use the fallback version of the CSS file.

Demo: Using the JavaScript and CSS Tag Helpers


Let's now take a look at the first demo of this module, where we will be using the
JavaScript and the CSS tag helpers to control the use of script and CSS files in
our views. In this demo, we are going to take a look at the JavaScript and CSS tag
helpers that come with ASP. NET Core. We're looking at the layout page, and
typically we would include scripts as you can see here highlighted. So we're using
a script tag that points to a JavaScript file. Now ASP. NET Core MVC comes with the
JavaScript tag helper, and that tag helper allows us to point to a JavaScript file
relative to the wwwroot folder. So over here we're seeing the JavaScript tag helper
being used, and we're pointing to the jQuery file within the lib directory, which
is a subfolder of the wwwroot folder. We don't always have to fully qualify the
JavaScript files with the script files that we are using. Over here you can see
that I'm using a globbing pattern, so I am using a wildcard symbol, and in this
case, I'm saying that all JavaScript files, no matter what subdirectories they are
in, should be included. Take a look at the Solution Explorer for a moment here. So
we have the Scripts folder, and below that, we have the MoreScripts folder, we have
the TempScripts folder, and I also have a couple of JavaScript files located in the
root of the Scripts folder. Just including the asp-src-include with the pattern you
see there would include all JavaScript files. But ASP. NET Core MVC comes also with
the asp-src-exclude, which also accepts a globbing pattern. In this case, I'm going
to say that I don't want to include the JavaScript files within the TempScripts
folder. And if we take a look at the resulting HTML, in the page source, we will
see that indeed script1, 2, 3, 4, 5, and 6 have effectively been included, but the
error script has not been included. Next to a tag helper for JavaScript, there's
also a tag helper for CSS. That's being used right over here at the top to include
bootstrap in this case. What I've done here is I've pointed out that I want to
download Bootstrap from the CDN, so the content delivery network in minified
format. Now as we've seen in the slide, ASP. NET Core MVC comes with a number of
attributes that we can use to also point to a fallback version of Bootstrap. I'm
using the asp-fallback-href here to point to the minified version of Bootstrap in
my local application. Now that file will be picked up if the CDN is unavailable.
Now we can write some test script for that. Now, we don't have to do that
ourselves. By using the asp-fallback-test attributes, ASP. NET Core will generate
the correct JavaScript to test if the class is available that we are specifying
with the test class. And then we are going to check for the given value for a given
property. Here we see the generated code. Notice that there's a meta tag that was
generated, which is pointing to the class btn. That was the one that I specified
here as a test class. The JavaScript code I haven't written myself, it's being
generated by ASP. NET Core MVC, and it's being injected to check if the value for
the given property that we've specified is available. If all works out, then we are
using the CDN version. If not, we're using the fallback version.

Other Tag Helpers in ASP.NET Core MVC


Something as simple as an image on a web page will probably not benefit a lot from
the added value that a tag helper can bring. However, ASP. NET Core MVC comes with
an image tag helper, which of course, adds some extra functionality on the image
tag. It's actually quite limited still in what it can do. It defines just one
attribute called the asp-append-version attribute. What does this attribute do
then? Well, it will add an extra version parameter value to the end of the image
name. This allows us to still use caching, but also to get a new version to show up
on the client-side as soon as it has changed on the server-side. Take a look at the
snippet here on the top of the slide. We can see the asp-append-version attribute
is set to true. What this will then generate is shown in the next snippet you see
here. The source value for the generated image tag is suffixed with a v parameter
and a value. This value is a version checksum. As long as the image stays the same,
this value will remain the same as well, allowing browsers to cache the image. When
we change it, this value will also change, and therefore a new version will also be
downloaded from the server. And a final advanced tag helper that we need to spend
some time looking at is the environment tag helper. This tag helper will allow us
to check whether or not part of the HTML should be generated or not, based on the
value of the hosting environment. If you don't know how to change the hosting
environment, no worries, I'll show that in the demo. Let's take a look at the tag
helper first. Here we can see the environment tag being used twice, and it has a
names attribute. This will contain one or more environment name, each indicating
when this block of markup code should end up in the final generated HTML. This
allows developers to include debug information and so on. Here I'm using it to
change between different versions of the CSS and JavaScript files that need to be
included.

Demo: Working with the Image and Environment Tag Helper


Let's take a look at the image tag helper and the environment tag helper in action
in the next demo. In this demo, we are going to take a look at some other tag
helpers that come with ASP. NET Core MVC. To start with, let's take a look at the
environment tag helper. Take a look at the Solution Explorer here. Notice that I
have a CSS file, as well as a minified version of my CSS file. Now, of course, I
want to use the minified version only for production purposes. ASP. NET Core MVC
comes with the environment tag helper. Now the environment tag helper is directly
linked with the environments which are part of ASP. NET Core MVC as well. If we go
to the project properties, we can see environment variables. There's a variable
built-in called the ASPNETCORE_ENVIRONMENT, which is by default set to Development.
We can also set it to, for example, production. Based on the value that we
specified there, the environment tag helper will either include or simply skip a
part of the code. That's what we see here. In the first use of the environment tag
helper, we're linked with the development environment, so it means that the code
between the open and closing tags will be included only if we are in the
development environment. If we are in staging or production, the second part will
be included. Now let's take a look. So I've set the environment now to production,
save this, and run the application. Let's take a look at the developer tools, and
under the Content directory, we're indeed seeing that only the minified version has
been downloaded. That's good. Now notice that there's something like a bit of a
version number which has been appended to that CSS file. Now that is because I've
used the asp-append-version tag helper, and I set it to true, of course. Using
append-version, a checksum will be calculated for the given file, and that will be
included as the version parameter. What this will result in is the fact that the
file can be cached locally, and we can change it on a server, the checksum will
change, and the browser will automatically see the change, because of the fact that
the version has not changed, the checksum has changed. I've used that here for the
CSS file, but I can also use it, for example, for an image file. For example, here
for Bethany's logo, I've also used append-version. If we go to the source again,
you will notice that also a version suffix has been appended to bethanylogo. png.
So by using append-version, we're appending a checksum. As soon as the file changed
on the server, the checksum will change and a new version will be downloaded as
well. This way we avoid problems with caching in the browser.

Creating Custom Tag Helpers


We've now seen that ASP. NET Core MVC comes with quite a number of built-in tag
helpers. Although these can get us pretty far, it's good to know that we can use
tag helpers as an extension point as well. As developers, we can create custom tag
helpers, ranging from very simple ones to very complex ones. In the next slides and
demos, we'll spend some time looking at custom tag helpers. Let's kick off this
part by exploring how we can create in general a custom tag helper. A tag helper is
in itself nothing more than a class that inherits from the base tag helper class.
Typically you'll want to place all your tag helpers that you create in your
application in a common location. Perhaps even in a separate project, so you can
package them and reuse them across multiple applications. Here on the slide, we're
looking at a very simple tag helper, which, by the way, was created in the
introduction course. It's called the EmailTagHelper, and indeed it inherits from
the base TagHelper class. The TagHelper class defines a method called Process,
which is the method we'll need to write code inside, code that does the actual HTML
generation, and manipulation. The name of the tag helper is also important, since
the name tells ASP. NET Core MVC what element this tag helper is working on. So in
our case, the EmailTagHelper will work on the email HTML element, which of course
is not a default HTML element. Because we add the EmailTagHelper in our
application, adding the email element in HTML will trigger the search for a tag
helper with the name EmailTagHelper. Now that's basically the way to invoke code
from the markup using a tag helper.

Demo: Creating Custom Tag Helpers


Now that we know how we can create custom tag helpers, we're going to explore
several samples in the demo here where we are going to be creating custom, more
complex tag helpers. We're going to create a process tag helper, a shorthand tag
helper, and finally, we're going to work with a tag helper that interacts with the
content around the tag. Demo time! In this demo, we are going to take a look at
some custom made tag helpers. And when you look at the screen here, you're already
seeing one. Take a look at the 33% complete progress bar. Well, that is actually
generated by a tag helper that I've created. It is actually using the progress bar
that comes with Bootstrap, but I've wrapped it inside of a tag helper, and I'll
show you the code in just a second. So here is the progress bar documentation on
the Bootstrap website. Let's take a look at some sample code here. You'll notice
that you can generate a Bootstrap progress bar by including the properties that you
see here. So the aria-valuenow is the current value, the min and the max value can
also be specified. And we can wrap this code inside of a tag helper. Let's take a
look. In the TagHelpers folder, you'll find a ProgressBarTagHelper class. The class
is named ProgressBarTagHelper, and it inherits from TagHelper. So that means that
by default, it would work on a ProgressBarTag. However, I don't want that. I'm
going to override how this TagHelper works. I'm going to specify that it targets a
div on which a progress-value attribute has been set. And I'll show that in just a
second. Now my tag helper needs a couple of values, the current value, the minimum,
and the maximum. If you omit the current value, it will be set to 0. Notice that
for each of these properties, I've also specified what the attribute in HTML will
be, so that this will be wired up when I use my tag helper. Automatically when a
tag helper is being used, the process method will be invoked. In here I'm going to,
well, generate my resulting HTML. First, I'm checking that the minimum and the
maximum are correct so that the minimum isn't larger than the maximum, and I also
checked that the current value isn't larger than the maximum or lower than the
minimum. I then calculate what the current percentage value should be. Finally, I'm
building up that HTML that we just saw on the Bootstrap website. I have the div
that has the class that is specified by Bootstrap, I have the current value, the
min value, and the max value being set here. Finally, I'm going to basically let my
tag helper generate the HTML. So I'm going to append the HTML that we've just
generated, and I'm also going to specify as an extra attribute that the class
should be progress. All right, now we saw the tag helper being used on the
ShoppingCart view, so that's this Index view. Notice here that I've generated a div
with the progress-value being 33. Indeed the target element for this tag helper is
a div on which the progress-value has been set as attribute. I have also specified
a value for the progress-value, which goes directly in this integer value here. I
haven't specified a value for the minimum and the maximum, so they will default to
0 and 100 respectively. Let's take a look at another type of tag helper that we can
use. So this tag helper basically wraps functionality, Bootstrap functionality in
this case, inside of a tag helper that we then can easily reuse across our
application. Now talking about reuse, let me show you another tag helper that
really makes reuse a lot easier. I have the BethanysPieShopFormButton TagHelper,
which is going to target in this case a new custom element called bethanysbutton.
Inside of the class, I have the Content and ButtonStyle as properties, and then in
the automatically invoked process method, I'm going to, well, be generating my HTML
that needs to be generated by the TagHelper. I specified that the attribute type
should be Submit, so it's going to be a plain Submit button. The tag mode should be
set as a starting and closing tag, and then, and that's important, I specify the
class to be a built-in Bootstrap class, ButtonStyle. So what I've now done is I've
basically wrapped functionality, again Bootstrap functionality, inside of this
process method, and I can then more easily create my own button. Let's take a look.
I've used this button over here, so I've called bethanysbutton as specified
content, as well as button-style as attributes, and so this primary will actually
be appended over here, and this will then result in the generation of a Bootstrap
button. So this tag helper generated a full control on itself. There's another tag
helper I want to point out here, and that's the TableHeaderTagHelper. This one
targets a table element where a header has been set. The tag helper defines a
HeaderContent property. In the process method, I'm going to generate a completely
new tag, namely, an h2 tag with as content the content I specified here, and then
before the actual element, I'm going to generate this HTML. This is being used
inside of the UserManagement view. Notice here that I have a table where header-
content has been defined and the header tag is there. That's a requirement for this
tag helper to be applied. Now the header-content is User Management, and notice
that the page itself does not have a title defined. Let's run the application and
we'll see a title appear. So here we are now in the User Management page, and so
indeed a title, User Management, has been set right before the table. And it's this
tag helper that actually generated it as a pre-element before the actual table. If
you want to dig into some more tag helpers, the sample code for this course comes
with quite a few extra tag helpers that I haven't highlighted here in this demo.
You can take a look at them at your own pace.

The Conditional Tag Helper


Now that we have seen some interesting stuff about the tag helper, let's take a
look at some scenarios that are also very interesting around tag helpers. And we'll
start off with a bit of a special one, one that I believe once you know it, you'll
be using quite often. Take a look at the code here on the slide. Using this code,
which is part of the menu in the layout file, I'm checking whether or not the user
is signed in, and if that is the case, we are showing in the menu also the item to
allow sending a pie as a gift to someone, an item which is hidden, by the way, for
not logged in users therefore. Now, although this works, it is quite verbose for
something that you'll need quite often in most of the applications that you'll be
building. And if you think about it, it's actually code that we are invoking from
the view. Now, since we're invoking code, we are probably capable of using a tag
helper for this one as well. Here I have replaced the code from the previous slide
with a condition tag helper. Only if the condition returns true will the anchor tag
be included. The result is the same as above, but if you look at it, the HTML is
much cleaner.

Demo: Creating the Conditional Tag Helper


In the next demo, we are going to take a look at how we can write that conditional
tag helper and then see it in action. Let's now take a look at that condition tag
helper I was talking about. So the need to check, for example, if a user is signed
in, and I'm using this code that you see here, the SignInManager. IsSignedIn,
passing in the user. And only if that returns true will it be including this link
into the menu, for example, to send a pie. Now this code is okay, but it's actually
a bit ugly. What I'm going to do to fix this is create another tag helper that I've
named the ConditionTagHelper. This one will work on any element that defines the
Condition property. So it's a Condition tag helper, it inherits from TagHelper, and
there's a condition that returns a Boolean that is going to be passed along. In the
Process method, I'm simply going to check if something is false, and if that is the
case, I will go to suppress the output. The tag helper is not going to generate
anything anymore. So what I can now do is remove this code, and uncomment this code
here. In here, I have an li on which I use my ConditionTagHelper, and I specify
that same condition. Is the user signed in using SignInManager. IsSignedIn? And
that will then generate my anchor tag if that condition returns true; otherwise,
the li and its children will not be generated. Let's try if it works. I'm going to
run the application, and when I'm not signed in, I should not be seeing the PieGift
option. And it seems to work. I'm not signed in. I'm not seeing it. Let's try if I
log in, and then indeed, the send a pie option is available. So the
ConditionTagHelper seems to work.

Working with the tagHelperPrefix


By default, when we are creating a tag helper and using it within our view code,
the tag helper will apply on all instances of the tag it's working on. That may in
some cases not be the behavior that we want. It's possible to basically make the
use of a tag helper explicit within a view using a tagHelperPrefix. Only then when
the prefix is being used will the tag helper become active. We can do this using
the tagHelperPrefix directive. In the sample code that you see here on the slide,
we have defined that custom will be the prefix. This results in the fact that only
elements which are then prefixed with the custom prefix will now support tag
helpers.

Demo: Using the tagHelperPrefix


Well, let's return again to our demo and see the tagHelperPrefix in action. In this
demo, I'm going to show you the tagHelperPrefix. So as mentioned in the slides,
using the tagHelperPrefix, I can specify a tag to basically enable tag support
within that view. And so basically I'm then going to make the usage of tag helpers
within that view explicit. So as you can see here at the top of the screen, I've
added the tagHelperPrefix custom. And let's take a look down here. This was the
page on which we had used that progress bar, which worked on a div on the progress
value attribute, and as we can see, Visual Studio is not highlighting it anymore
now, because this is not being seen a tag helper anymore. I need to prefix this,
and now as you can see, Visual Studio highlights this again, it applies some
different coloring here, indicating that this is now seen again as a tag helper.
But notice down here, because I've made tag helpers explicit, now that also the
asp-controller and the asp-action tag helpers aren't working anymore. So when I
want to enable them again here, I need to also prefix the anchor tag here with the
custom tag helper. In this way, we can, using the tag helper prefix, enable or
disable the usage of tag helpers within a page.

Async View Components


We have now seen in much detail how tag helpers can help us keep the view code much
cleaner, and how they can help us with the reuse of certain blocks of
functionality. Another new view-related feature which was added with the
introduction of ASP. NET Core MVC is view components. In this part, we'll learn
more about asynchronous view components. Before we start exploring the asynchronous
version of view components, it's definitely interesting to spend a minute to do a
quick recap on what view components are. View components are, as the name implies,
blocks of UI functionality, so partial content. They can be compared with a partial
view, but there is definitely a big difference between view components and partial
views. A partial view is just view codes, meaning that it won't contain any logic.
We pass it a model, and it will display the data from that model in some way. Now a
view component actually consists of view code and logic, to which we can pass
parameters. If you look at a view component, it is basically a mini controller and
its view. Using view components, or better, moving things to a separate view
components, improves the reuse of code, and thus improves also the separation of
concerns. Although they look a bit like mini controllers, they aren't to be used
standalone; they will always be linked to a parent view. There are different ways
of creating a view component, and the most common approach is shown here on the
slide. We create a class with, in this case, the name ShoppingCartSummary, and it
inherits from the base ViewComponent class. Now the functionality of the view
component should then be placed in the method called Invoke. Notice that we aren't
overriding the invoke method, since the base ViewComponent doesn't provide a
default implementation. However, the Invoke method will be invoked for us by ASP.
NET Core, when we use the ViewComponent on another view. The Invoke method can then
return a string, by typically it's more interesting to return an object that
implements the IViewComponentResult interface. ASP. NET Core MVC comes with three
types that implement this interface. Content ViewComponentResult, and HTML Content
ViewComponentResult. I guess the person within the. NET Core team that created
these names must have created them on a Monday morning. Anyway, we typically won't
be creating these ourselves. Instead, we can use, for example, the View method
declared on the base ViewComponent class to return a partial view, as you can see
here on the slide. That returned view should then be placed in a specific location
for ASP. NET Core MVC to locate it. If we put it in a different location, it won't
resolve, leading to an error. Here you can see that if the name of the
ViewComponenet is ShoppingCartSummary, ASP. NET Core MVC will search for the view
in two locations. Assume that we are using the ViewComponent in the context of the
HomeController, it will search in the Views, Home, Components, ShoppingCartSummary
folder, and in the Views, Shared, Components, ShoppingCartSummary folder. In there,
if you don't specify a file, it will search for the Default. cshtml file. Now in
the introduction course, we've been building a view component this way. Most view
components that we'll create are synchronous view components. Basically, any view
component that we are creating using the Invoke method is synchronous. However, it
is not unthinkable that we have to perform work in the view component that will
work with an asynchronous API. If that is the case, we won't be able to work with
the regular Invoke method. Instead, we'll have to use the asynchronous version
called InvokeAsync, which will return a task. When we use this in the Razor view,
it will instruct Razor to wait for the method to complete, and when it's ready, it
will insert result into the view.

Demo: Creating an Async View Component


In the next demo, we will be creating an async view component, and we will see that
Razor will wait for the request to complete before returning the result to the
client. In this demo, we are going to take a look at the status which is down here
at the bottom of the page. It currently says All systems up and running. Now how
did that little text there appear? Well, it's actually being built using an
asynchronous view component. Let's take a look. In my Components folder, there's a
SystemStatusPage view component, which is just a plain class that inherits from
ViewComponent. Typically for a view component, there's an invoke or for an
asynchronous view component an InvokeAsync method that will be invoked
automatically when the ViewComponent is called. Because we're going to do an
asynchronous task within the Invoke method, I'm going to use the asynchronous
version, and I'm going to return a task in IViewComponentResult. For the purpose of
the demo here, we are going to do a check to see if the Pluralsight website is
available. So I'm going to do an asynchronous request to the Pluralsight website,
I'm going to check if I then get a status code OK, if so I'm going to return a view
true; otherwise, I'm going to return to a view false. Now with a view component,
ASP. NET Core expects that in the Components folder we have a subfolder with the
same name, that is the SystemStatusPage, and in there I have a Default view file
available, which is, in this case, bound to a Boolean value, and if that returns
true, it says all systems up and running; otherwise, it says we're currently
encountering some issues. And that's basically what you see at the bottom of the
page. If the Pluralsight website is available, we will see that all systems are up
and running. Now using this asynchronous component inside of, in this case, my
layout, is actually done in a very similar way to using a regular view component.
In this case, I'm calling Component. InvokeAsync with then the name of the view
component SystemStatusPage here.

Localizing the Application


Bethany has again returned to our office. She's starting to get more international
tracking with her store. Customers are ordering her pies from all over the world.
And non-English-speaking customers will have an easier time navigating through her
site when it's actually available in their native language. So Bethany has now
asked us if it's possible to translate the application in several UI languages. The
good news for Bethany is that indeed it's of course possible to translate the
application into several languages. It's even possible that we initially support a
couple of languages and that we add more languages later on. Let's see how we can
do all this in ASP. NET Core MVC. Now to start with, the model that is being used
in ASP. NET Core MVC is similar to what we had in previous versions of ASP. NET
MVC. It's also based on the use of resource files, so *. resx files. The resource
file is again a dictionary, so we are searching translations based on the key we
are supplying. ASP. NET Core MVC will search for the closest match in terms of the
resource file. Although conceptually not that much has changed, the way that
resources are being used did change. Quite a lot, in fact. Previously, when we
added a *. resx file, Visual Studio would also create a class that allowed strongly
typed access to do resources. That is no longer happening. So that model has
changed. In ASP. NET Core MVC, a new model is set up based on two interfaces that
we can use. The IStringLocalizer, and the IStringLocalizer of T. Let's see how
these two interfaces can help us with getting our application translated. We will
be using these interfaces in our controllers. Just like everything in ASP. NET
Core, ASP. NET Core will make sure that we get an instance via dependency injection
again. In the sample code we see here on the slide, I'm defining first the local
IStringLocalizer, and then using constructor injection, we're getting values that's
being passed in by ASP. NET Core. The IStringLocalizer defines an indexer, which
I'm using on the last line of the snippet here. To that indexer I'm passing the key
of the resource that I want to retrieve. Here that would be PageTitle, which I then
place in the PageTitle property of the ViewBag. Now what's happening behind the
scenes is the following. When we ask the stringLocalizer to get a translate value
for PageTitle, ASP. NET Core, well, in fact, the stringLocalizer, will check what
is the current culture. Based on that, it will search for a resource file for that
culture. It will search for an exact match first. Otherwise, it will use a
fallback. For example, if the current culture is set to ENUS, it will search for a
resource file with that exact culture. If that resource file cannot be found, it
will search for a resource file for the EN culture, so the English culture. If that
one isn't found, it will fall back on a default resource file. Now once it has the
resource file it needs, it will start a search for the localized version of the key
that we've passed it, in our case, PageTitle. If that key is found, the value from
the RESX file will be returned. Now, if that value cannot be found, and this is
really a bit special here, it will return the original string, in our case, so
PageTitle. So essentially, if the key isn't found in the dictionary, the key is
returned. The latter is definitely a change from how our resources are otherwise
returned. And I must say, the first time I saw this model, I wasn't really a fan.
And now instead of discussing whether or not this is a good approach, let's see how
we can configure our application so that it supports localization. Now we talk
about configuration, we immediately think of making a change in a Startup class,
and that is no different here. Note that we don't need to add any extra packages,
by the way, to add support for localization in our application. The package that's
required is already referenced by the default Microsoft ASP. NET Core MVC package.
Now, the code that we're looking at here on the slide is the code that needs to go
in the ConfigureServices method of the Startup class. First, we are calling
AddLocalization, which will add support for, well, localizing the application. To
the options, we are passing a resource path, which is the folder where the
resources will reside in our project. Calling AddViewLocalization also enables the
application to have localized view files. So for example, it will then support
index. en. cshtml. Again, I'm specifying here using the options where ASP. NET Core
should be searching for these resource files. This already is enough to allow the
application to support localization services inside of the application. We also
need to be able to select the culture based on the incoming request. For this, we
need to use the RequestLocalizationOptions. Using this class, we can refine which
cultures the application supports, and which will be the default one. That's
exactly what is happening in the snippet you see here on the slide. First, I'm
creating a list of cultures which are supported in my application, I then use the
options to specify which is the default culture, as well as which cultures are
supported in the application. Next, we also need to make use of the request
localization middleware. This will help in figuring out which is the culture for
the incoming request using a provider. We can configure it using the options we
have just created which define the supported and the default culture. Now you may
be thinking, I need to be able to localize the application in several places.
Typically you'll need to be able to localize controllers, services, views, and data
annotations. The good news is that the IStringLocalizer actually supports all of
these to be localized. We'll see in the demo in just a minute how this can be done.
Now, one more thing before we go to the demo. Here you can see a screenshot of how
the resource files are structured within the Resources folder in our application.
Typically for views, the type that's responsible for the localization of the view,
the IViewLocalizer, uses the name of the view suffixed with. resx. Note that indeed
it uses the full name, including the folders in which the views reside. And for
controllers, a similar structure is being used as you can see.

Demo: Supporting Localization in the Application


Let's return to the demo one last time for this module and see how we can enable
localization of the application so that Bethany can offer site in multiple
languages to her customers. In the last demo of this module, we are going to take a
look at the different ways that we can translate our application into several
languages. At the bottom of the page, I now have this selection that I can use to
change the language of my application. For example, I can set it to French, a
couple of things will now be translated as we can see here in the middle of the
screen. I can also change things into Dutch, which is my native language, and now
this is Dutch. All right. I'm going to show you quite a few things to see how
translations can be done in ASP. NET Core MVC. I'm going to jump back and forth
between the demo and the code. Localization can be done in several places within my
application. I can localize starting from the controller, and I can localize
starting from the view. Let's first take a look at the controller. And I want to
start localizing content from within the controller. I can use the IStringLocalizer
interface that I'm injecting here via dependency injection into my controller. In
the index action method, I'm going to use the stringLocalizer, which has an indexer
available to search for the translation of a given value. Now the first question
that pops to mind, where is this thing going to search? Well, ASP. NET Core MVC
uses resource files for translations. In my application, these resource files are
in a folder called Resources. And in here, there's quite a few resource files. Now
as we can see, there's a. resx file which has the fully qualified name for the
HomeController, so Controllers. HomeController. resx, there's a Dutch translation,
and then a French translation, and then FR translation, so that's one with the
local culture. I open the default. resx file, and I'll have some key value pairs
here. This hasn't really changed from previous versions or other technologies that
also work with resources files. I'm going to look at the Dutch version. There's
Dutch translations, and in a French version there's, of course, French
translations. Now the home controller actually asked us to look up this particular
value here. Now ASP. NET Core MVC has a bit of a special ability when it comes to
translating values. It will actually use this as the key to look up the translated
value, and if it can't find the value, well, then it will return this particular
value here. Let's check that. I'm going to add this value into the ViewData for the
view with key PageTitle. Let's take a look at the layout file for a second. Over
here at the top I've specified that the PageTitle should be retrieved from the
ViewBag, so it will actually search in the ViewData for a value with PageTitle.
There's no other title defined here. So let's run the application again, and check
what the title at this point does when we change languages. So notice that the
title is now Welcome to Bethany's Pie Shop. Let's translate the application into
French. And you'll notice that it doesn't change. And the reason that it didn't
change was that this key couldn't be found in the resource files. Instead, let's do
something else. Let's put in the ViewBag, or you could easily put in ViewData as
well, a value that is looked up with the key PageTitle. And if we take another look
in the Resource files, I have a PageTitle, and I have a PageTitle here as well, and
I should also have it for the Dutch version, PageTitle. Let's run the application
again and see if the title now is also going to be localized. You can already see
that the title is now in Dutch. And when we change the application into French,
well, then the title changes to French. All right, that's good. Now one thing I
want to point out here is keep in mind that the resources that are going to be
looked up with this controller when we use the StringLocalizer will be the
resources with the name Controllers, then the name of the Controller, and then
optionally the language, and then resx as the extension. I want to show you one
last thing here, let me comment this out, uncomment this, and this line is actually
going to search for PiesOfTheWeek, which is available in the default resources, but
is not available in the French or the Dutch translations. I'm going to paste
another line in there, which is going to search in the resources for a key which is
not available anywhere. All right. Now let's visualize that in the Index again. So
now here in the Index, I'm going to comment this out, and this should actually show
us two lines of extra content in the homepage of the site. And notice what happened
now. So, no matter what language we are running the site in, we will keep seeing
test123. That is because we have a default value in the default resource. So
French, so no value can be found in the Dutch or the French translation, so it's
going to pick up the value for the default resource. But then take a look at what
happened for the second value, so NonExistingKey. In my resources, NonExistingKey
is nowhere to be found. I asked the stringLocalizer here to search for
NonExistingKey. It didn't find it, so it simply returned NonExistingKey as the
value to be displayed in the UI, and that's the value that we saw here. Now I just
showed you how you can work with translations, but there's one thing that I haven't
shown you yet, and that's the configuration that we need to do to get localization
to work. So let's go to the Startup file, and over here you can see that I'm adding
to my Services collection localization support. I can optionally pass in some
localization options, and this is a way to specify where the resources are to be
found. In this case, that is the Resources folder in the root of my application. I
can, of course, change that. What we have seen so far was actually basic
localization for the controller, but we can also work with ViewLocalization. When
we add support for ViewLocalization, our views will automatically also be linked
with a resource file that can then contain localized versions of the content for
that view. In this case, I specify that I want to also use the suffixed way of
searching for the correct resource, and that these resources will also live in the
Resources folder. Also, date annotations can be localized, and we're adding support
for that here as well. Let me show you ViewLocalization next. We're now back here
in the Index view, and notice here that I'm injecting an IViewLocalizer here. The
IViewLocalizer will also do lookups in resources files, but in this case, it will
actually look up for the resources in the resources folder, but now it will search
in the Views. Home. Index and then the suffix for the language, and then the. resx
extension. The values that were retrieved here were the ones that we saw changing
languages when we ran the application. So let me show you them again. So that was
these two values that are being retrieved from view resources. Now what I haven't
shown you yet is how we can actually change languages, how I can list the number of
languages that my application supports and create that language selection. Now the
first thing that I'll show you is the Startup again. In the Startup, I'm
configuring my application so that a number of cultures are supported. That's the
list that you can see here. I also specify what is going to be the default, and
then I specify that these cultures are supported as cultures, as well as UI
cultures. This way we can configure our application to support these languages.
Also in the Configure method, I need to make a small change. I'm using here a
UseRequestLocalization, which is passed a RequestLocalizationOptions value. This
can be used to check what the culture of the incoming request will be. And the
actual language selection is a partial view I've created in the shared folder. In
here, I'm injecting an IViewLocalizer, as well as RequestLocalizationOptions. The
requestCulture is used to determine what culture was requested upon receiving the
request. In this block of code here, I am asking the localization options supported
by the application to be returned as a list, and I'm going to put them in a list of
select list items. Over here you can see the form that allows the user to switch
between languages. Most importantly, the select is bound to the list of culture
items, that's the one that was created up here, and the selected value is captured
in this attribute. And when we change the language, the SetLanguage method on the
home controller is going to be invoked. In here, we are going to create a new
cookie, and we are going to set the culture value to the newly selected value, and
we're going to make it expire only in one year from now. And now we're going to
redirect to the return URL that was built up in the cshtml as well. At this point,
we have a fully working localized version of Bethany's Pie Shop, where also the
user can change languages.
Summary
We have reached the end of this view-oriented module. It's been interesting to
learn the different options that we have to make our view code more readable. We've
started our journey by exploring the built-in tag helpers, and we have seen quite a
few options to create custom tag helpers. We've then also learned how we can create
synchronous view components, thus adding support for calling asynchronous APIs from
within a view component. Finally, we've updated our application so that the user is
now able to select his or her preferred language, and see the site in the selected
culture. In the next module, we'll stay a bit in the same area. We'll see how we
can create more discoverable pages using ASP. NET Core MVC. Thanks for watching.

Optimizing the Discoverability of Pages Using the Routing Engine


Module Introduction
Hi there, and welcome to this module titled Optimizing the Discoverability of Pages
Using the Routing Engine. What a nice title I have come up with for this module,
even if I say so myself. Just so you know, you're listening to Gill Cleeren here in
this Pluralsight course named Building an Enterprise Application With ASP. NET Core
MVC. As you may have understood from my wonderful title there, I'm really proud of
it, this module is about more advanced routing topics. Using routing, we are able
to make the pages within our site easy to reach and easy to discover using a search
engine. This is, of course, for many companies the ultimate goal, since it will
typically result in better sales when it's easier to find something on your site.
Let's kick off the module by taking a look at the topics that we will explore in
the module. As the very first item in this module, I will give you a brief overview
of the routing engine and its options. If you are already familiar with the routing
engine in ASP. NET Core MVC, feel free to skip this item. After we've seen how it
works, we'll dive in the more advanced topics of this module. I'm going to start
with attribute-based routing. We'll learn the different ways that we can use
attributes in our controllers to control the routing of the application. Next,
we'll discuss areas, which will also help in making the URLs for the application
cleaner and more representative. Finally, we'll discuss how the routing engine can
be used to create outgoing URLs. For example, to others places within the
application. A lot of interesting stuff, if you ask me. Let's get started.

An Overview of Routing
So as mentioned, I'm going to start the module with a brief overview of the routing
engine that comes with ASP. NET Core MVC. In the introduction course, I've already
deeply covered the routing engine and its basic options. The following is just a
summary of what we've seen there. ASP. NET Core MVC comes with a routing engine.
Earlier versions of ASP. NET, so webforms, did not contain this building block. At
the time of webforms, there was a close relationship between the request and a
physical file that was being requested; hence, ASP. NET just had to look for the
file in the file system of the application and save that. With ASP. NET MVC, and
there's also with ASP. NET Core MVC, that close relationship is gone. We're now
making requests to action methods within a controller, so there's no direct link
anymore. Now to solve for this, ASP. NET Core MVC comes with a routing engine. This
routing system will make sure that requests are routed to the correct action method
within the controller. Now let's see how that routing engine works. Routing is
based on routes. Each route is a URL pattern, and that's mapped to a handler. The
handler in the case of MVC is the action on the controller. The fact that we can
use patterns for our routes means that we don't have to type all the possible
routes for our application. What will happen is that URLs are compared to these
patterns. And when a match is found, in fact, I should say when the first match is
found, that pattern will be used to trigger the corresponding action. Now take a
look at this basic route that you see here on the slide, bethanyspieshop.
com/Home/Index. When we look at this URL, we can see that it's made up out of a
number of parts. The host, well, that's bethanyspieshop. com, as well as Home and
Index. These parts are known as segments. Typically the first part will be the
controller and the second part will be the action. Of course, we have to explain
this somehow to the routing engine. It's not that it's something that works by
default. We'll have to create a route that says that when a URL with a pattern with
two segments is encountered, that we'll assume that the first one is the
controller, and the second one is the action. If we now try to browse through
bethanyspieshop. com/Home, there won't be a match. The reason is simple. There's no
second segment here. Only if we by default have a matching number of segments will
there be a match. If you throw Home/index/pies at it, again, there will not be a
match for this pattern. The reason is the same. The number of segments isn't
correct, so there will not be a match. The number of segments is clearly one of the
most fundamental ways for the routing engine to know if a URL matches a pattern or
not. Now routing works for incoming URLs, so for incoming requests. That means that
if I sent a request to the web application, the routing engine will be invoked as
part of the process, and it will try to find an action to execute on a controller.
Next to doing this for incoming requests, the routing engine will also work for
creating outgoing URLs, meaning that it will be invoked when we want to generate a
URL, for example, to generate a link to an action on the different controller that
will be part of the generated page. We'll see later in this module how ASP. NET
Core MVC can be used to generate these outgoing links. Now working with routes has
changed quite a bit with ASP. NET Core MVC compared to previous versions of ASP.
NET MVC. Let's see how we can create routes first in our application. It's not
required, by the way, to add any package to enable the routing engine in an ASP.
NET Core MVC application. We can go ahead and configure routes inside of our
application. Of course, this is really configuration of the application, and it's
therefore something that we do in the Startup class of the application, more
specifically, in the configure method. There we can add code as we can see here on
the slide. I'm passing to the routing engine the routes or patterns that I want my
application to use. Keep in mind that I've said that as soon as a match is found,
ASP. NET Core will take that pattern to perform the matching; therefore, the
sequence that we place these routes in in the application has a very big influence
on which routes will be selected. The route that I've added here is a very basic
one, which contains just two named segments, one to indicate a controller, and one
to indicate which path is the action. Of course, real life applications, and that's
the goal of this course, meet some more complex routes than what you can see here.
Very often we will also want to pass to the route some default values, for example.
This allows us, in this case, to browse to the root URL, and the routing engine
will then know that in fact it should use the index action on the home controller.
Instead of using the syntax we just saw, where we created the defaults with a named
parameter, we can also define these inline, as you can see here. The net result is
exactly the same. When we navigate to the root URL, so without specifying a value
for the controller or the action, we will navigate to the index action of the home
controller. In many cases, we'll want to specify some restriction on what value can
be used for the matching of the parameter value. In that case, we can apply a
constraint. Here we can see an actual segment defined in the route, id. Now, id
will typically be a value that is passed to the action method, and it may be so
that we are expecting an integer parameter. If that's the case, we can specify this
using a route constraint, which as you can see here defines that the id should get
an integer value in order for this to be a match. Also, I've added a question mark
at the end. This is used to indicate that the id segment is optional, meaning that
this route is allowed to be used even if the id parameter cannot be found. There
will still be a match. The route that we've looked at in fact contains only
segments. If we are looking at improving the SEO for our site, so making it
possible for search engines to more easily know what the page is about, we can add
static segments to the route. This is just a string that will be part of the
pattern matching. That's being done by the routing engine only when a request is
made for a URL that starts with shop might there be a possible match for this
pattern.

Attribute-based Routing
Now that we've done a bit of a refresher on the routing engine that comes with ASP.
NET Core MVC, let's dive in the more advanced topics regarding routing. The routes
that we've just looked at are so-called convention-based routes, meaning that we
defined the route in the application's configuration. Well, there is another type
of routing that's often used, and that is attribute routing. Let's take a look at
the options we're getting with this type of routing. In the case of attribute
routing, we can use attributes which are going to be used to map an action to a
route template. Now to start with, to enable attribute routing, nothing really
needs to be configured at the application level. As long as we call app, use MVC in
the Startup class, we're covered. Nothing extra is required. The actual defining of
the routes and which action needs to be executed will now be done in the
controllers themselves. Take a look at the code here on the slides. We're inside
the HomeController and I have an Index action. On the action, I've now added an
attribute called Route. And as value, I've defined Home. Well, this means that when
a request comes in for /Home, there will be a match for the Index action on the
HomeController. We're not constrained to matching an action method with just one
attribute. On the contrary, we can add multiple instances of the route attribute,
each with a different parameter. In this case, a request for the root URL, so one
for Home, and one for Home/Index will all match or be routed to this action method.
Keep in mind that there is now no pattern matching whatsoever going on. Only when
there is a precise match of the defined string will the action be invoked. The name
of both the controller and the action are with this way of working of no influence.
As you may already be seeing, working with this attribute-based routing is perhaps
more work, since we need to define all these individual attributes on the action
methods in our code. Now, on the other hand, it's more fine-grained, and it gives
us more precise control compared to when we are defining the routes in the
configuration of the application. Now, as mentioned, by default, the name of the
controller and the action are of no importance for the selection of an action when
working with attribute-based routing. It is, however, possible, though, to create
routes in a more complex way. That changes this a little bit. Take a look at the
code here on the slide. I now have added another attribute where we are using
something called token replacement. By default, ASP. NET Core knows about three
tokens, controller, action, and area. And when we surround these with square
brackets, they will be replaced with the name of the action, the controller, or the
area where the action is defined. Now, know that we'll look, by the way, at areas
later in this module. Here in the code, I've added controller between square
brackets, and so this will be a match for a request for /Home/Details, and then the
id value also. Now also with attribute-based routing, we can take things a step
further. Here we are looking at the same route again, but now I've defined that the
id parameter is constrained again. The route itself is just a mix between a static
part and a variable part again. Using attribute routing, we can also use the Http
verb, such as HttpGet and HttpPost. These Http verb attributes can accept a route
template, so here in the sample, we see the HttpGet attribute accepting /Pies. This
means that if we now perform a request to /Pies, the ListPies action will be
invoked when the request is of type Get. Of course, this approach also works for
other Http verbs, such as Post. So we can also use the HttpPost attribute, which
will be invoked if we are performing a post request to /Pies. This approach is a
very good way of working when building an API with ASP. NET Core MVC as well.
Instead of defining the route on the action using an attribute, we can also move it
to the controller level. Under controller, I've now defined pies, and on the action
method ListPies, I've added the HttpGet attribute. This way, where we now perform a
request to /Pies, the ListPies method of the PiesController will be invoked. Now to
get to the GetPie action, I've added another HttpGet attribute, but it has the id
value between curly braces. This means that the action will be invoked now when I
perform a request, for example, for /Pies/1 where 1 will be the value for the id.
Just like we have already seen that we can on a single action method add multiple
attributes, we can do the same thing with controllers in our application. Here you
can see that both the controller, as well as the action, have multiple route
attributes defined. Now that we have spent some time exploring attribute routing, I
want you to think about what your preference would be. The good thing is that this
is not a this or that approach. In fact, it's very common to have one application
where you mix both approaches. So, convention-based and attribute-based routing.
Very often you'll see that for controllers convention-based is used more for HTML
pages and attribute-based routing is used more for APIs. Now, for actions, there's
really no rule of thumb here. However, keep in mind that as soon as we add a route
attribute on an action, it can only be reached using the attribute route, and not
anymore with the conventional route. As soon as we define a route attribute on a
controller, well, all its methods become only reachable via the attribute-based
system.

Demo: Optimizing the Routes in the Application


Enough slides. We've covered a lot of ground here. Let's return to the application
and learn about attribute routes in action. In this demo, we are going to take a
look at attribute-based routing, so I've now reconfigured the site to use
attribute-based routes. As you can see, when we go to the root of the site, we
simply still arrive on the homepage. If we go and take a look at the code, you'll
notice that on the index at this point I've placed a route with simply no value, so
the empty string, basically. This means that whenever the empty string route is
requested, we still arrive on the index method of the HomeController. Let's stop
Visual Studio for a second and make a small change here. I've now specified also
that the empty route should also go to this HomeController. Let's see the
consequence of this. As you can see, there's really no consequence here, but the
root on the controller, as well as on the Index action method still point to the
root of the site. Now let's take a look down here. When we switched languages, we
were also basically invoking an action method on the HomeController. Let's see if
that still works. Well, indeed the application is now translated, so the cookie has
been set via the action method, as we saw in one of the previous modules. In the
action method, I've now specified controller/SetLanguage, so this will basically be
available via /Home/SetLanguage. That's the method that was invoked at this case.
I've used a token replacement for this. Let's now take a look at the pies overview.
So the view all pies now goes to /Pie/AllPies. Let's take a look at the code. And
so we're now in the PieController. On the controller level, I have specified a
route that is again using token replacement for the controller. That one is
responsible for the pie part. For the list action method, I've in this case
specified two possible routes, AllPies or ListOfPies. Since the action method is
within the PieController, they will be addressable via /Pie/AllPies or
/Pie/ListOfPies. If I replace this with listofpies, indeed we arrive on the same
page. For the Details method, I've used a token for the id. If we indeed click here
on the apple pie, we go to /Pie/Details/30, which is the id that is getting
replaced. Let's make another change here, and remove the route attribute on the
controller. Let's run the application again. Let's now go to Pies, View all pies,
and now we're going to the localhost/AllPies, and that will directly take me to
this action method here. So as you can see, attribute-based routes give you more
fine-grained control over your routing in your ASP. NET Core application. To do
what I've just done here, I have disabled the conventional routes, but it is
possible to combine the two if you really want to do so.

Areas in ASP.NET Core MVC


So far, we've put all the controllers in the controllers folder. Using static
segments and routes, we can get control over what the route to a specific
controller should be. However, ASP. NET Core MVC supports something extra, and it's
called an area. Let's take a look at areas in the next part of this module. Instead
of throwing all controllers on one big pile, it is possible to structure our
application using areas. If we have a part of functionality that logically belongs
together, we can consider turning it into an area. Think, for example, the
administration part of Bethany's Pie Shop. That could be one large area, although
it may even be possible to break the administration part into smaller blocks even,
each of them becoming an area in turn. It's quite logical that this approach tends
to be more interesting in larger applications, since there will typically have a
lot of controllers and views, and in the long run, it may become a hassle to keep
an overview of things in the default way. When working with areas, on the other
hand, each area will typically get its own structure, similar to the structure of a
full ASP. NET Core application. It includes a controller, a view, a models folder,
making it obvious that this is basically a separate part of the application. And if
your application is large, this way it will also be easier to allow different
developers to work on different parts of the application. One other interesting
aspect is that by using routes, we can have multiple controllers with the same
name, as long as they live in different areas. Now reaching an area, so basically,
the controllers and the action within an area is typically done using the routing
engine, where we now add an extra parameter to the route pattern. By default, all
areas that we will create will go under the areas folder in the root of an ASP. NET
Core MVC application. To make things a bit more obvious and visible, let's take a
look at a slightly modified version of Bethany's Pie Shop. Here we've made a
decision that we want to add a new functionality called promo. This is clearly a
separate functionality. So the choice to move this into an area is a good one. As
we can see here, there's now a folder called Areas in the root of the application.
And inside, we have a promo subfolder. In that folder, we have the typical folder
structure that we normally have in an ASP. NET Core MVC application, such as
Controllers, View, and Models. The promo functionality is therefore, I'd say,
contained within the promo area. Do keep in mind that all the code in such an area,
such as the models, is still usable outside of the Promo folder. It is just C#, and
code within the area folders gets compiled just like the other code. We can thus
still use namespaces to use the code from other locations within our code base. Now
as mentioned, to reach the functionality within the area subfolder, we need to make
some changes to the routes again. And I'm using the MapRoute method here again. For
the template, notice that I now have defined the template starting with
area:exists. This is now a segment that I've added which will be the name of the
area that we want to reach. The exists constraint allows us to make sure that only
areas that have been defined in the application will be matched. Since this route
is adding support for areas, it will typically need to be defined at the top of the
routing table, less specific routes, so the ones that do not define the area should
go below this one. Next to making the above changes to the area, we also need to
add an extra attribute on the controllers within an area. This is basically how an
area is defined within the application. As we can see on the slide, we have the
HomeController, which is now part of the promo area. But to make it part of that
area, we need to also add the area attribute on top of the controller.

Demo: Adding the Promo Area to the Site


In the next demo, we will explore the promo area and look at all the items we need
to add or create in order to support this area. In this demo, we are going to take
a look at how areas work within ASP. NET Core MVC. As we can see in the top
navigation, there's now a link to Promotions, and promotions is actually an area
that I've defined within the application. It also defines a view where I can see
the pies which are currently in promotion. Let's take a look at the code for just a
second. In the solution, I've now added the Areas folder, and inside of that Areas
folder, I've defined one single area which is the promo area. You can imagine it
has been a block of functionality. In this case, it contains everything that has to
do with the promotions within Bethany's Pie Shop. So it has its own controller,
optionally it has its own models, and it will also define its own views. So notice
the name of the controller, it's HomeController, and the application itself also
already has a HomeController, so using areas it becomes possible to have two
controllers with the same name. Let's take a look at the HomeController. The first
thing that you'll notice is that this controller has an attribute area defined on
it, and as parameter we defined the name of the area so that it will be promo in
our case. For the rest this is just a plain controller that is using, however,
models which are defined on the application level, so not within the area itself.
Also, very similarly, ASP. NET Core MVC will search for views in the corresponding
folder. So we have an Index method here in my controller, and it will search for
Views, Home, Index, which is just a plain ASP. NET Core MVC view. However, there's
one thing that I want you to notice here. Notice that I have a copy of the
_ViewImports file. The _ViewImports file is used to import items within my view
code. In this case, I'm importing a couple of namespaces, so BethanysPieShop.
Models, as well as ViewModels, and I'm also specifying where a search should be
conducted for my tag helpers. In this case, that's my own BethanysPieShop.
TagHelpers namespace and the general Microsoft. AspNetCore. Mvc. TagHelpers
namespace. If you don't add this _ViewImports file, tag helpers, such as the asp-
controller, asp-action, and so on, will not be recognized. Because they are by
default imported using the ViewImports file within the general Views folder. Now
let's take a look at the _Layout file, and notice here I have an extra li item
where I now have used the asp-area tag helper, and I've defined Promo. So this
Promo is actually the link to the Promo defined here on the view controller. This
is how ASP. NET Core knows that this is the area that we are referring to. Now one
more thing needs to be added here, and that's in the Startup file, I need to define
a new route that also includes support for areas. As we can see, I've added this
route as the first route, which is quite normal, because the area around is more
specific, I need to add the more specific routes at the top. So I'm first going to
check if the area segment is there, and then I use the HomeController and the Index
method on that HomeController as a default. This allows me to go to /Promo, and
then it will automatically direct me to the HomeController and the Index action
method. Let's take a look at the running application once more, and let me click on
the Contact us button for now, and automatically we are getting a 404 Not Found. If
you take a look here in the address bar, we're now navigating to /Promor/Contact,
which is, in fact, quite logical. We are still within the realm of the area, let's
say. So I need to make another change in my _Layout file to make this work
correctly again. If you take a look at the link that is being generated here for
the Contact us page, I need to specify that this is not living within an area. So,
I'm going to use the asp-area, and I'm going to set it to the empty string. And if
you run the application now again, let's refresh the page, they can contact us, and
now everything is working fine again, because we're now saying that we do not want
to navigate to an area. That's how we work with areas within our ASP. NET Core MVC
applications.

Managing Outgoing Links


In the last topic for this module, we are going to look at outgoing links in
combination with the routing engine. I've mentioned this already at the beginning
of the module. When we think of routing, we think of matching a request with the
correct action on a controller. While that is probably where you will be using the
routing engine mostly, it has another important task, and that is the generation of
outgoing links or outgoing URLs. With this, I mean the links that will be generated
as part of the outgoing HTML that is sent to the client. This can include the links
in the navigation menu of the application, for example. It's important that these
are created in the correct way, following the same rules, since it will be these
that trigger the new request when user taps them. Just a small reminder, although
it may seem easy to just hard code these in the view code, it's not going to be a
good idea. When the routes are only slightly changed, this may cause some links to
stop working. By letting both incoming and outgoing links to be generated with one
and the same block of code, so the routing engine, we won't be getting any errors
when a change is made. Let's take a look at how this works then. At the base of URL
generation is the IUrlHelper interface. We can easily work with this interface
using the URL property, which is available on just any controller, View, and even
ViewComponent that we create. Take a look at the code here, which is a snippet of
the PieController. Like every controller, it inherits on the base controller class,
and like I just said, therefore it has the URL property which is of type
IUrlHelper. We can now use this to generate a dynamic link. So, a non-hard-coded
link to another action, in this case. Using the action method and passing along the
action I want to target, a link will be generated to the SomeAction method. Since
no controller is specified, the current controller, so PieController, is assumed.
The link will be generated based on the routes that are defined within the
application. Now how does ASP. NET Core MVC generate the link for us then? First,
ASP. NET Core knows what the current request is, so it also has the route values of
the current request. Next, we are passing to the URL action what the target
controller and target action will be. Using the template, this will result in the
link /Pie/SomeAction to be generated for us. All required parameters in the
template need to be given a value that matches any specified constraint for the
link generation to succeed. If not all values can be found for a given template,
the next template will be tried, and ASP. NET Core MVC will do this until it finds
a match or until all templates have been tried for a match. If no match can be
found at the end, an empty href will be generated. Of course, we can generate links
using code, but also directly from the view code can we ask ASP. NET to generate a
link. Optionally, for example, to another controller. Take a look at the snippet
you see here. We have an anchor tag with the asp-action and asp-controller
attribute on it. This will be using tag helpers to generate the link to navigate to
the List action of the PieController. Again, ASP. NET Core MVC will use a defined
route to create the correct link, and if this were changed at some point, the
generated link will also be updated. That is why we don't want hard-coded links
inside of our views. Url-action will work as we've seen with conventional routing.
But it will also work with attribute-based routing. However, it does work a bit
differently here. In this case, the route value for the controller and the action
are going to be used to look up which template should be used. Take a look at the
example here. We have again the PieController, and I have an Index action method in
which a link needs to be generated the destination action in the same controller.
The latter has an attribute defined on it, foo/bar/SomeAction. Since that's the URL
that we'll need to use to invoke this action, the generated URL should in fact be
the same, right? In order to fix that, ASP. NET Core MVC will basically build a
lookup table for all actions that have been defined with an attribute on top of it.
Based on the controller and the action that we need, the URL will be generated, so
in this case, foo/bar/SomeAction. Of course, we won't always be generating a link
to an action method on the same controller. Very often we won't, in fact. To allow
for this, the Url. Action method has quite some overloads, and one of them allows
us to specify the action and the controller name as you can see here. We can also
with this overload pass parameters; in this case, I'm passing the id parameter.
Very often, what an action method will do is basically returning a URL as part of
the action result. Imagine that the user has clicked on the logout link on our
site. We then need to perform an action, and afterwards return a URL to redirect
the user in this case back to the homepage. And we can do that using an action
result. In the code you see here on the slide, I'm using one of the many methods
defined on the base controller. In this case, the RedirectToAction, which accepts
the action and the controller to which I want to point the user after completing
this action.

Demo: Working with Outgoing URLs


In the last demo of this module, we are going to look at the generation of outgoing
links in Bethany's Pie Shop. Although it may seem simple, ASP. NET Core is doing a
lot of the work to generate the correct links in the HTML that's being shown to the
user. If you take, for example, at the navigation bar at the top of the screen, the
links that are being generated are effectively based on the routes that we have
defined in the application. So, for example, the Contact us link or the Promotions
link for that same matter, are the result of the ASP. NET Core MVC generating an
outgoing link for us, based on the values that we defined for the asp-controller,
asp-action, and asp-area tag helpers. So effectively we specify these values, and
ASP. NET Core MVC is going to work with the routes that we have defined in the
route table within our ASP. NET Core MVC application. Now there are also other
attributes available that we can use to define a route. In the code that you see
here, I've not only used the controller action and route id, but I've also used the
asp-protocol tag helper, the asp-host tag helper, and the asp-fragment tag helper.
So the outgoing link that is going to be generated is going to be fully qualified.
So here's that pie of the week, and as we can see at the bottom of the screen, this
is going to bethanyspieshop. com/Pie/Details/30#details. So it is the fragment that
we've pointed it to that was the result of this asp-fragment attribute here. Also
from code, we can ask ASP. NET Core MVC to generate a link for us. For example,
here I'm using the Url. Action, and I specify as parameters the action, the
controller, and then optionally the values that we want to pass along. This again
is going to use the built-in routes of our application to generate the correct
link. If you navigate to /Home/TestUrl, I'm going to hit the breakpoint here, and
we're going to see that indeed /Pie/Details/1 is going to be generated for us to do
whatever we want with it. So this indeed used this particular route to generate
that outgoing URL. That's how routing is constantly used to build up the outgoing
URLs.

Summary
And we've reached the end of another module in this course, a module in which we
looked at the many options of the routing engine that you are able to use in your
applications. We've covered attribute-based routing, which offers us fine-grained
control over the routes in the application. We've then also looked at using areas,
which has two main advantages. The first one is the manageability of the site's
code base, and the second one was the fact that it can also help us with making
URLs for the site more meaningful. Finally, we've looked at how the routing engine
will also kick in to generate links that become part of the generated HTML. Now in
the next module, we are going to learn how we can write unit tests for our
enterprise ASP. NET Core MVC application. I hope to see you there as well.

Creating Unit Tests to Support Business Changes Without Fear


Module Introduction
Hello, and welcome to another module of the Build an Enterprise Application with
ASP. NET Core MVC course here on Pluralsight. My name is Gill Cleeren, and you can
contact me via Twitter via @gillcleeren. Now, this module should be a way to give
ourselves some better sleep during the night. Now I won't be giving you any
sleeping tips; I instead will be discussing how we can harness our ASP. NET Core
MVC applications with some unit tests, so that we can make changes to our code
without the constant fear of breaking things, and thus, a better night's sleep. Now
let's see how we can do that in ASP. NET Core MVC. A good tradition is to start the
module with a brief overview of what we will be doing in this course. And the list
is actually rather concise for this one. I'll start with a brief overview of what
unit tests are and why you need to add them to your code base in basically just any
application, and that of course includes Bethany's Pie Shop. Now the meat of this
module will actually come after that when we will be writing unit tests for the
controllers of the application. Now in this context, we will also be using the mock
framework to create mocks for our unit tests.

Why You Need Unit Tests


Now I said in the beginning that this module will actually help us as developers to
get some more ease of mind. Well, in fact, our good friend Bethany is also a bit
worried. She has been a regular visitor of our office lately, and she is, as you
know, quite tech savvy. She has picked up that it is, in fact, rather dangerous
that we are making a lot of changes to her site, and chances are that at some point
things will break. So for a change, she has come to the office yet once again to
check with our development team and ask them if the frequent changes that she has
been asking for will cause any issues in her site. Now the good news, as mentioned,
is that we can bring Bethany's mind to calm down by creating some unit tests for
the code base we currently have. Now before I show you how you can create unit
tests, let's take a minute to see why we actually need to add unit tests, well, in
just about any application, and definitely in your next ASP. NET Core MVC
enterprise application. Most of you probably already know what a unit test is. Now,
to be complete in this course, a good definition is in place. The definition that
you can see here on the slide is by Roy Osherove, who has written the excellent
book "The Art of Unit Testing. " He defines a unit test as an automated piece of
code that invokes a unit of work in the system and then checks a single assumption
about the behavior of that unit of work, a nice definition, if you ask me, that
captures nicely the essence of writing unit tests. Now if we analyze in a bit more
detail the what and why of unit test, we can say that the unit test will typically
test a block of code, so basically the unit we are testing. In many cases, this
will be a method that's typically the smallest item that we'll test. Unit tests, in
most cases, will test the public API of a class, and will often not be bothered,
let's say, by the inner workings, so the private methods. However, if we have a lot
of functionality that we are willing to test, we can also write a unit test on the
private methods. In any case, unit tests should run in isolation and be independent
of other code. If you want to achieve this, we typically will have to remove all
dependencies from the code we are testing. This will typically then boil down to
replacing these dependencies with mock versions that we have while writing the unit
test under control. And we'll be doing that in the demos later in this module as
well. Unit tests should also return consistent results. This means that if we run
the same test several times, we should be getting the same result every time.
Again, both the implementations can help with this, instead of using, for example,
a real database for running unit tests. Most of the time, we will also run unit
tests using a test runner. Visual Studio has the built-in ability to do this, but
other test runners are available as well that can help in the execution of the
battery of unit tests. And of course, since well-tested application will contain
quite a number of tests, unit tests need to run fast as well. If that wouldn't be
the case, developers wouldn't be writing unit tests anymore, since it would be too
time consuming. So in the end, what will adding unit tests give us then? It will
certainly help us with the discovery of bugs. I think that is a given. Not only
will we more easily find bugs in the code base, but we will also be able to make
changes to the code more easily, and be able to verify that the changes we have
made didn't break anything. If the unit test after the change keeps giving us the
same result, chances are high that the change has been implemented correctly.
Overall, unit tests will greatly help with the improvement of the code quality. And
finally, a well-written set of unit tests where the names of the test methods
describe what test we will be doing will serve as a form of documentation of the
code for new developers, for example, who are joining the team. In the context of
unit tests, you'll often see the AAA approach being used. Now these three As stand
for arrange, act, and assert. Most unit tests will follow this approach. First, we
will need to prepare some things, so basically the setup for the unit test. That's
typically done in the arrange block. Then, when everything is ready, we can execute
the code that we want to test by invoking it within the act block. Finally, the
assert block will then be used to verify the result of executing the code under
test. We will assert if the results are what we were expecting. Here on the slide,
we can see a very simple unit test. First, take a look at the name of the unit
test. The name really describes what this test will be doing. Remember that I said
that a unit test should be seen as a form of documentation of the code? Well, if we
follow this approach closely, the unit test name describes what the invoked code
will do, and that is a good start. Then, in the arrange block, we are setting
things up, so ready for test. In this case, I'm creating here a new pie. Next, in
the act block, I perform the actual functionality. Here I am doing a very simple
test, which does nothing more than setting or updating the value of the price
property. After that, we can perform the assertion. We can verify that indeed the
value of the price of the pie is equal to what we were expecting it to be. In most
unit tests, you'll see one assertion per test; however, you will also see more than
one assertion being done in one single test.

Writing Unit Tests


Now that I hope that I've convinced you that unit tests are a very useful thing,
and that you have a basic understanding of the structure of a unit test, let's see
how we can add unit tests to our ASP. NET Core MVC application. Starting with
Visual Studio 2017, there are two types of unit test projects which are supported
for. NET Core projects. A project template exists for MSTest, and another one for
xUnit. For the demos in this module, we will use the xUnit test project template.

Demo: Creating Unit Tests


Now it's time to start creating unit tests ourselves. In this demo, we will create
a unit test for a controller. We've seen that it should be possible to run unit
tests in isolation, so we'll have to create some mocks as well. And for this
purpose, I'll be using the Moq framework. We will also be looking at how we can
parameterize our unit tests. In this demo, we are going to take a look at how we
can work with unit tests in ASP. NET Core MVC. Now to start out with, I've added
this test solution folder, and I've added an xUnit Test Project. That's the one
that I'll be using here in this demo. Now first let me show you a couple of sample
tests. A unit test class is just a plain class, and on the actual unit test
methods, I've added the Fact attribute. Adding the Fact attribute will actually
cause Visual Studio to pick up this as being a unit test method. A typical unit
test will contain an arrange, an act, and an assert block. As we can see here in
this SampleTests class, I have a very simple unit test that indeed follows this
pattern. The unit test is simply going to check if we can update the price of a
pie. As we can see, the name describes what this unit test will do, and hence, a
good battery of unit tests is a good set of documentation for your application. So
we can update pie price, we'll first in the arrange block create a new pie. That's
basically the setup of the test. Then I'm going to act, I'm going to test
something. In this case, I'm going to specify the price of the pie. And then in the
assert block, I'll typically add one or more assertions. In this case, I'm going to
check if the price is indeed equal to the price I've just specified. And there's
another simple test here that you can take a look at at your own pace. And the main
goal of this demo is showing you some more realistic unit tests. There's a class
here called PieManagementControllerTests. The name already gives away what this
class will contain. It contains tests for the PieManagementController. So the
PieManagementController is a class that allowed me to add pies, edit pies in bulk,
edit pies, and so on, so it is the controller that contains all the action methods
to work with pies within the administration part of my site. That's typically
something I want to unit test. First let's take a look at the dependencies of the
PieManagementController. As you can see, it is dependent on the pieRepostiry and
the categoryRepository. An IPieRepository and an ICategoryRepository are being
injected into this controller using the dependency injection system of ASP. NET
Core MVC by default. When we want to unit test this controller, we are effectively
going to have to mock out these repositories, because they are dependencies. We
want to test the controller in isolation, and we want to have full control over
what we inject, in this case, those two repositories. That's why in my unit test,
I'm going to inject a mock version of these two repositories, as we'll see in just
a second. I have quite a few methods here, such as the AddPie, that I'm going to be
unit testing. All right, let's now take a look at the PieManagementControllerTests
class. It's the class that contains my unit tests. Again, I have a couple of
methods in here, all attributed with the Fact attribute, meaning that these are
unit tests. The first thing I'll want to unit test is my Index method, and I want
to see that it will return a view result that contains all the pies. It's this
method here that I want to unit test. As you can see, this one has a dependency on
pieRepository. So I'll need a mock version of the repository. In the model
directory, I have created a RepositoryMocks class. This one will be using the Moq
framework, as you can see here, in the NuGet, Dependencies, a reference to the Moq
package. So the RepositoryMocks class contains a couple of methods, such as the
GetPie repository and GetCategory repository that will return me a mock version of
the pie repository. If we take a look at the GetPieRepository method, we can see
that first I'm building up a list of pies. I then create a mock implementation of
the IPieRepository, and I'm using the Setup method that specifies that when the
pies collection is going to be invoked that it will return this hard-coded list of
pies. I'm also specifying that when the GetPieById method is invoked, I will return
the pie with id 0, and then I'll return the mockPieRepository. So now I have a mock
implementation of the IPieRepository of which I have full control within my unit
test, so I can use that to make assertions on. So now back here unit test method,
in the arrange block I'm going to use my just created mocks for the category and
the pie repository. Then, I'm instantiating the PieManagementController, passing in
the mock version of the pie and the category repository, using the Object method,
which is going to expose the mocked object instance. In the act block, I'm then
going to invoke what I want to unit test, in this case, the Index method. This is
going to return me a result, and that result will be of type ViewResult. That's
indeed what my Index method is going to return. Then I'm going to make some
assertions. I'm going to check if the result is indeed of type ViewResult. I'm also
going to verify that two types basically are going to be the same. I'm going to
check that the viewResult. ViewData. Model, the model of my returned index view, is
indeed of type IEnumerable in pie, and if that is true, then I'm also going to make
an assertion to check if the pies count is indeed 10, and 10 was the number of pies
I hard-coded here inside of my RepositoryMocks class. This is why it's important to
have full control over that mock data. I need to know up front how many items there
are going to be, so that in my assertion of my unit test, I can make these
assumptions. Let's take a look at another unit test. In this case, I'm going to be
testing the AddPie method. Let's first take a look at the AddPie method in the
PieManagementController. I'm going to be checking the happy path here. So I'm going
to insert a valid pieEditViewModel containing basically a valid pie. If that's the
case, I'm going to be redirecting to the Index method. Let's take a look at the
unit test here. So I'm going to create a new pieEditViewModel; that is what the
AddPie method is expecting. I'm going to be using my mock repository here again,
and I'm going to ask it for the pie with id1, which is a valid pie. I set that as
the pie property for the pieEditViewModel, and I also specified a CategoryId, just
to be on the safe side so that this is indeed a valid pie. I also instantiate again
the PieManagementController, passing in my mock objects. I then invoke the AddPie
method, as we can see here, and then I'm going to check the result that is going to
be returned is of type redirectToActionResult. That's the one I was hoping to be
arriving at. Finally, I also check that the action name of the
redirectToActionResult is Index. Then I can be 100% sure that I followed this path.
When I insert a valid pie, well, then this code execution path has been covered.
What now if I inject an InvalidPieViewModel? For example, what I've done here is
I've created another pie for which the PieOfTheWeek is set to true, and the InStock
is set to false. If you take a look at the business rules that I have manually
created here, I specified that if the pie of the week is true and the pie is not in
stock, well, this will add a model error. If that is the case, the model state is
not going to be valid, and we should be arriving over here. We should be returning
the same view, passing in that same pieEditViewModel again. Let's unit test that.
So in the arrange, I've specified indeed this invalid state for the pie. Then I do
all the things that I've done before, but now in the assert I'm going to check that
the return type is of type ViewResult. The model shouldn't be null, and the view
name should be empty. If that is the case, well, then I have indeed followed this
code execution path, so I know that when I'm passing in an invalid pie, I will
arrive over here. Now it's very well possible that I want to maybe inject a couple
of values and I don't want to write a different unit test for all of these values.
And it's possible to pass in parameters to our unit tests. That's what I'm doing
here. Notice that I've now added the Theory attribute, and then I specified
InelineData 0 and -10. Also note now that my unit test now has a parameter price,
and that will be set to 0 and then -10, so I'm going to loop, I'm going to execute,
basically, this unit test a couple of times, 2 times in this case, first with price
0, then with price -10. I'm setting the price of the pie over here, and then I'm
going to do the same unit test again, and I'm going to check indeed again that I
will arrive over here, that I'm following this code execution path here. So as we
can see, it's quite a lot of coding to test just a couple of controller methods.
Well, now we've seen all these unit tests, let us try to run them. I'm going to go
to my Test Explorer, and I'm going to run all my tests. And success, we're getting
a green light on all of these unit tests. So this is how we can unit test
controller methods in ASP. NET Core MVC.

Summary
With that, we have reached the end of another module in this course. I hope you
have again learned a lot. Let us summarize what we have seen in this module
together. We have started this module with a short overview of what unit testing is
all about, and where it can help us with basically building a safety net around our
code. We've then looked at how we can write unit tests using xUnit. Achievement
unlocked. We've added unit tests to our code base. In the next module, we'll take a
look at how we can get information from our running site using logging and other
diagnostic tools. I hope you to see you there again as well! Thanks for watching.

Diagnosing Runtime Application Issues


Module Introduction
Hello there, and welcome to another module of the Building an Enterprise
Application with ASP. NET Core MVC. I'm, of course, still Gill Cleeren, and if you
have any questions about this module, please reach out to me on Twitter via
@gillcleeren, or contact me via the discussion board here on the Pluralsight
website. In the last module, we have seen how we can create a more robust code base
by adding unit tests to our code. Now when the application is running in
production, there still will be things that go wrong. Of course, then it's harder
to know since the exceptions may have occurred while other people were using the
site when the site was on the heavy load, and so on and so on. In that case, it's
vital that we instrument our site's code so that we as developers can still see
what is going wrong. In this module, we will explore the different options that we
as developers are getting with ASP. NET Core to diagnose application runtime
issues. Let's again start the module by exploring what we will be looking at in
this module. We'll start by taking a look at the diagnostics middleware package, a
separate package from ASP. NET Core that helps us on our way with quite a few
features to configure the runtime behavior of our application. After that, we will
dive deep in probably the most common way of knowing what went wrong at runtime,
and that is, of course, logging. ASP. NET Core comes with several options of doing
logging, and knowing which option might be best for what situation will be vital
when creating an enterprise application. Next, we'll look at filters. Filters can
also be used to instrument code, such as the code in our controls, so that we from
there can handle exceptions and so on. Finally, we'll involve Azure. Azure has a
great way of allowing us to diagnose runtime information using something called
Azure Application Insights. In this path, we'll explore how we can add Azure
Application Insights to our application and use it to get information about what
went wrong with the application at runtime.

Diagnostics Middleware
As said, we'll start the module by exploring the diagnostics middleware. We have
already encountered middleware components before. We can existing middleware
components, or we can even create our own. ASP. NET Core comes with a number of
built-in middleware components, which are basically available by default without us
having to do anything. These include authentication, routing, session support, and
diagnostics. Let's take a look at the diagnostics middleware package to start the
module. As the name implies, the diagnostics middleware will enable ASP. NET Core
developers to get diagnostic information about the running application. It's
basically a feature targeted at developers, and users will typically not get any
benefit from this. Of course, apart from the fact that the developer will know what
went wrong, and can thus improve the application. Using the built-in diagnostics,
developers will also get away to handle exceptions that happened in the
application. As mentioned, we don't need to do add a package to the configuration
ourselves. The diagnostics package, Microsoft. AspNetCore. Diagnostics, is already
added by default in a new ASP. NET Core application. So what exactly can we do with
this package then? First, the UseDeveloperExceptionPage middleware will give
developers information about exceptions that happened when the application was
running. Typically these will be used when we are using the development
environment, which is the default where we are starting a new application. Without
calling this method in the configuration of the application, when an exception is
occurring, we will see the following. Indeed, nothing. No crash information is
shown to the developer, so we don't know what happened. When we instead call the
UseDeveloperExceptionPage, we will get information about the exception which has
occurred. The page that we are seeing here can be seen as a replacement for the
yellow screen of death that ASP. NET applications showed previously when something
went wrong during the execution. Of course, as you can see from the screenshot
here, vital information about the application is being shown here. This is
developer information, so this should never be shown to end users. The
UseStatusCodePages can also be added to the execution pipeline. This can be used to
handle status codes between 400 and 600, which are being returned from the server,
that is. If that is the case, a generic error page showing the status will be
shown. The UseExceptionHandler middleware is a very nice one. When we are running
the application in the development environment, we won't see anything. But if we
are running the application in staging or production and an exception occurs, we
will see a nice error page. It is of course not showing any development information
about the application. When we add it to the Configure method in our application,
we can pass it which page we want to show if something went wrong during the
execution of the application. Finally, the UseWelcomePage middleware can be used to
show a generic page to welcome the user, which can be, for example, done while
we're still building the site. If the end user tries to browse to a different page,
the request will be re-routed to this welcome page. Again, we can specify which
page we want that to be.

Demo: Using the Different Diagnostics Options in Your Site


Let's go to the first demo of this module and see how we can use the diagnostics
package in our application. In the first demo of this module, I'm going to show you
some of the diagnostic options that we are getting with ASP. NET Core MVC. Now to
add support for the diagnostic features that we will see, we need to add a package
reference to a package, the Microsoft. Extensions. Logging. Filter package, and you
can see here that I've added that in my csproj file, and you can add that directly
here or also via NuGet. Now to add support for the diagnostic packages, I will go
to the Startup class, and more specifically, I will be in my Configure method. And
the first one that we'll look at is the UseWelcomePage, and the UseWelcomePage,
well, it does exactly what the name is indicating. It'll show a placeholder page.
Let's run the application. As we can see, we're now redirected to a placeholder
page that we can change, and any request for just any other URL in our site will
all be redirected to this same welcome page, and that's because the middleware was
injected in the pipeline, and that will intercept all requests to other pages.
Other diagnostic packages that we can include is the UseDeveloperExceptionPage and
the UseStatusCodePages. The UseDeveloperExceptionPage is basically a replacement
for the yellow screen of death page that we had with previous versions of ASP. NET.
We will then see diagnostic information about what went wrong. UseStatusCodePages
will actually show us the HTTP response for HTTP statuses between 400 and 599. Now
these are, of course, settings I only want to have applied when my application is
running in development mode. And that is why I have surrounded them with the
environment check to see if we are currently in development mode. If that is not
the case, well then, I'll use another diagnostic package called the
UseExceptionHandler, and I'm pointing that to /AppException. Now this will actually
redirect us to the AppExceptionController, which is just a basic controller that
will simply show a view that is over here, and that will simply show an error page.
So this is what you will see in production. Just as a small reminder, we can
control the environment setting by going to the project properties, and over here
we'll see the environment variables which are currently set, and we can see that
one special variable is here called ASPNETCORE_ENVIRONMENT, and it is currently set
to Development. If we now go to the HomeController, and throw some new exception,
then we'll see the diagnostics packages in action. So as you can see, I'm now
throwing an exception in the Index action method of the HomeController. Let's now
run the application, but let's not forget to remove that UseWelcomePage again, hit
F5, and we'll take a look at the result. So in here the exception is being thrown,
and indeed we now see an exception page that shows us the details. Of course, this
is only to be used when the application is running in development mode. If it
switched the application properties to production, hit Save, and run the
application once more. We will hit that same exception, but now the user is
redirected to the just created exception page.

Logging Middleware
Our good friend Bethany has returned again to our office with a new question. She
has been receiving some complaints from her customers that seem to be getting some
errors while using her site. Of course, we all know users are saying we're getting
an error, but we typically do not get any more information. Bethany is a bit
worried about this, so she wants to know what we as developers can do about a
problem. Luckily, ASP. NET Core MVC offers us quite a lot of ways to perform
logging in our site, making it possible to more easily see what's going on with the
application at runtime and hopefully find the cause of the error more easily. Let
us explore the logging middleware in our ASP. NET Core applications to get runtime
information. In many cases, that's the only way that we as developers can know what
went wrong when the user got the error he or she was referring to. When we look at
the ASP. NET Core platform in its current state, there are, in fact, three ways of
logging built-in. EventSource is the first one, and it's been around for quite some
time, meaning it wasn't added for just ASP. NET Core. It was already available
since ASP. NET 4. 5. The data that we're getting back is strongly typed, and the
EventSource is therefore also typically used in combination with the logging of the
operating system. ILogger is a second way of doing logging in ASP. NET Core. It's
very much linked with ASP. NET Core, and it will be the one that we typically use
in combination with ASP. NET Core applications. It will typically be added to our
application by adding an ILogger instance using dependency injection, and we'll see
that very soon in the upcoming slides and demos. The third and final option to
perform logging in our ASP. NET Core applications is using DiagnosticSource, which
is very similar to EventSource. Both ILogger and DiagnosticSource are used
internally by ASP. NET Core as well. Now we won't be looking in more detail to this
type of logging in this course. So as many of you probably have already understood
from the previous slide, ILogger is for most logging purposes going to be the way
forward in our ASP. NET Core applications. We'll see in a minute how we can use
this logging system. This logging API is actually based on the system of logging
providers. ASP. NET Core comes with quite a number of built-in providers, which
we'll look at in the next slide. Secondly, it's an extension point, meaning that we
can install other providers for other destinations. There are open source providers
available, and we can also write our own. Now as I said, ASP. NET Core comes with a
number of logging providers built into the platform. The first one, and probably
the most basic one, is a console provider. The relevant package which is built in
by default again is the Microsoft. Extensions. Logging. Console package, and as the
name implies, it will send log information to the console. The debug logging
provider will allow us to write logging information to the outputs using the
system. diagnostics. debug class. We'll see this one in the upcoming demo. The
EventSource provider can be used to implement event tracing. This one only works
with ASP. NET Core 1. 1 or higher. The EventLog provider, available to the
Microsoft. Extensions. Logging. EventLog package, will allow us to send logging
information to the Windows Event Log. The TraceSource provider will allow us to the
use the System. Diagnostic. TraceSource library to perform logging. This is,
however, a bit of a special case. The application has to run on the full. NET
framework instead of. NET Core. Finally, the Azure App Service provider allows us
to log directly to an Azure App Service or an Azure Storage Account. It can then,
for example, send text files to the filesystem of an Azure App Service, or an Azure
Storage Account. This provider also is only available for ASP. NET Core
applications running. NET Core 1. 1 or higher. Let's now take a look at how we can
work with that ILogger interface. First, as always in ASP. NET Core, we need to
start by adding some configuration in our Startup class. More specifically, in the
Configure method. Through the Configure method, we pass the ILoggerFactory, which
will be provided by the ASP. NET Core dependency injection system. Once we have
that, we can continue by calling the extension method for the provider we want to
add. In the code that you see here on the slide, we are adding the console
provider, as well as the debug provider. I'm also passing the LogLevel, and I'll
talk about that in just a minute. Once we have configured logging, we of course
need to start using it from our code. Here we see some sample code of a controller
of the application. Notice at first I'm creating a private field for ILogger
instance. I'm then using the dependency injection system again, so that in my
controller I now will have an instance of the logger. Note that the logger I'm
requesting here is actually an ILogger in HomeController. The fact that I passed
the HomeController type here will result in the fact that a HomeController will be
the category for logging here. I'll explain categories in just a second. Keep that
in mind for now. Once I have the ILogger instance, we are ready to start logging. I
can now call methods on the logger instance. For example, here I'm going to log
information on the logger to actually log something. Now we've seen in a previous
slide that we were using the log information method. In fact, by calling this
method, I'm already going to specify the log level. When we're writing a log, we
need to specify this level. Now, several levels exist. We have the trace, the
debug, the information, the warning, the error, and critical. Depending on what we
are willing to log, we need to select the correct level. If you, for example, just
want to log that something went successfully, we should just be using information.
If we want to log that the time out of the database has occurred and thus that the
application is down, we can use the critical level. Next to using the level for
logging, other information can be added when using logging as well. The log
category is basically a grouping mechanism that we can use to group logged
information. A group is, in fact, nothing more than a string that we can create
ourselves. Typically, however, log categories are the fully qualified name of the
class for where we are performing the logging. The log event ID is, like the name
implies, an ID that we can also specify when writing a log. It's typically used for
grouping some logging events together. Finally, the log format string is a string
that contains parameters that we also want to include in the logged message. Very
often, this is a suiting combination with structured logging, which we'll look at
later in this module.

Demo: Adding Logging to Your Site


Now that we have seen how logging works in ASP. NET Core, we'll head back over to
the demo, and we'll add logging information to our site, so that we'll be able to
see hopefully where the errors that Bethany's users were complaining are coming
from. Let us now take a look at the logging features that we are getting with ASP.
NET Core MVC, and how they can help us to get a log information from the production
version of our application. To add support for logging, I've added another package
reference, the Microsoft. Extensions. Logging. Debug package, and it's currently at
version 1. 1. 2. Now first I'll need to configure logging in my application, and
just as always, configuration will be done in the Configure method of my Startup
class. And we can see, I'm getting in an ILoggerFactory, so this one will be
injected through the dependency injection system. I can then use the ILoggerFactory
to configure the logging I want to use. As we can see here, I've used, well, some
basic logging support. I've added support for console output and debug output. The
parameter, so LogLevel. Debug, in the case that I'll want to log everything that is
marked with debug or worse, so basically everything that has a higher gravity in
terms of log level. By using AddConsole and AddDebug, I will see development output
in my log information. Now this is just configuring logging, so now I can use it
within my application. For example, let's go to the HomeController. Here I'm
passing in to my constructor of my controller an ILogger, and that ILogger is typed
in HomeController. By default, the logs that will be written will be categorized
under the type that I've passed, so that will in this case be HomeController. So
that basically allows me to group all logging information based on the category, so
the type that I've passed here. So this will be injected into my controller again
using dependency injection. Nothing has really changed here. So now I have my
logger, I can now use it to log information. Here I'm using the _logger.
LogInformation. In the line you see highlighted here, I'm using the _logger.
LogInformation. This will then log with the level information. The first parameter
that this is accepting is, in this case, the EventId. The EventId is an id that
I've given myself to associate this log with. Again, it's some way to filter your
logs afterwards. The second value that I've added here is the message I really want
to log to the output. Let's take a look at the LogEventIds, because I've created it
myself. Let's do a go to definition here, and as you can see, it's a class that
contains some const int values that I use to categorize, or to give an id to be
more precise, to my logs. Also, for example, we can specify that we are interested
to know in the logs when we have changed the language. So I'm using here again
_logger. LogInformation with anther message. Let's run the application and see the
log output. So we started the application, let's go back to Visual Studio. Now when
we look in the output window here, we'll find the log information we were looking
for. Now it's quite difficult to find that here, so let me copy that to Notepad,
and now we are actually looking for loading home page, and it seems that indeed we
have logged level information loading home page, and the category is automatically
set to BethanysPieShop. Controllers. HomeController. And that's because I've used
HomeController as the type for the log here. Now when we change in the Startup, the
level that we're interested in, for example, let's say that we are only interested
in Critical logs, and we then still only log information here, well, then we
shouldn't be seeing this loading home page entry. Let's try that. So the page has
loaded, let's return to Visual Studio. Let's see what logs have been outputting.
Let's search for loading home page, and the text cannot be found. So through the
log levels, we can indicate what types of log information we're interested in. And
I've got to set it back to debug for now. In the code that you can download with
this course, you'll find some more log statements. For example, in the
PieController, I'm using the same logger, and in this case, I'm using the LogDebug
to log information about a pie that was being searched with an id that cannot be
found. And instead of just logging everything plainly to the console and to debug,
I can also apply a filter. In line of code that you can see here, I'm using the
AddDebug method, and I'm passing a filter that will check that the string that is
going to be outputted to contain HomeController, and that the LogLevel is Trace or
higher. I can also use the. WithFilter extension method here. This method will
basically apply for all providers that are registered with the logger factory, and
it's basically going to accept some filter settings, filter logger settings, to be
more precise. In this case, I'll only log warnings that contain Microsoft, warnings
that contain system, or debug messages that contain HomeController. This gives us
more fine-grained control to filter log messages.

Using Third-party Logging Providers and Serilog


As said earlier in the module, ASP. NET Core uses providers to perform the actual
physical part of the logging. We've seen in the previous demo that we can use the
built-in providers to cover a wide range of scenarios already; however, as
mentioned before, ASP. NET Core's logging system allows for the use of custom
providers that we can plug into ASP. NET Core and thus extend on the logging
features. Some of the more commonly used third-party logging providers include
elmah, NLog, and Serilog. All of these work perfectly together with the ILogger
logging system of ASP. NET Core MVC. Let's take a look at how we can use one of
these third-party loggers, Serilog. Serilog is very commonly used because of its
support for structured logging or semantic logging. Structured logging is getting
more and more traction nowadays. Basically it comes down to using a more defined
format of the logs we are creating. By default, logs are nothing more than
unstructured data. Using the concept of structured logging, we are indeed bringing
a structure into this, making it much easier to extract the values we need from the
logs we're getting in. Now, to use Serilog, as always, we need to add the correct
package, which I'll show you this time in the upcoming demo. Once we've done that,
we need to configure Serilog in a Startup class again, and here you can see a
sample from the configuration of Serilog.

Demo: Adding Support for Serilog


Now that we've seen Serilog, let's return to our demo and understand how we can
work with it to bring structured logging into our application. This will make it
easier to extract the correct information from the application's log files
afterwards. In this demo, we are going to take a look at a third party logging
provider, namely Serilog. Serilog is notable because of two things; it can actually
support structured logging, and it also has a rich set of syncs, basically ways to
output the log information. Now to support Serilog, we of course need to add a
reference. In fact, we need to add more than one. To start with Serilog, we need to
add Serilog and Serilog. Extensions. Logging, as you can see here. Now in the demo,
I'll show you I'll be outputting my log information to a rolling file. So a rolling
file is a file that will continue to add information. When it grows too large, it
will remove the oldest information. Now that requires a separate package, the
Serilog. Sinks. RollingFile package. Now to configure Serilog, where should we go?
Well, I think you get it by now. We should of course go to the Configure method of
the Startup class. In here, I'm configuring Serilog, and the lines that you see
highlighted here. First I'm going to configure the global logger, so that's Log.
Logger, and I'm going to create a new logging configuration. I am going to use a
fluent API to configure that logger. And I'm first going to specify that the
minimum level is Debug, and I'm then going to say that I want to output to a
rolling file, so that's going to be that sync that I'm going to be using, that
RollingFileSync. In this case, I've specified that I want to output to a file in
which the date is going to be replaced with the current date, and that file is
going to be placed in the content root path. Now that date template that you see
here is something that is available through Serilog. Serilog also offers us some
other parameters; you can find them on a Serilog GitHub page. And then I'm calling
CreateLogger to create the logger. I've now configured the logger. Now I need to
add Serilog to the logging pipeline by calling loggerFactory. AddSerilog. And at
this point, Serilog is configured, so now we can use it to perform the logging. And
from then on, it's pretty similar. For example, go to the HomeController again. I
am now calling _logger. LogDebug, and I'm passing in a message. That's now run this
and see what the output from this structured logging framework will be. I've now
loaded the homepage. Let's now take a look at the log output. Now in this case,
because I configured Serilog to output to a rolling file in the applications root
path, I need to search for my logs in a file. Take a look here at the Solution
Explorer, and you'll notice that a file has been added with the date of today. This
file contains all the logs that I had in my application, but now output or
basically captured by Serilog, and it will therefore send them to this file. A
search for loading home page. You can now see the loading home page message in a
structured format that was created by Serilog.

Adding Filters
We've now covered diagnostics and logging middleware already in this module.
Although they aren't directly linked to this, filters can definitely help in
allowing us to get information about the execution of the code. Let's dive into
filters in ASP. NET Core MVC. Let's first look at what filters are, and then we'll
take a look at different options we get when we work with them. Filters are
basically going to allow us to add logic in the request pipeline of ASP. NET Core
MVC. Typically when we send a request, the corresponding action is executed on the
controller. However, if we want, we can attribute the action method with one or
more filters. A filter will trigger the execution before or after the controller
has executed, and can, in some cases, also be used to completely interrupt the
normal execution flow. Very often, filters are added to ASP. NET Core applications
for the use of so-called cross-cutting concerns. A cross-cutting concern can be
security, or logging, or basically anything that we'll be doing across action
methods. They may not have a direct link to the code that we're executing in the
action method, though. It is typically used so that we can have this code in one
location to avoid the duplication of this functionality in our code. As mentioned,
there's quite a few common usages in typical applications, including authorization,
requiring that a request is sent over HTTPS, logging, and much more. As mentioned,
a filter has the power to also interrupt a normal flow, meaning that if, for
example, a request would come in using plain HTTP, and we have a filter applied
which requires that all requests are made using HTTPS, it can cause an exception
and block the action from executing. If you're still a bit unclear about filters,
let me explain with a little example. Let's again use the example of requiring that
all requests are made using HTTPS. Although this is something that doesn't have
anything to do really with the functionality of an action method, the code inside
the action method will be littered with checks to see that the request that we are
handling is effectively HTTPS. As you can see by the frequent usages of Request.
IsHttps. Apart from the fact that this isn't very clean, it's also duplication of
code. Now using a filter, we can now move this code so that it becomes an attribute
that we can apply on the action method, allowing for easy reuse across the
application's code base. The code itself is much cleaner, and we're avoiding code
duplication. Imagine that at some point we need to make an additional check. In
that case, we only have to change the filter code in one place and all will be
updated. Really good stuff if you ask me. Filters, in fact, run in what is often
referred to as the filter pipeline. When a request is received, it first goes
through the middleware, then the routing middleware, and then the correct action is
selected. If a filter is applied on this action, then the filter pipeline will
start. This also implies that on a single action method, it's very well possible
that one or more filters will be applied. ASP. NET Core MVC comes with different
types of filters that we can apply on our action methods. Each will run in a
certain stage in the filter pipeline. So ASP. NET Core MVC is doing the
orchestration here to make sure that all filters will execute in the correct order.
The first type of filter is the authorization filter, and as that name implies, it
will be used to check if the current user is actually allowed, or authorized, to
make the request to the current action method. If that is not the case, ASP. NET
Core can actually stop the further execution from taking place. We often refer to
this process as ASP. NET Core basically short-circuiting the request. The second
type of filter is resource filters. After the authorization filters have finished,
any resource filters we have applied will run. Here we can, for example, perform
caching, if needed. These filters will also still run before the model binding has
taken place. Next, we have action filters. An action filter can run right before
and right after an action method has been called. They can, for example, change the
result that's being returned from the action. As the fourth type of filter, we have
the exception filters. As the name already is giving away, exception filters can be
used to indicate how we want to handle exceptions that are occurring in the action
method. These are typically applied on a global level in our code, meaning that
they will have an effect on the entire application's code base. We'll look at how
we can apply a filter globally later in this module. Finally, we have result
filters. A result filter can run right before and right after the execution of an
action result. They will only run if the action method has actually run
successfully. All filters that we will create will implement a common interface
called the IFilterMetadata interface, part of the Microsoft ASP. NET Core MVC
filters namespace. This interface has no methods that we need to implement, which
if you think about it, is quite logical. We have different types of filters, so
they all have different purposes. Now before we go and take a look at filters in a
demo, let's take a look at some of these filters in a bit more detail. Let's start
with the simplest one to understand in my opinion, and that's the authorization
filters. As said already, authorization filters are used to check if the user
executing the request is allowed or better authorized to do so. They will run as
the very first filter in the execution pipeline, and also before the actual method
is executing. They only define a before method. Now the Authorize attribute that
we're getting with ASP. NET Core MVC is actually not a filter. It used to be a
filter in earlier versions of ASP. NET, but with the release of ASP. NET Core,
that's not the case anymore. If you want to create our own authorization filter
then, you have to create a class that implements the IAuthorizationFilter
interface. This interface is just defining the OnAuthorization method, in which we
can then write a code to authorize the request. Note that this one is receiving an
AuthorizationFilterContext instance, which contains context data about the actual
request. And now for the filter to be able to check whether or not the user is
authorized to make the request. Here on this slide, we can see a sample of an
actual authorization filter. This filter is the RequireHeaderFilterAttribute class,
and as the name implies, this will check if the request contains, well, the
required header. We're placing this code in an authorization filter. Since this way
we have a way to short-circuit the execution of the action method, should the
required header not be present. As you can see in the implementation, we're
checking the presence of the Referrer header, and if it's present, we're checking
that the value is effectively bethanyspieshop. com. If that's not the case, we
aren't going to throw an exception, since there's no way to catch this. Instead, we
are going to return a 403 Forbidden and prevent that the action method will be
executed. It's going to be short-circuited. The most common type of filters that
we'll be writing are action filters. Action filters are general purpose, and with
that, I basically mean that we can write whatever code we want in them. If we'd
like to log that an action method was invoked, or we want to log the result of an
action method, this would typically be the place to do so. Action filters can be
applied on action method, and based on what we will be implementing in our filter,
they can also interrupt the flow before the action method has been executed, or
change the result of the action method after it has executed. Action filters will
typically implement the IActionFilter interface. Here we can see that interface,
and as you can see, it defines two methods, OnActionExecuting and OnActionExecuted.
As mentioned in a previous slide, using an action filter we can execute code before
the action has executed, or right after. This can be controlled by selecting one of
these methods.

Demo: Creating Filters in ASP.NET Core MVC


Now that we've seen what types of filters we can have in ASP. NET Core MVC, let's
go back to the demo and add an authorization filter, an action filter, and an
exception filter. In this demo, I will show you filters, the different types of
filters that are available in ASP. NET Core MVC, and we'll start with the
authorization filters. As mentioned the slides, these will get executed first. So
here we're looking at a custom filter, which implements the IAuthorizationFilter,
so this is effectively an authorization filter. And I've called this filter
RequireHeaderAttribute. The IAuthorizationFilter interface has one method,
OnAuthorization, that will be invoked automatically for us and we're getting in a
context. Now this filter, as the name already implies, will check if a certain
referrer is available in the header of the request. And through the context of this
being passed in, I get access to the request. I'm going to search for the referrer
in the headers of my request. And I'm going to check if it's found if it equals
bethanyspieshop. com. If that is, however, not the case, well, then I'm going to
short-circuit the request, and I'm not going to allow the execution of the action
method. And I'm going to do that by returning a new status code result that is
going to contain a 403 Forbidden exception. And that is going to be set as a result
for the context. Just creating the attribute, of course, won't do a thing. We, of
course, need to use it. Here on my HomeController, I've now added the RequireHeader
attribute, as we can see here. So all requests to action methods of this controller
will now be redirected through that filter. Let's try and run the application. And
as we effectively can see, we're now seeing a 403 Forbidden, and that's that filter
doing its job. It's quite logical that indeed we were getting this error because we
were expecting bethanyspieshop. com as being the referrer. All right, now let me
comment out this header, because otherwise we will keep seeing that 403 Forbidden
message. Now let us next take a look at an action filter. I've created this
TimeAction class, which inherits from ActionFilterAttribute. Now the
ActionFilterAttribute contains a couple of methods that we can override. As we can
see, we have the OnActionExecuting and OnActionExecuted, and OnResultExecuting and
OnResultExecuted. There's also two asynchronous versions that we can use. Now in my
TimerAction class, I've overridden the OnActionExecuting and Executed, and
ResultExecuted. Now what I've done in this particular TimerAction class, I've
created a stopwatch, and I want to check how long the execution of an action really
takes. So upon starting the execution of the action, I'm doing a reset, and then I
start the stopwatch, and I do another stopwatch when the action has finished
executing. Let's add this TimerAction onto my HomeController. I'm going to add
TimerAction over here. Now I'm not outputting anything just yet in my TimerAction
class, so let's for now put a couple of breakpoints that we will see getting hit
when actions are being executed on the HomeController. Let's run the application
again. So, OnActionExecuting is being hit, and OnActionExecuted is also being hit.
So I can now inspect my stopwatch and see the elapsed time of milliseconds. Now
that might be useful, but it might be more interesting when we can log that
information, perhaps combined with what we've seen in the previous demos. I've made
some changes to my TimerAction class. As you can see, I'm injecting another
ILoggerFactory, and I'm creating a new logger. In the OnActionExecuted, I'm then
going to log how long it took for the action to execute. And since I'm now logging
these messages, I don't really need these breakpoints anymore. Do remember, for
this to work, that of course I need to configure logging, like we did in the
previous demos, in my Startup class. And when we go back to the HomeController,
we'll now see an error here on the TimerAction attribute. And basically if you
think about it, well, we had the TimerAction created now with a parameter of type
ILoggerFactory. And we cannot pass that here in the attribute. Now basically what I
want is I want dependency injection within my filter. And I can do that, but in
that case, I need to replace my TimerAction with a service filter, and a service
filter will basically retrieve an instance of the filter from dependency injection.
So I need to replace my TimerAction here with ServiceFilter type of TimerAction.
And so now dependency injection will create the filter and all other types it needs
will be injected, so in this case, the ILoggerFactory. And now for this to work, I
need to make an additional change. In the Startup class, I now need to register my
TimerAction with the dependency injection system, and I'm doing that using the
AddScoped method. Let's run the application, and see if we're getting log output in
the console. So the application is loaded. Let's now go to the output. So I've
pasted the output of the application to Notepad here, and you can see that indeed
the log message containing the elapsed time has been logged correctly. There's one
more filter that I've added here in the application, and that is the
PieNotFoundExceptionAttribute, which inherits from the ExceptionFilterAttribute.
Exception filters can be used to run when a certain type of exception has been
thrown, and to handle that in a certain way. For example, with this filter, I'm
going to handle that a certain pie when searched was not found. The
ExceptionFilterAttribute defines the OnException method, which again gets in
context. And I'm going to check if the exception that was being thrown is of type
PieNotFoundException. If that is the case, I'm going to redirect the user to a view
PieNotFound, and I'm going to pass along some view data, and the model of that view
data is going to be a string. If you take a look at the View folder, you'll notice
that I have a PieNotFound view here, which is going to output that string. Of
course, I need to use this exception filter on my controller. As you can see here
on the PieController, I've registered the attribute PieNotFoundException. When we
are in the details page, and we are going to search for a pie which cannot be
found, I'm going to throw a new PieNotFoundException. This one will then be called
by the PieNotFoundExceptionAttribute, which will handle it by redirecting the user
to the PieNotFound view. Let's try that out. So let's go to the Detail page. This
pie, of course, will be found. Let's search for an ID which probably doesn't exist.
Now the PieNotFoundException will be thrown, and you now sees the view that is
showing that error message.

Working with Global Filters


The filters that we've looked at so far were all applied directly on the action
method that we wanted them to work on. Although this definitely works, there will
be times that we have a filter that we'd like to apply on all actions throughout
the entire application. If that is the case, we probably should opt for something
called a global filter. Any filter we create can be applied globally, meaning that
whenever an action is called, the filter will run as well. To register a filter as
being a global filter, we have to go back to ConfigureServices method of the
Startup class, and add some more configuration codes. I'm using the MVC. Options.
Filters. AddService method here, and I'm passing the filter type I want to register
globally within my application. The result of this line of code is effectively that
an instance of the SomeActionFilterAttribute will be created, and it will be
applied on all action methods within my application.

Demo: Adding a Global Filter


Now in the next demo, I'll show you how we can register a filter globally for the
application. In this demo, we are going to take a look at global filters. Now for
the purpose of this demo, I've used the same TimerAction filter that we used in the
previous demo, so the one without logging, and I've registered it as a global
filter. Let's first take a look at the global action filter in action. When I
navigate to another page, you'll hit the breakpoints that I've set here. For every
action that is being executed, the filter will get hit. Now I think you get the
drill. Now how did I do that? And the filter itself hasn't changed, but I've made
some changes in the Startup class again. In the services. AddMvc, I've now passed
in configuration. I've used an instance of MVC options here, and that exposes a
filters collection that are going to be applied on all actions within my
application. And I'm adding my own TimerAction filter here. Now I can add more than
one filter, we're not limited to just using one filter as global filter.

Adding Azure Application Insights


In the final part of this module, we will spend some time looking at Azure
Application Insights, which as we'll see in a minute, will give us better runtime
information about the application. Now before we explore how we can add Azure
Application Insights to our site, let's first take a look at what this is all
about. It has Azure in its name, so it probably has something to do with cloud.
Well, you've got that part right. Azure Application Insights is a product part of
the Azure family aimed at giving us the ability to store diagnostic information
about our site in the cloud. It's called Insights also with a reason. It's not
aimed at just allowing us to store logs, for example, in the cloud. It will give us
insight in the performance of the application, exceptions that have occurred, and
it will allow us to take an analytical view at that data as well. It will also
support automatic alerts. For example, an email being sent if a certain type of
exceptions is occurring. Or if a threshold of number of errors per time limit has
been exceeded. Also, we can get access to this information in a number of
dashboards, which we'll see in the last demo of this module. Note also that
although this is a cloud-based solution, it also works with sites which are hosted
elsewhere, so perhaps on premises.

Demo: Working with Azure Application Insights


Now that we have already seen what Azure Application Insights is all about, let's
return once again to our demo and see how we can send logs and exceptions that have
occurred in our application back to Application Insights. In the last demo of this
module, we are going to add Application Insights into our application. Now to get
started, select the project and go to the Project menu, and select Add Application
Insights Telemetry. Now you'll be guided through a couple of steps where you can
configure Application Insights in your application. Now this does require an Azure
account; I'm not going to show you how to set up an Azure account, you can create a
free one if you want to follow along with this demo, or use an existing one that
you may already have from an existing MSDN subscription, for example. So I'm going
to start by clicking on Start Free here, and I need to select my MSDN account, and
I'm going to select in which resource I want to add my Application Insights. In
this case, I'm going to add a new Application Insights resource. Note that the base
monthly price is free, but an additional cost may incur if you go over a specified
amount of data. Let's click on register, and this will now configure Application
Insights in our application. Note that this also will configure Application
Insights in your Azure subscription. These two will be linked automatically
together. So that seems to have succeeded. I'm going to click Finish here, and now
we can start using Application Insights in our application. Now before we take a
look at Application Insights and how we use it, let's first take a look at what the
configuration wizard has done for us. Let's open the csproj file, and take a look
here. There's now another package reference that has been added to Microsoft.
ApplicationInsights. AspNetCore, and I'm using the new version 2. 0. This version
is pretty new, and a lot of the documentation at the time of the creation of this
course hasn't been updated to work with this version yet. Now I don't really need
to do anything in my application, I just need to run it, and then we can actually
dig into the Application Insights telemetry. Now before we run the application
locally, I'm going to open the local Application Insights Telemetry window. So I go
to View, Other Windows, and there we'll see Application Insights Search. Let's now
run the application, and automatically the telemetry information will appear in
this window, and we can then drill down into this information. So if we go to the
homepage, let's click on the Contact us page, and let's then click on the View all
pies page, and click on a detail of one of the pies. All right, let's now jump back
to Visual Studio, and hit the search button to view all telemetry information, and
notice now that it has captured 18 items, a custom events, a couple of page views,
and a couple of requests. Well, let's uncheck everything here, and let's take a
look at the requests, for example. Here is the list of requests, so 16 requests
have been fulfilled by my application, including CSS files that have been loaded,
but also, for example, the loading of the pie details passing in the ID. I can
click on one of the requests here, and I will see some more details. It's even
possible to see that the operation was GET Pie/Details. I can click on this, and
this will then take me to the controller action that handled this request. Now the
cool thing about the Application Insights is that all the information that you see
here will also be synchronized with the Azure back-end that sits behind Application
Insights. And do note that there is a delay before the events that you have
captured on your server will appear in the Azure portal. So let's now go to the
Azure portal and let's dig into Azure Application Insights there. Now automatically
when it was configuring Application Insights in my application, it also configured
Application Insights in Azure. And here I can then see the same telemetry
information for my application. I can then, for example, see the page requests. I
can click on one of these, and I can see some more information about the
performance. I'm not going to dig too deep in what you can do here; there's other
courses on Pluralsight that dig deep in Application Insights. Now by default
Application Insights will capture all the information that you just saw. Now it is,
however, also possible to use the API and track specific things. Now to do that, we
have to use the TelemetryClient class, and that has a couple of methods, such as
TrackPageView and TrackEvent, which will then cause specific entries to be logged
in the telemetry of Application Insights. These will then also be visible in the
local Application Insights search, as well as in the view you get in Azure.

Summary
Whew! That was a long module, wasn't it? I hope that you have learned a lot about
diagnosing your application's runtime issues. We have started this module by
exploring the different options for logging, and we have spent most of the time on
looking at the use of the ILogger type of logging. Next, we have explored using
filters in our application. As you remember, hopefully, filters have enabled us to
move code into a separate class and invoke this as an attribute on action methods.
We finished this module by looking at Azure Application Insights. Using this
framework, we can store and send log information into Azure and get useful
information about the performance of our application. In the next module, we will
try to improve the performance of the application. I hope to see you there as well,
and thanks for watching.

Improving the Application's Performance


Module Introduction
Hi there, and welcome to this module of the Building an Enterprise Application with
ASP. NET Core MVC course here on Pluralsight. My name is Gill Cleeren, and I'll be
guiding you through this module. This module is titled Improving the Application's
Performance. Ooh, performance. Getting more done with the same hardware, because we
as developers have done a better job creating our code so that the application runs
faster. That is what we will be discussing in this module. Let's for starters take
a look at the topics we will be discussing in this module. First, we will take a
look at the what and why of caching, and how it, from a bird's eye perspective, can
help us with improving the performance of our site. Then for the rest of the
module, we'll take a look at all the options that ASP. NET Core MVC offers us in
this area. First, we'll take a look at the in-memory caching, a very simple, but in
some cases, effective way to perform caching. ASP. NET Core MVC comes with a tag
helper that is specific to caching, quite conveniently called the caching tag
helper, and we'll explore that one, too. Next, we'll take a look at a more complex
setup using distributed caching, and I'll be using Redis for this. Next, we'll take
a look at response caching and the different options that ASP. NET Core is offering
us here. Finally, we'll take a look at how compression can be done, basically to
limit the amount of data going over the wire, and this way also improving the
application's performance. A lot of things to cover. Let's get started.

Caching as Performance Booster


Yesterday Bethany came to our office once again. Don't get me wrong, we're always
happy when a good customer of ours pays us a visit. However, this time she had some
bad news. Some customers are complaining that her site sometimes seems to be
slowing down quite a lot, and she's given us the task to investigate and see what
can be done about it. Of course, we can take the easy route and scale up the server
in Azure where her site is hosted. Or we can do the noble thing and see if we have
done everything we can to make sure that our code is running optimally. Well,
Bethany, let's start with the latter, shall we? So instead of buying stronger or
more hardware, we are going to see how we can get the most out of what we have. One
of the possible approaches here is caching. Let's see how caching can improve the
performance of our site. When we talk about caching, we typically think of some
data that has already been generated and reusing that somehow. That is definitely
what caching is all about, trying to avoid that an expensive resource is to be
generated or downloaded again. This way we can bring down the amount of CPU cycles
or the number of bytes going over the wire. In the context of a web application
nowadays, there are typically quite a few places where we can improve. If we think
of a site, such as Bethany's Pie Shop, it's as we know already, a regular server-
side ASP. NET Core MVC application. Most of the execution is happening on the
server-side, but even there it's very well possible that an expensive operation is
taking place. Reading from database, reading from a remote service, and so on and
so on. There are many things that actually can take a very long time and cause
heavy load on the servers. And we can definitely cache that data on the server and
thus improve the performance of the site on the server's end. Of course, when we
reach the limitations of the single server that we may be initially using, we're
going to add some more servers. When we then perform caching, we may run into
issues in that the cache data isn't available on all these servers. That's why
distributed caching can be used. It's typically a place, a server probably, where
all of our rep servers will have access to anywhere the cache data will be stored.
But caching can also be done on the client-side. In that case, we are capable of
controlling from within our ASP. NET Core MVC site if the pages on the client
should be cached, and if so, how long the cached copy can be returned on the
client. In that case, we are capable of controlling from our ASP. NET Core MVC site
if the pages on the client should be cached, and if so, how long a cached copy
should be returned to the user. So as you can see, even in a hard or simple
application, there are a number of places where we can cache data, and this way
improve the performance of the site, for free. We can cache data on the server, we
can extend it with a caching server, and as said, we can also control how the data
that was already sent to the client, is cached on the client. Caching can
definitely help us with the speeding up of our application. We'll see the different
ways how we can implement it in ASP. NET Core MVC in this module. Caching is
typically a good thing for stale data, meaning data that doesn't change very often.
Imagine that we have a number of categories of pies for Bethany's Pie Shop that
would typically be coming from a database. Chances are that the list of categories
is pretty static, and we probably don't have to reload it for every request, and
it's typically data that is a good candidate for caching. But if caching gives us
better performance for free, why don't we always use it then? Why even doubt? Well,
the thing is, using caching requires some thought up front. If you start doing
caching the wrong way, it may even cause some odd side-effects to occur. So while
it will definitely help in quite a few places, we should still be careful about
where and when we start applying it.

In-memory Caching
Now that you have an idea about the general concept of caching, and where we can
apply it in a web application, let's dive into several options in more detail from
an ASP. NET Core MVC's perspective, and we'll start with in-memory caching. In-
memory caching is probably the simplest form of caching available in ASP. NET Core
MVC. It's basically, as the name implies, some data that will be cached in the
memory of the server. It is represented by the IMemoryCache interface, and we'll
see that one when we look at the code. Since the data that we're going to work with
is simply going to be stored in the memory of the web server, it is tied directly
to that server. That means that in-memory caching is intended for sticky sessions,
meaning that some secret requests should always return to the same server in the
case we're using a webform. In the case that we can't really use sticky sessions,
then we can't really use this type of caching, since we'll probably end up with
inconsistencies in the data that is being cached. Distributed caching will probably
be a solution for this setup, and we'll take a look at that later in this module.
Since we're storing data objects in-memory for retrieval later on, we're basically
not limited to what we are storing. Typically we'll want to store expensive
objects, expensive data, things that require a lot of processing before they are
available again. Now to start using in-memory caching, we'll need to first add a
package reference in our application again. In this case, the required package is
the Microsoft. Extensions. Caching. Memory package. Now with the package added to
our project, we can start configuring the application so it can use in-memory
caching. Like most things in ASP. NET Core MVC, we can use it through dependency
injection. Now for the ISystem to know about it, we need to register it, of course,
and this can be done by calling services. AddMemoryCache in the ConfigureServices
method of the Startup class. Once IMemoryCache is configured for use with the DI
container, we can get a hold of it in our controllers. Here on this slide, you'll
see a basic controller which is expecting an IMemoryCache instance as a constructor
parameter. Because IMemoryCache was registered in the DI container, we'll get back
an instance that we can then use in our controller code. Now using IMemoryCache
isn't very difficult. It has a very straightforward API that we can use. You can
think of an in-memory cache as an in-memory dictionary, where each cached value is
addressable using a key. Of course, we don't know up front whether or not a value
for a given key is already available in the cache. Therefore, we need to perform a
check before trying to use a value. Here in the slide, we can see how I can perform
that check using the TryGetValue method of the IMemoryCache interface. I pass it
the key. Here that is the PiesOfTheWeek constant. If a value is found, it's
returned using the out parameter. If not, well, then we need to perform code to
retrieve the actual value, and then we'll store it in the IMemoryCache instance
using the set method, passing along again the same constant string as key. When we
are working with cached data, one of the important things is that we'll need to
find a balance between performance game and the amount of time that we keep the
data cached. We shouldn't keep the data cached for too long, since then we may have
a risk that we're sharing out-of-date data to the user. In many cases, it is not a
good idea to cache something indefinitely. ASP. NET Core uses the
MemoryCacheEntryOptions, which among others, allow us to manage when a cache should
expire. We can specify an absolute expiration, which is a specified point in time.
We can, for example, say that we will cache for one hour, and then, upon the next
request that we receive for that particular piece of data, the cache is cleared and
the data must be retrieved again from the source. Alternatively, we can also use a
sliding expiration, meaning that every time the cache data is used, the timer for
expiration is being reset. We also have the ability through the use of the
MemoryCacheEntryOptions to change the cache priority. Using this, we can indicate
to ASP. NET Core MVC how important the piece of data really is. Should there be a
shortage of memory, ASP. NET will remove the items with the lowest priority first.
And finally, there's also the option to create a delegate that will point to a
function that needs to run should the data be forcibly removed from memory. That is
the dramatic-sounding PostEvictionDelegate.

Demo: Working with In-memory Cache


In the first demo of this module, we are going to start playing with the easiest
form of caching. I'm going to start by configuring the application for use of
IMemoryCache, and secondly, we'll use it in the application. In this demo, we are
going to take a look at working with in-memory caching, so the simplest form of
caching in ASP. NET Core MVC. And to work with in-memory caching, we need to make
sure that the Microsoft. Extensions. Caching. Memory package is already referenced
in our application. And we can see that by opening the csproj file, as we've done
many times before. Now to make sure that memory cache works in ASP. NET Core MVC,
we need to add it to the services collection by using services. AddMemoryCache in
the Startup ConfigureServices method. Now with in-memory cache configured, we can
start using it. Now to explain in-memory caching, I've used the HomeController
again. Notice that I now have an IMemoryCache local field, and an instance is being
injected through dependency injection, as we can see here. Nothing has really
changed. This we've done quite some times already. Now in the Index action method
of my HomeController, I need to have the PiesOfTheWeek. Now why do I get the
PiesOfTheWeek typically? Well, I get them by doing a database call, but typically
the list of PiesOfTheWeek doesn't change that often. And for the purpose of this
demo, I'm going to pretend that it may be so that every 30 seconds the list of pies
of the week could change. So I'm going to refresh my cache every 30 seconds. Let me
show you how I've done that here. On the memoryCache instance, I'm going to use the
TryGetValue method. And this one accepts a key that will be used to search the
cache for the requested value. If the value is found, I'm going to return it here
using this out parameter. If the value cannot be found in the cache, well, then I'm
going to go to the pieRepository and ask for the pies of the week. When I have this
list, however, I'm going to cache it. I'm going to build up an instance of
MemoryCacheEntryOptions, and I'm going to specify that in this case I want a
sliding expiration of 30 seconds. A sliding expiration is basically a sliding
window, so whenever this value is accessed another 30 seconds will be added. I can
also use a SetAbsoluteExpiration to make sure that after 30 seconds in this case,
the value will expire. To the CacheEntryOptions, I can also pass a callback, the
PostEvictionCallback. This callback method will be invoked when the value is
removed from memory. And I can handle that, for example, by logging a value.
Finally, I use the Set method on my memory cache local variable here. I pass the
same key, and the list of pies I want to cache. Also, don't forget to pass here the
CacheEntryOptions. Let's try running the site, and see if the result is still the
same. I've put a breakpoint here as well, so that we can see that initially the
value will not be in the cache. We're hitting the breakpoint, so at this point, the
value could not be found in the cache. Let's hit F5 so it will now store the value
in the cache, and then return the list of pies. Now the resulting view is the same,
we're getting that same list of pies of the week. If I now do a refresh, the
breakpoint is not hit. Let's put another breakpoint here, so another refresh, and
as we can see, indeed this breakpoint is being hit, so the pies are indeed
retrieved from the cache. Alternatively, we can also work with the extension
methods on the in-memory cache. The GetOrCreate method accepts as the first
parameter again the key and a second parameter a func. In this case, I'm going to
pass a function that is going to set the SlidingExpiration, set a Priority, and
then return the list of the pies of the week from the repository. This function
will execute when the value cannot be found in the cache, and if the value is still
in the cache, well, then it's simply returned, and the result is exactly the same.

Cache Tag Helper


So far, we've seen the ability to cache data from code using the IMemoryCache. One
of the biggest changes in ASP. NET Core MVC are tag helpers. It turns out that
there's also a tag helper, the cache tag helper, that allows us to perform caching.
Let's take a look. The cache tag helper is very simple, and we'll see it in action
in just a minute. Since it's a tag helper, we'll be able to use it from Razor code,
so server-side. While a tag helper is typically used to generate HTML, the cache
tag helper works a bit differently, in that it's typically going to be used to
cache data between the open and the closed cache tag. Behind the scenes, however,
the cache tag helper is really nothing more than a convenient way to use the
IMemoryCache in a declarative way. And because it's basically nothing more than
IMemoryCache, it follows roughly the same rules. It can store all types, since they
will be stored in memory. But just because all the data is stored in the memory of
the server, in order to function correctly, the cache tag helper also requires that
we have sticky sessions. Like I said, and I never lie, and that's honest, the cache
tag helper is very straightforward to work with. The only thing that we need to do
is wrapping the item we want to cache between an open and closed cache tag. Behind
the scenes, what will happen is that code will run, code that is part of the tag
helper, which will check whether or not the required data is already in-memory. And
if that is the case, the cached version will be returned. If no previous version is
found, Razor will process the code and store the response for you in-memory for the
next request. If no previous cache data is found, Razor will process the code and
store the response for you in-memory, so that the next time it doesn't need to
execute that code, resulting in better performance for the application. Keep in
mind that this tag helper won't be generating any output itself in the resulting
HTML. It's a server-side tag. Now in the code here, you can also see the expires-
after attribute being used. Just like with regular use of the IMemoryCache, we need
to be capable of letting ASP. NET Core MVC know when the cached version of the data
is set to expire. For this, the cache tag helper has a couple of attributes defined
that we can use to indicate this. Let's see what options we are getting on the
cache tag helper to indicate when the data should expire. The expires-after
attribute allows us to specify that the cached data should expire after a certain
amount of time, for example, 10 minutes. Expires-on allows us to specify a certain
date and time in the future that we'll want the data to expire on. And expires-
sliding allows us to specify again a sliding window, meaning that if the data isn't
accessed after a specified amount of time, it should expire. As you can see, these
options are very similar to the ones we had with the plain IMemoryCache. Next is
specifying a time-based option to indicate expiration. The cache tag helper also
defines a couple of other options that we can use to extend the usage of it. By
default, the cache tag helper will create a unique ID for the instance of the tag
helper. This allows us to use several instances of the cache tag helper on a single
page. It is, however, also possible to have the tag helper define multiple cached
instances of the same single tag helper. This is possible by asking the tag helper
to combine the key with another attribute that we specify. Multiple versions of the
vary-by attribute can be used to do this. Take a look at the code you see here on
the slide. I've used the vary-by-user attribute. What this will result in is that a
different version of the cached data is stored for each logged in user. I'll get my
copy of the cached data when I visit the page. If you are logged into the site,
you'll get your own copy. If we are caching, for example, the menu of the site,
this could come in handy. I may have access to other pages in the site that you
don't. If we would try the same menu, we'd both see the cached single instance, and
using the vary-by-user, this will not happen. Several vary-by options exist in ASP.
NET Core. We've already seen the vary-by-user. Vary-by-route allows us to store
different versions based on the route data parameters. For example, we can store an
instance of the cached data per different version of the ID parameter. Vary-by-
query will practically be the same, but now for query string values. Vary-by-cookie
allows us to store a different version of the cached data based on the value within
a cookie. Vary-by-header does the same, but now based on the value of one or more
specified headers. Finally, the vary-by allows us to store multiple versions of the
cache based on an arbitrary string value.

Demo: Using the Cache Tag Helper


Let us now return to the demo and see how we can use the cache tag helper in action
to increase again the performance of our site. In this short demo, I'm going to
show you how we can work with the cache tag helper. As explained in the slides,
working with the cache tag helper is basically the same as working with the in-
memory cache that we saw in the previous demo. But now we can do it declaratively,
so directly from the Razor code. So I'm here in the layout file, and I have the
category menu in that layout. Now, categories within my application, well, they
don't tend to change that often. So I would actually have to go to the database for
every user that visits my site to build up that list of categories. I could easily
cache that as well. That's why I'm using the cache tag helper as we can see here.
I've placed a cache open and close tag around the invocation of the CategoryMenu,
and that's that view component that actually builds up the menu. Now this value,
the resulting HTML basically, will then be cached automatically for me via the
cache tag helper and will then be inserted on subsequent requests. I've used here
the expires-after, so I'm basically going to say after 20 seconds it will by
default expire. Let's run the application. Just note, I've placed a breakpoint here
in the CategoryMenu ViewComponent, and so we'll see when a new version of the menu
is being requested. So let us run the application. So now the first request is
happening, and the category menu needs to be constructed. Hit F5, and there's our
menu. Let's refresh the page, and as we can see, we didn't hit that breakpoint
again. If we wait a couple of seconds now, so if I can continue talking for about
20 seconds, well, then we will actually be hitting that CategoryMenu again. Do
another refresh, and there we go, we are hitting that breakpoint in the
CategoryMenu again, so the cache has expired. Now there's quite a few options that
we have with the cache tag helper. For example, we can specify that the value will
only expire on a certain date. We can also specify alternatively a sliding
expiration again. In this case, when a request is made within 20 seconds, the timer
basically starts counting again.

Distributed Cache
So far, we've discussed options where we are storing the data in the server's
memory, and we've discussed that this may not always be the best solution. Now
let's take a look at using distributed caching. I've already talked about the fact
that for the purpose of caching, it is not always a good idea to cache data in the
memory of the server. While that is okay for simple applications that don't
generate a lot of load on the server, it is not always the best solution for larger
systems, typical for the enterprise. In the case that we have a large application,
or perhaps an application that starts small, but grows over time, another approach
may be better, both for performance and scalability of the application. Using so-
called distributed caching might help in achieving this. A distributed cache
basically means that the data won't be cached directly in the memory of a web
server, instead a shared cache is set up which is available for all servers. Using
a distributed cache removes the need to work with sticky sessions, which may not
always be good for performance anyway. The data that's in the cache is available to
all servers. It's also much easier to scale the system. We can install an extra
server, and it can go ahead and use the same shared cache. Also, without
distributed caching, the cache data is lost when the server needs to reboot. We
then distribute that cache that is no longer a problem. And in general, using a
distributed cache will result in better performance, which is what we're after in
this module anyway. Now using a distributed cache is quite logically more complex
compared to an in-memory cache. The good news is that ASP. NET Core MVC comes with
support for two built-in approaches, and that is Redis and SQL Server. We'll look
at a way to implement this in the next demo. Just like with the IMemoryCache
interface for in-memory caching purposes, we have another interface that we can use
with distributed caches. Microsoft has kept the name quite simple, and I think it's
pretty obvious where the name is coming front. IDistributedCache is the interface
that we will be using to work with a distributed cache. The cache here finds a
number of methods, each which has a synchronous and an asynchronous implementation
available. We have the Get and GetAsync, which accept a string as key and returns
the cache data if found using a byte array. Quite logically, the Set and SetAsync
will store data, again, as a byte array based on the key we're giving it. Refresh
and RefreshAsync are used to refresh the sliding expiration for a cache item, and I
think you can figure out that Remove and RemoveAsync will remove an item from the
cache based on its key.

Demo: Adding the Distributed Redis Cache


Let's go back to Bethany's Pie Shop and let's see how we can now use a distributed
cache. We'll start the demo by setting up Redis and then secondly we'll use the
Redis distributed cache from the application code. In this demo, I'm going to show
you how you can work with a distributed cache. Now for the purpose of this demo,
I've selected to use the Redis distributed cache. Now to add Redis to your
application, you can go to NuGet and search for the redis-64 package. So the first
step is adding this package to your application. The next thing you need to do is
start the Redis server. Now to do this, open a Command Prompt, and go to the folder
you see here on the screen, of course, replacing Gill by your own username. In
there, you'll find a file called redis-server. exe. Start that and Redis will run
locally on your machine as a distributed cache. There you go. So Redis is now
running. Now Redis actually only supports storing byte arrays, so that means that
if you want to store, for example, the pies, like we've done with the in-memory
cache, we will need to serialize them. Now for the purpose of this, I've also added
Newtonsoft. Json. net to my application. Next we, of course, need to make some
configuration changes to work with Redis. To the services collection, I'm adding
Redis distributed cache using the AddDistributedRedisCache method. I can pass some
options here, such as the instance name and the configuration. Now let's go to the
HomeController where we will be caching some pies. In the HomeController, I've now
used an IDistributedCache, and I'm getting that instance in my HomeController using
dependency injection again. Next in the Index action, I'm now using the
LoadPiesFromRepoOrCache method to load my pies of the week. Now this is the method
that will actually do the interaction with the Redis distributed cache. I'm going
to check their distributed cache for the presence of the key allPies. If that
doesn't return anything, well, then we need to load it in the cache. So I'm then
going to go to the repository and then I'm going to serialize my pies. Now as
mentioned, Redis can only work with byte arrays, so I'm going to convert my string
into a byte array, and then I'm going to add some DistributedCacheEntryOptions, in
this case, I'm going to add again a sliding expiration of 1000 seconds. Finally,
I'll use a set method on the distributed cache with that key to pass in the pies
I've just retrieved from the repository. And I then return the list of pies. If
that key is found, well, then I'm going to get from the distributedCache by byte
array of encoded pies, I'm going to convert that into a string, and I'm going to
deserialize them using json. net into a list of actual pies. Let's run the
application and make sure that everything still works as before. And success! The
pies of the week list is still showing. From now on, this list can be retrieved
from a distributed cache.

Response Caching
So far, we've focused on the optimizations we can do from the server-side in our
application. Another option is using response caching. Let us explore what we can
do in this area to improve the performance of the application. As the name implies,
using response caching, we can now add the correct headers, cache-related headers,
to the response. These headers can then be used down the line, so on the client,
but also on intermediates, such as proxy, to cache the entire response and reuse
that. This, of course, will make the application look faster, as well as bring down
the load on the server, since the same data only needs to be returned once. Working
with response cache in ASP. NET Core MVC can be done using an attribute called the
ResponseCache attribute. This attribute will allow us to specify some parameters
that will then result in setting the correct headers in the resulting response.
Let's take a look at how we can use this ResponseCache attribute. Here in the
sample code that you see here on the slide, we have a small example. To the
attribute, I've added several parameters. To enable response caching, we need to
specify a value for the duration parameter. Here I've specified 30 minutes, which
will result in the max-age header being set in the response. Next I've also used
the VaryByHeader and I specified the User-Agent here. Setting these headers, as
mentioned, will result in headers being set in the generated response that is being
sent down to the client. Here you can see a screenshot where these headers have
been added. We have the ability to specify several types of headers to control
this. The location header allows us to specify where the caching can happen. For
response caching to work, it must be set to any or client. If we set it to none, no
caching will happen. Duration is the second one. We've already seen that on in the
previous slide, it gives us control over what the duration of caching or the
response will be. NoStore allows us to control that the caching should not happen
at all. This just results in the cache control header to be set to NoStore no
cache. Finally, the VaryByHeader allows us to specify what header we want to check
on. We can use the ResponseCache attribute throughout our code base, with the risk
that we have to change it and thus make changes in several places. It's easier to
fix this by creating something called a CacheProfile. A CacheProfile is registered
in the ConfigureServices method of the Startup class, and it allows us to create
one or more named profiles, each of which has a number of parameters set. On the
slide here, we're defining a couple of profiles, and we can then from actual code
refer to these profiles. And as we can see, each profile has a number of properties
set.

Demo: Adding Response Caching


Let us return to the demo application and apply response caching, again, improving
on the application's performance. In this demo, I will show you response caching,
basically how from the server-side we get the ability to control if the client will
reuse a locally cached version. We're again in the HomeController and I'm on the
Index action method here, and I've now added the ResponseCache attribute, and I
specified that the duration is 30, so that will be 30 seconds. So this means that
during the next 30 seconds, no new request will be done. And this will be reflected
in the headers that will be sent to the client. Let's run the application and take
a look at the developer tools. So here's Bethany's Pie Shop. Let me hit F12 to open
the developer tools. And let's do a refresh of that request. And here we see the
localhost request, and we can see that the Cache-Control is set public, and max-age
30. Other options are available for working with the ResponseCache, basically
giving us more fine-grained control over how that header will be set. We can
include the location and set that, for example, to client. We can include the
VaryByHeader and set that to User-Agent. Alternatively, we can also work with cache
profiles. As you can see here, my ResponseCache now has an attribute
CacheProfileName, which is pointing to the Default cache profile. Cache profiles
can be found in a Startup class. In the configuration of my application, I can add
one or more cache profiles. A cache profile has a name and then one or more
attributes with basically the same attributes that we can use directly on the
action methods. Of course, by creating and thus grouping these values in the
Startup, it's easiest to make a change that will be application-wide.
Managing Compression
For the last topic in this module on increasing the performance of Bethany's site,
we're not going to work with caching. Instead, we are going to focus on bringing
down the number of bytes that need to go over the wire. You don't need to be a math
expert to understand that if we send less bytes over the wire, that the client will
get its data faster, and thus the site should feel more responsive. We can know
this by using compression techniques on the data that is being transferred.
Compressed data arrives faster on the client, and thus should, as mentioned, make
itself feel more responsive. Compression can be applied on almost all types of data
that are being sent to the client, including HTML, CSS, JavaScript, and so on. Data
types that have already been compressed should typically not be compressed again.
This includes things like JPEGs. The faster all this data is on the client, the
faster the browser can render it. Keep in mind that compression should typically
only be used on files which are above 1K in size. Compression is by default not
applied by the server. Typically, the client will indicate to the server using
headers that it's capable of receiving compressed data. It can do so by using the
Accept-Encoding header when sending a request. When the server has decided it will
indeed send compressed data to the client, it's required that it will let the
client know about this, and this can be done using the Content-Encoding header,
which is then sent by the server. It shouldn't come as a surprise that enabling
support for compression in our site is done using another package. We need to add a
package to our application, in this case, the Microsoft. AspNetCore.
ResponseCompression package. With the package added, we need to add support for the
ResponseCompression middleware in the Startup class of the application. Here on the
slide, I've added in the ConfigureServices that we now need to support compression
using the AddResponseCompression method. ASP. NET Core MVC will default to Gzip
compression. We'll need to add this as middleware to the pipeline again. Here you
can see the Configure method, where I'm specifying that we'll want to use Gzip
compression. In one go, I'm also passing in options where I, in this case, have
specified that we'll want to use the CompressionLevel. Optimal. The latter means
that I'll want to perform compression even if it takes a bit longer. How can you
now see the difference between compressed and uncompressed responses? Here is a
screenshot where the response isn't compressed. So the text is readable, no
compression has been applied to it. Notice that there's no Accept-Encoding or
Content-Encoding here, since indeed there's no compression happening here. In the
screenshot you see here, you can see that the request now indeed has the Accept-
Encoding header sent. The server is responding with a compressed response and
indicates this using the Content-Encoding header.

Demo: Working with Compression


In the final demo of this module, let's see how we can squeeze the last drop of
performance out of Bethany's Pie Shop by adding support for compression. In the
final demo of this module, we'll take a look at response compression. Now, to work
with compression, again, another package is required. In this case, it will be the
Microsoft. AspNetCore. ResponseCompression package that you need to add to your
project. Now before I show you compression, I'm going to first show you the
uncompressed version; otherwise, it's pretty difficult to show you the difference.
Just so you know, I have added some Lorem ipsum text to the index view to make it a
bit bigger. Let's run the application and see the size of the response. Now if you
open in developer tools, and we refresh the page, we see that a request for the
homepage is now 5. 7 KB in size. Now let's enable compression. So we need to do
that again in the Startup file, and in the ConfigureServices method we need to add
support for compression by calling AddResponseCompression. Next in the Configure
method, we need to add the ResponseCompression middleware. Let's now run the
application once again. Let's open the Chrome developer tools again, refresh the
page, and now we can see that the size has indeed decreased to 4. 6 KB. Now it's
possible to add more options to the ResponseCompression. To the
AddResponseCompression call, we can pass options, for example, to also enable
compression for HTTPS traffic, as well for other MimeTypes. A compression also uses
a provider model, and the default provider that we can use is the Gzip compression
provider. We can use that provider to use a specific compression level. In this
case, I've chosen for the Optimal compression level.

Summary
We've reached the end of this module. Time for a quick recap of what we have seen
in this module. We started our journey to improve the performance of Bethany's Pie
Shop by looking at several ways to perform server-side caching. We've seen in-
memory caching here, and we've also seen how distributed caching works. Next, we
have spent time looking at how we can from the server add the correct headers to
the response, so that the client will be able to cache a version. Finally, we've
looked at how we can improve the performance even more by compressing the response
before it's even sent to the client. In the next and last module of this course, we
are going to take a look at how we can automate the builds and deployments for our
site. Thanks for watching this module.

Automating the Deployment of Your Application


Module Introduction
Hello there, it's that time. You have reached the last module of this course. But
no fear. In this last module of the Building an Enterprise Application with ASP.
NET Core MVC course, we're going to have some more fun together. Also for this last
module, my name hasn't changed, so that is still Gill Cleeren. Let me know if you
have any questions about this course via the discussion board here on the
Pluralsight website. Now in this last module of this course, we are going to focus
on the automation of the deployment process of the application. After this module,
you'll have an example of how to set up the automated build and deployment of
Bethany's Pie Shop to Azure. For the last time, let's take a look at the outline of
the module before we're getting started. Since we will be using VSTS, Visual Studio
Team Services, for this course, we will start with a brief overview of the
platform. Feel free to skip this part if you're already experienced with VSTS. Once
we have finished the overview of VSTS, it's time to set up continuous integration
with it, and as the last topic for this course, we are going to take things a
little bit further, so that we also have an automated deployment of the site onto
an Azure App Service. If you've watched the intro course before, you may have seen
that we have already done a regular deployment to an Azure App Service. Now in this
course, we'll take things a bit further. Let's get started.

An Overview of VSTS
As promised, to make sure that everyone is on board with VSTS, a small overview of
the platform is in place. Pluralsight has quite a few courses that go in much more
depth on this topic. VSTS, short for Visual Studio Team Services, is the online
component of the Visual Studio family. Previously known as Visual Studio Online,
VSTS is an integrated environment for the entire development team. Visual Studio
Online gave people the idea of working with an in-browser version of Visual Studio.
And although you can do some editing from within VSTS, it is much more than just
code editing. Using VSTS, we can check in code to a source control system, which is
built in, but we can also automate builds, perform deployments, plan the work for
the entire team, and so much more. It is, in fact, a complete DevOps solution. VSTS
prides itself also in the fact that it is not bound to a certain technology. VSTS
is very open, meaning that we can use of course for ASP. NET, C#, WPF, and
basically all. NET applications that we're building. But also VSTS can work with
Java, iOS, Android, and other platforms. It also integrates with many third-party
tools, such as Jenkins or Jira. Internally, it is also based on Azure. That's
right, VSTS is a software as a service solution, meaning that it is, in fact, TFS,
which is being hosted by Microsoft in the cloud for us. That being said, many, if
not most things that you'll learn in this module are one-on-one applicable in TFS,
so Team Foundation Server. So what does VSTS bring to the table then? Source
control. That's, of course, an important one. VSTS supports Team Foundation Source
Control, or TFSC, as well as git. Using VSTS, we can also plan the work for the
entire team by creating work items, registering bugs, assigning tasks, and much
more. VSTS also comes with a built-in planning board, and it does allow us to
follow up on the project's progress. VSTS can also be used as a build server, so in
fact, it's also a continuous integration tool. This makes it possible to set up a
build with every check-in, for example. But we can also configure from VSTS a
nightly build. VSTS also contains something called release management. As the name
implies, this allows us to manage and orchestrate releases to staging, production,
and so on. For testing, VSTS also features a lot of useful parts. Basically, I can
go on and on and on about all the features in VSTS, but that would take us way too
far.

Demo: An Overview of VSTS


I think instead of talking too much about VSTS it's better that we take a look at
it in action. I will give you a brief overview of the VSTS environment in the first
demo of this module. In this demo, I'm going to show you a high level overview of
VSTS, or Visual Studio Team Services. Now VSTS is free up until a certain level.
You can, for example, if you're a standalone developer, use it entirely for free.
Now to get started, go to visualstudio. com, and over there you'll find the Visual
Studio Team Services Get started for free link, and that will take you through the
steps to create your own Visual Studio account. Now I have, of course, done that
already. So we're going to be using my Visual Studio account in this demo. So when
you've created your own Visual Studio Team Services environment, you will arrive
when you go to your domain. visualstudio. com on this landing page here, which
shows you a number of projects if you already have some. From here you can get
started by creating a new project. You can give your project a name, you can give
it a description, you can select the type of version control you want, and you can
also choose between Scrum or Agile to manage the project. When you then click on
Create, the project will be created for you. Again, I'm not going to do that here,
I've already done that long beforehand. When your project has been created, it will
appear here in this landing page. And from there, we can click on it and start
working with this project. Now basically everything is managed from the tabs you
see there at the top of the screen. So for example, here I can go to my dashboard.
The dashboard can be used to show you a high-level overview of the project. You see
here a couple of widgets. You can add widgets if you want to do that, and from
here, you can also, for example, create new work items and so on. Now the Code dab
is, of course, quite an important one. From here we can see the repository of the
code, but the code that I've been working on is right here in this branch here. So
here we see the same code structure that we've been working on throughout this
course. Now the Visual Studio Team Services environment even gives you the ability
to edit source files inside of the browser. When I click here, for example, on one
of the controllers, in this case, the HomeController for the Promos area that we've
worked on, we can see and directly edit here inside of the browser. Now it's not
something that I use very often, but sometimes it can be useful to make a small or
quick change when you don't have access to Visual Studio. The second tab, the Work
tab, gives you the overview of all the tasks, the bugs, and basically the product
backlog for the project. So for example, here I can create a new product backlog
item, deploy to Azure, I can add it, I can then edit it in more details. We can
now, for example, assign this to myself in this case, save and close it, and now
the product backlog task has been created. VSTS also comes with its own Scrum
board. From here you can actually manage your project, you can move it to different
tasks into the different links. In this case, by default we have a couple of lanes
which are configured by default, that is the to do lane, the in process lane, and a
done lane. Now we are going to be mostly working with the Build and Release tab in
this module. So as you can see, by the way, there's a Build and Release sub-menu
item here, and we're going to be using those in this module. The builds landing
page contains the build definitions that I've created. We'll see in the next demo
how we can work with these. In the Releases tab, we'll be able to see our actual
releases that we have done. There's also a Test tab that can be used to manage the
testing part from VSTS. Finally, there's also a wiki that you can use to manage all
the project information in one central location available to all developers. The
little wheel here gives you access to the different options that you have in your
VSTS environment. We'll be using a few of these options later in this module as
well. So although this is a very brief overview of the features of VSTS, it should
give you an idea of what VSTS is capable of.

Setting up Continuous Integration


I hope that you're now on board with what VSTS really is, and what it can do for
you and your team. In the next topic of this course, I will use VSTS to set up
continuous integration for our ASP. NET Core site. If you've never heard of
continuous integration, don't worry. Let me explain first what it's all about.
Basically, continuous integration, or CI, allows us to frequently integrate all
changes that were made to the code base and verify that everything still works.
Imagine that you're working on a project, and you are working on some code. You
have made quite some changes and you have verified that everything is working fine.
That is, you have verified that this is working on your local machine, your local
build seems to be working fine. You think, good job! This feature is ready. Let me
check that in. So you come in to change this back to the source control system.
Meanwhile, a colleague has done some other changes and for him or her too, the
local build is working fine. Your colleague is happy too, and is checking in the
code after a successful local build as well. Although for the both of you, the
local version of the code is working fine; it might very well be when you want to
build the merge version of the code that things start to fail. This might be
because of a conflicting change, a reference which has gone wrong. There are so
many things that could cause the merged version to fail building. If we set up a
build up on every check-in, we will detect early that something has gone wrong, and
we can take the appropriate action. This is the benefit of continuous integration.
VSTS has support for setting up continuous integration easily. For starters, it
will work as a build server, and we can create a build linked to any check-in of a
team member. So basically, as soon as a developer checks in code, we can kick off a
build. We can link a build to a test, a work item, a check-in, and so on. Now to
perform the build, VSTS comes with the ability to use something called a hosted
agent. A hosted agent is basically the process that will perform the build for you,
so there's really no need to start setting up a separate build server yourself.
Once the build has run, we're getting a lot of information about the build. This
includes diagnostic information, reports about any failed test that the build has
encountered, and so on. As mentioned before, VSTS of course works great with. NET,
including. NET Core projects. However, CI builds can also be set up for other
platforms. So as mentioned, in order to set up continuous integration, we will need
to define a build which will kick in when a check-in is made by a developer. For a
build to trigger, we of course need to define the build first. In fact, I should
say that we need to define the build definition first. Now to do this, VSTS has the
Builds and Releases tab, which you can see here in the screenshot. The screenshot
that you see here dates from June 2017, so by the time you're watching this course,
things may have already slightly changed. You will, by the way, see a lot of things
change frequently in the UI of VSTS. Using VSTS, creating a build definition isn't
very hard. Out of the box it comes with a number of pre-created build definitions
that you can use as a starting point. These include a regular Visual Studio build
definition, a build definition for Xamarin, and the Empty build definition. Very
often, we'll start from the blank one, as that of course gives us the most
flexibility right out of the box. When we are creating a build definition, or
editing an existing one, by the way, we can see the different build steps, which
define the build. The build definition is as mentioned a sequence of steps that
will be executed sequentially for the build to complete. These individual build
tabs each perform a certain task, and for this step we can define the properties of
the step. Using these properties, we can configure the build step. VSTS has a large
set of build steps that we can use to create our build definitions. They are
grouped based on their category in the task catalog you see here. In the upcoming
demo, we'll add some build steps that are specifically created for the build of
our. NET Core application, which is what we need to do here. VSTS shows us an
overview of all build definitions that we have created in the environment. A build
definition defines how the build should be done. It contains all instructions, the
so-called build steps that need to run for the build of the code to work. Here you
can see that I have created a single build definition already, and I've given it a
name, BethanysPieShop - CI Build. For our build definition, we can trigger a build
manually, or we can also specify that the selected should execute when we perform a
check-in. When we trigger a build, we're basically queueing a build. This means
that we are asking the build server to perform the build for us, so we're asking it
to execute the different build steps for us. We can see here in the screenshot
which build agent entry we want to use for the build. A build agent is basically
the process that will perform the build. By default, VSTS comes with a local agent,
meaning that it is a process that's hosted by Microsoft Forest in the cloud. We can
also select the version of the source. Once we're done in this screen, we can click
OK, and the build will kick off. Once we have started the build, well, we have time
to grab a cup of coffee. The build agent is now building. While it does that, you
will get console output, which we'll see happening in the upcoming demo. Once the
build has finished, it is, by the way, also goes for a continuous integration,
you'll hopefully see that the build has succeed. Whether or not it has succeeded,
you will get an overview of the build results, including what the unit tests did
and much more, and I'll show you this in the demo.

Demo: Setting up Continuous Integration


Now that you are already in the know about builds in VSTS, let's go to the demo and
create a first build definition for our ASP. NET Core project. Once we have done
that, we will execute the build, and finally we will configure CI for this build
definition as well. In this demo, we are going to see how we can create an
automated build. Now the first thing that I have to do is, of course, creating a
build. And I've already done that, but I'll show how I've done that in this demo.
When you go to the Build and Release step, and then you click on builds, well, then
you arrive on this Build Definitions page. From here, you have the ability to
create, well, a new build definition, and let me show you that first. So there's a
New button that will quite logically take us to a page where we can create a new
build definition. Here we get the ability to start from an empty process, which is
what I've done, or you can also choose to start from an already created build
template. Very recently Microsoft has added an ASP. NET Core build template that
you can use to get started from. I'm not going to be doing that here, I'm going to
use, well, the manual way. So what I've done is I've started out from this empty
build definition. Let's take a look at my build definition that I'm using here to
automate my builds. So, the build pipeline that I've created is the one that you
see here, well, let's click on that one. And then we see basically a summary of
what this build definition has been used for. From this page, I can also edit my
build pipeline, and let me start by doing that first. So I'm going to click here on
the Edit button, and then you can basically the different build steps or tasks
which are required for this build definition. Now the first line here, so the
process, gives me the ability to manage a couple of general properties, such as the
name, and then also the default agent queue. Now the agent queue that you're going
to be using is basically the agent who's going to perform your build. Now very
importantly, the default hosted agent does not support. NET Core 1. 1. If you want
to perform a build for. NET Core 1. 1 or higher, you have to select the Hosted
VS2017 agent queue. Otherwise, you'll get some very weird errors. It took me awhile
before I figured that one out, by the way. Now next you can see here my different
build steps, or tasks, that will be performed in a sequence by VSTS when it's
performing the build. The first step is, well, pretty simple. It's used to
basically define which sources I want to build. By default, I want to use my
BethanysPieShop repository and in there I want to build the BethanysPieShop.
Advanced. Note that you can also, for example, directly build from GitHub a remote
repo or even a subversion repo. Now the build steps that I'm using are command-line
build steps, as you can see here in the list. Now in here, I'm going to use the.
NET executable, and I'm going to pass it arguments to instruct the. NET executable
what to do with my application. So the first step that I'm doing here is called Run
dotnet, and the tool is dotnet as you can see here. I'm going to do dotnet restore.
Now dotnet restore is the command-line way to restore the dependencies in my
project, so this will then basically download all the necessary packages to my
build server, which is of course, VSTS. Once that step has succeeded, well, then
I'm going to go to this second step, which I've also called run dotnet. Maybe my
naming convention here isn't optimal. But notice now it's still the dotnet tool,
and then I'm going to be publishing. Now dotnet publish will basically compile the
applications and then publish the results to a certain directory. The first
parameter, the c, accepts the build configuration. Now the build configuration, as
you can see, is prefixed with a dollar sign. That means that it is actually a
variable in VSTS. Indeed when I go to the Variables tab, you will see here that
BuildConfiguration by default is set to Release. Of course we can change it, but
typically that will be the version that I'm willing to release. The -o parameter is
basically where I want to output my artifacts, so basically whether I want dotnet
publish to boot everything. Now when you go to the Variables tab, you won't see
that variable here. That's because this is a built-in variable in VSTS. I've also
specified the working folder here, and by the way, you can also enable or disable
this step using this checkbox here. But of course, we'll leave it enabled. Next
I've added this archive files step here, which is basically going to create a zip
file out of the staging directory. In the final step, well, then I'm going to
publish the build artifacts. Publishing basically means making them available, and
the part that I'm going to publish is that zip file that I've created in the
previous step, and I'm giving it the name drop, and you'll see that return in just
a second. If you want to add additional steps, well, there's the Add Task button
here at the bottom from where you can add new tasks. And this you can see this
quite a lot, and it can also be found under these different categories here. Note
that if you're in need for an additional build task, you can go to the marketplace
where you can find many others. All right, so now the build pipeline is set up,
we're now ready to queue a new build. Well, let's do that. So we're going to click
here on Save and queue, and now I'm going to be asked to queue a new build, and
remember, by default it should jump to this Hosted VS2017 agent queue, but if it
doesn't, don't forget to set it to this particular agent queue. Well, this is
indeed the shelves that I want to build, so I'm going to now queue this build. It
now says here that a build has been queued. So we can click on this here, and now
at this point the build is still in wait. And there we go, the build has started.
You will see console output of your build process in the browser here, which is
very cool to follow along if everything is working correctly. So we're now going to
see a lot of output appearing, I'm going to be fast-forwarding and show you the
results. Well, there we go. The build has succeeded. As you can see here, a green
message is showing us that everything went according to plan. On the left here, we
see all the succeeded steps. We can click on either of these, and then we can see
the logs from them. Now the summary allows us to also view a timeline, the
artifacts, well, that's an important one, and remember that in the build steps, we
had that drop location that we defined, well, that's exactly what has been created
here. We now have the ability to get access to what has been built on the build
server in VSTS. You can download the file, or you can explore it, and you'll see
here that inside this drop folder here, there's the build number. zip, which is the
zipped compiled version of our application. Now I haven't included any build steps
to work with testing, but if I would have done that, well, then also in this Tests
tab, we would see the test results. All right, so now the build has succeeded,
we've set up the build pipeline correctly. But there's one thing that we were
actually looking for as well, and that's an automated continuous integration build.
Now I haven't set that up yet. Let's go back to the build definition, and then
click here on Edit, and in here I have the Triggers tab. And here in the Triggers
tab, I can enable continuous integration, meaning that whenever now a check-in will
happen, automatically a build will be triggered.
Automating the Deployment to an Azure App Service
We've now successfully been able to automate the build for Bethany's Pie Shop.
That's great. In the first introduction course, we've also deployed the application
to Azure. Why don't we automate a deployment of the site to Azure as well? Let's do
that as the last topic for this course. Now you may be thinking, why is it useful
to automate a deployment of the site? Well, we are entering the realms here of
continuous delivery. We've covered continuous integration where the builds were
automated. We can take things a step further and deploy continuous as well.
Continuous delivery comes down to being able to release a software, in this case,
Bethany's Pie Shop, frequently. With continuous delivery, we are going to release
to a production-like environment frequently, so perhaps to a staging environment.
On this release, we will run automated tests and these can then be repeated at any
time. This means that if the tests and the deployment ran successfully, we can
afterwards deploy safely to production. We can even extend on this and go to
continuous deployment. In this scenario, we will basically say that once we have
done a change and it passes the automated tests, it will be deployed to production.
While that may sound pretty dangerous for many companies, it will take a lot of the
stress when it comes to making a big bang release. Of course, continuous deployment
won't be possible for every company to implement. Now that you have a bit of a
background on why we should even consider automating deployments, let's see how
VSTS handles this for us. VSTS can perform an automated deployment in several ways.
It can work with Git or GitHub so that it pulls the sources and performs the build
and deployment for us. That's one way to automate the releases with VSTS. Secondly,
we can use another component of VSTS called Release Management. A Release
Management is a component of VSTS which allows us to create and automate releases
based on builds we have defined in VSTS. Release Management is itself quite large,
and it's in itself a tool large enough to build an entire Pluralsight course about.

Demo: Automating the Deployment to an Azure App Service


To finish this course, let's explore how we can automate the release of Bethany's
Pie Shop to an Azure App Service. Well, in the final demo of this course, we are
going to take a look at how we can create an automated release to Azure. Now
there's a couple of things I need to show you before we can actually build that
release definition. The first thing I need to show you is how you can basically
link your VSTS account with your Azure account, because that will be necessary in
just a minute. Click here on the Settings, and then click on Services. And in here,
you need to add a new Service Endpoint and select Azure Resource Manager. Here you
can then give that connection a name, and you can select your Windows Azure
subscription. That's mine that is appearing here. Once you have done that, it will
appear here in the list, and that will be as mentioned necessary in just a second.
And the next thing that I'm going to do is I'm going to create an Azure Web App to
which I'm going to release or deploy Bethany's Pie Shop. So, let's go to the Azure
Portal and then create a new web app. I'm going to search here for web app, click
on Create here, and then I need to give it some information for the creation of my
web app. I'm going to call this bethanydemo4. It's going to be in my Azure
subscription. I'm going to be using an existing resource group. A resource group is
just a way to group resources together, so you can also afterwards delete them. So
I'm going to put that in my Pluralsight resource group. Of course, it's going to be
on Windows, and then I'm going to click on Create to have Azure create my web app
for me. So there we go, it has now started the deployment. So success! The
deployment has succeeded. The web app is now ready. Let's now go back to VSTS. In
VSTS, let's now go to Releases. And here you can see the release definitions I have
created. It's called the New Azure App Service Deployment. Let's first take a look
at this release definition. Click here on Edit, and then we can see the release
definitions details. In the release definition, I have now just one environment, so
I only need to deploy this particular app. We can add additional environments. For
example, if you need to deploy different applications together, well, then you add
new environments here. In this case, my release definition only has one particular
task, and that is deploying to an Azure App Service. Very similar to the build
task, well, this one also has a couple of properties. The first thing that you need
to select here is your Azure subscription. This should be showing up when you've
added it like I've shown you before as a service in VSTS. Next I'm going to select
the App Service name to where I'm going to deploy. I've just created a new app, so
I'm going to have to refresh that list, and if we're lucky, well, there we go,
bethanydemo4 is available. All right, so let's save that. And now the release
definition is ready. Let's go back to the builds and click here on the latest build
that we've done. And what I'm now going to do is I'm going to create a release
based on this build. So here you see a release button. Let's click on that one.
That's going to allow us to deploy Bethany's Pie Shop using the release definition
that we've just created. The build I want to deploy is build 146. Well, let's
create that release. Click on Create here, and we'll see what happens next. I
started the release, let's go to the Releases tab again, and now you can see that a
build is currently pending. I can double-click this line here, and also here I can
see that the deployment status is in process. And we are lucky again. The
deployment has succeeded. Now this of course says that the deployment has
succeeded, but is our website actually live? Well, let's take a look. Let's go here
to our Pluralsight Resource Group, and in here we have bethanydemo4, which was
deployed to bethanydemo4. azurewebsites. net. Well, let's try if that one is live.
Our fingers crossed. And there we go, Bethany's Pie Shop is live using an automated
build and an automated release in Azure. That's great! Now I do have to make a
small confession here. There's one thing that I haven't shown you, and I also
haven't automated for the purpose of this demo. And it is the database connection
string. I've cheated a little bit. I've basically changed the database connection
string to the SQL Azure database that I already created in the intro course. Just
to make sure that you can also update this, well, go to Code here in VSTS, and in
BethanysPieShop. Advanced, in the src folder, open the appsettings. json, and that
should show you the connection string through the SQL Azure database which your
data for Bethany's Pie Shop is residing.

Summary and Course Closure


We've reached the end of the last module of this course, in which we have focused
on using VSTS in combination with our web application. I hope that it's clear that
VSTS can make the life for the enterprise. NET Core developer a lot easier. We've
seen how we can easily set up CI, so continuous integration, as well as deploy the
site automatically to Azure App Services. And that concludes our time together here
in this course as well. I hope that you have learned a lot of new things that you
can readily apply in your day-to-day job as a. NET Core developer. The only thing
that I still need to do is congratulating you on completing this course. I hope to
see you again in another course here on Pluralsight. Thanks for watching. Bye-bye!

You might also like