· 6 years ago · Jul 08, 2019, 04:12 PM
1Course Overview
2Course Overview
3Hi everyone. My name is Mosh Hamedani, and welcome to my course, Become a Full-Stack. NET Developer. I'm a software engineer and author with 15 years of professional experience. The demand for full-stack developers who are comfortable with both front-end and back-end development is increasing constantly, and in fact some companies only hire full-stack developers. In this course, you're going to learn the core front-end and back-end skills that every full-stack. NET developer must know. Some of the major topics that we'll cover include building beautiful user interfaces, building back-end APIs, object-oriented programming, clean architecture, and automated testing, and you're going to learn all these in the context of a real world application. So if you have always wanted to see how professional developers start from a requirements document and deliver working software with clean code, clean architecture, and automated tests, this is the course for you. This course comes in three parts. The focus of the first part is on the fundamentals of full-stack development. So, by the end of this part you'll be able to get the requirements document for your next project, extract the core use cases that have the most impact on the design and architecture of your application, and implement them end to end in a systematic way. Before beginning the course, you should be familiar with ASP. NET MVC 5 and Entity Framework 6. I hope you'll join me on this journey to learn full-stack development with Become a Full-Stack. NET Developer course at Pluralsight.
4
5Course Introduction
6What You'll Learn
7Hi, welcome to Become a Full-stack. NET Developer. My name is Mosh Hamedani, and I'm going to be your instructor over the next few hours. In this course, you're going to learn the core skills that every full-stack. NET developer must know, and you're going to learn all this as part of building a real-world mini social networking application using ASP. NET MVC 5 and Entity Framework 6. Whether you are a junior-level developer and want to learn a systematic approach to build applications end to end or you have more experience and want to strengthen your front-end and back-end development skills, this course is for you. Now let me give you a sneak peak of what we're going to build. We are going to start with a default MVC project template, which looks pretty boring. And over a few iterations, we're going to turn this into a simple social networking website for live music lovers. So musicians can sign up and list their upcoming gigs, and their followers can see all the upcoming gigs on the home page or search for them by artist, genre, or location, and then they can add their favorite gigs to their calendar, and here's the interesting part. Once a musician updates or cancels one of their upcoming gigs, users who are attending that gig will see a notification here on the navigation bar when they log in. As part of this, we'll be exploring a lot of front-end and back-end development topics, such as Bootstrap, CSS, usability, Entity Framework Code First, RESTful APIs, security, object-oriented design, clean architecture, automated testing, and much, much more. Along the way, I'm going to share with you lots and lots of shortcuts that I use on a daily basis to write code fast. And not only that, I will also show you how to refactor poorly-written code into clean, maintainable, and elegant code that speaks. And here's my promise to you. If you watch all the videos in this course and do the exercises, by the end of watching this course, both your front-end and back-end development skills will be at the next level. Are you ready? Let's get started.
8
9Prerequisites
10Now, in order to follow along this course, at a minimum you should have some basic familiarity with ASP. NET MVC 5 and Entity Framework 6. If not, you may find this course a little bit challenging at times because I'm not going to teach you the fundamentals of these frameworks. Most of our focus will be on building a real-world application. Now just to clarify, you don't have to be an expert in ASP. NET MVC or Entity Framework. Just some basic familiarity is enough. Okay, next, I'm going to explain how I have structured this course so you know what's coming up.
11
12Structure
13So this course is actually part of a series, and currently there are three parts in this series. The first part is most suitable for junior developers. I get a lot of emails from my students telling me that when they're given a project they don't know how to get started. What should be the next step? So in this part, we'll start with the requirements document, and then I will show you how to extract the core use cases that have the most impact on the design of our application, and then we'll build them in a step-by-step fashion over the next few hours. So the focus of this part is to teach you software engineering mindset, how you should think like a software engineer, how you should get a problem, break it down into smaller problems, and solve them step by step. Now, as part of this, we'll also touch on various aspects of front-end and back-end development, such as Entity Framework Code-First workflow, Bootstrap, data validation, security, artistic aspects of building user interfaces, usability, shortcuts, and so on. In the second part, we'll implement the notification system that you saw in the demo. In this part, there'll be a lot of emphasis on object-oriented design, building APIs, and using Bootstrap to build modern applications. And, finally, in the last part, we'll look at architecture and automated testing. Now, chances are, you are a bit more experienced, and you may want to skip the first part or two. While you're welcome to do that, my recommendation is to start from the very first part and treat this like a real-world project that you start and finish. If you jump straight to the second or third part, you may think I'm coding too fast or you may be wondering why I have done things in a certain way. If that's the case, you've really got to go back and start from the beginning. If you have watched any of my courses before, you know that I don't waste your time by fluffing or mucking around, so I highly recommend you to watch all the three parts thoroughly and go through the exercises I give you along the way. If you do so, I can guarantee that by the end of watching this series you're going to be an advanced full-stack. NET developer. So the introduction is finished. In the next section, we're going to kick off development.
14
15Creating a Visual Studio Online Account
16Alright, now you need to create a visualstudio. com account. So, head over to visualstudio. com, and in the middle section you should see Visual Studio Online. Click Get started for free; you will need to log in with your Microsoft account. And there is a very simple form for registration, so fill it out, and then when you sign up you're going to see a page like this. So under Accounts you can see the URL to your account. In this case, my URL is programmingwithmosh. visualstudio. com. So, click this here. Okay, now we need to create our project. I'm going to call this project GigHub. Leave Process templates as is because in this course I'm not really going to teach you agile or scrum. We're simply going to use visualstudio. com for a bit of planning and using Team Foundation Servers as our version control system. Next, click Create project. Alright, our project is created. In the next module when we get to extracting use cases from requirements, you're going to get back here and do some work.
17
18Setting up the Development Environment
19Alright, now open up Visual Studio. We need to connect our team project that we created in the last video, so go to the View menu and select Team Explorer. Next, click Select Team Projects, and this we know we should see the Team Foundation Servers that we have registered in Visual Studio. Currently there is none, so click Servers, Add. Here you need to type the URL of your Visual Studio Online account. So that's your name,. visualstudio. com. In my case, it's programmingwithmosh. visualstudio. com. Okay. Next you need to log in. (Typing) Alright, beautiful. We registered our Team Foundation Server in Visual Studio. Click Close. Now under Team Projects you should see GigHub, the project that we created earlier in the last video. So, let's take that and connect. Alright, we are temporarily done with the Team Explorer window, so I'm going to close it. Next, we need to create an ASP. NET MVC project. So we'll go into the File menu, New, Project. On the left side we select Web, ASP. NET Web Application. We give it a name, GigHub, and I'm going to store it in my C drive in the Projects folder. Be sure to tick Add to source control because we want to add this project to Team Foundation Server in our Visual Studio Online account. Okay. So from the template we select MVC, and click OK. The first time it's going to take a few seconds, so be patient because some files are going to be downloaded from the internet. Alright, beautiful. The project is created. Now in the Choose Source Control dialog, make sure Team Foundation Version Control is selected. You can use Git if you prefer and know how to use it. It's entirely up to you, but in this course I'm going to use TFS. Click OK. So in the next dialog you see our GigHub project is selected. Click OK. Alright, we're done. So, we connected to our Visual Studio Online account, then we created a project, and now we need to commit our project to the repository. If you have not worked with source control repositories, the idea is you have a source code repository somewhere on a server and you have a working folder on your machine. So every time you're working on a piece of functionality, you modify your code and then commit it to the repository. On the repository, essentially we have a database of your source code. Every modification of every file is stored in the repository. So the benefits are you can always look back in the history and see the older versions of your files, you can undo things, you can compare files, and so on. So now we created our project, we need to commit it to our repository. So back to Team Explorer window, now click Pending Changes. Let's scroll down a little bit. So, the files you see here are the files in our project, and as you see all of them have the state of add. They are new files. So at the moment our project has 211 files that we're going to commit to the repository. In the future, as we are implementing different functions, we may modify only a few files, so when you want to commit your code to the repository you're going to see only those few files in the Included Changes area. So, scroll up. We're going to give this commit a comment. A comment is like a label that we attach to each commit, so later when we look in the history, we know what each commit is all about. I'm going to call this Initial commit, and Check In. So all these files are now going to be uploaded to your Visual Studio Online account, it's going to take maybe a few seconds, so please be patient. Beautiful. Changeset successfully checked in. Now I need to show you some of the plugins that I'm going to use in this course. If you have seen my other courses, you should know that I'm a huge ReSharper fan. ReSharper is a commercial product for which you need to get a license. Now the good news is you can get a 30-day free trial version of ReSharper, and I highly recommend you to get it in order to code along with me in this course, and then later you can decide if you want to use ReSharper or not. If you don't want to use ReSharper, I will still show you alternative ways of writing code in Visual Studio. So don't worry if you don't want to get ReSharper, that's perfectly fine. There are two other plugins that I use here, and they both are free. So, go to the Tools menu, under Extensions and Updates, on the left side click Online, and here search for Productivity Power Tools. There you go. So, that's Productivity Power Tools 2013, and you can see by this green icon here that I have already installed it in my Visual Studio. In your case if you don't have it, you'll see a button to install it. Anther plugin is Web Essentials. There you go. So Web Essentially 2013. 5. So be sure to install these two free plugins, and ideally ReSharper as well, to ensure your coding experience will be as close as possible to mine.
20
21Extracting Core Use Cases from Requirements
22Introduction
23One of the questions that a lot of junior developers ask me is, "Mosh, when I'm given a project, I don't know how to start. "I don't know what to do next. " So that's one of the first things we want to cover in this section. I'm going to show you a requirements document and then you will see that over a few steps, I will extract the core use cases that can have the most impact on the design of our software. So instead of implementing each feature end-to-end and fully polished, we want to implement these core use cases first. Because implementing these use cases early on will give us an idea of the challenges involved in this project. With all that, now let's take a look at the requirements document.
24
25Requirements Document
26Typically, software development starts with a requirements document. Sometimes a requirements document can be half a page or it can be several pages long. Irrespective of that, your job as a software engineer is to extract the use cases from the requirements document. In this video, we're going to take a look at the requirements document for our project called GigHub. GigHub is a a mini social network that makes it really easy for live music lovers to track the gigs of their favorite artists. Artists can sign up and list their gigs. When adding a gig, they should specify the date and time, location, and genre of the gig. An artist should have a page called My Upcoming Gigs. From there, they should be able to edit or remove an existing gig, or add another one to the list. Users should be able to view all upcoming gigs or search them by artist, genre, or location. They should be able to view the details of a gig and add it to their calendar. Additionally, users should be able to follow their favorite artists. When they follow an artist, they should see the upcoming gigs of their favorite artists in the Gig Feed. This is a reasonably simple requirements document. It could expanded in more details, but it doesn't really matter at this stage. Details can come later. Plus, they will often change over time. So, don't rely too much on the early requirements document. What we should do now, instead, is to extract the use cases, or high-level features, from this requirements document. We should express these use cases using only a few words. As an example, in the second paragraph we have two use cases, sign up and add a gig. Expressing these use cases using only a few words make it really easy to communicate with other team members or the client. We don't have to go through pages and pages of detailed requirements document. The idea is to form a basic understanding of high-level features. Details can come later when we get closer to implementation. So pause the video now and spend a minute or two finding the use cases in this application. Write them down on a piece of paper and in the next video you can compare your solution with mine.
27
28Extracting the Use Cases
29Alright, here are the use cases that I have extracted from our requirements document. On the authentication side, I found sign up in the requirements document. But the other use cases you see here, like login, log out, change password, and edit profile, were not really spelled out in the requirements document. That's why I said don't worry too much about the early requirements document. Use it as a tool to give you a high-level understanding of what this project is all about. As you progress, you need to use your own judgment or communicate with the business or the client, whoever you're making the software for, to fill the missing parts. In this case, I realized if we have sign up we should also have login, log out, and other use cases you see here. Now, before were proceed any further, I got some good news. We're not going to spend any time implementing any of these use cases. Because they all come with ASP. NET Identity package which is part of ASP. NET MVC 5 project template by default. You'll see this shortly when you start coding. Okay, next. Other use cases I found include add a gig, my upcoming gigs, edit a gig, remove a gig, view all upcoming gigs, search, and view gig details. Next, I found add a gig to calendar in the requirements document. But remove a gig from calendar and view gigs I'm attending were not there. So that's, again, another example where I used my own judgment to fill the missing parts. If you're going to give the user the ability to add a gig to their calendar, they should be able to view all gigs in their calendar and remove one or more if they want. Next set of use cases. Again, following an artist was in the requirements document, but the next two use cases were not spelled out. And finally we've got gig feed here. Alright, now to keep track of these use cases as we implement them, we're going to put them in our backlog in Visual Studio Online.
30
31Adding Use Cases to the Backlog
32So, open up your browser and go to your Visual Studio Online url. In my case, it's programwithmosh. visualstudio. com. When you login, you're going to see this home page. Under recent projects and teams, you should see GigHub, the project that we created in the last module. So, click GigHub. Now here on the top, we've got a few tabs. Code is our source code repository. It shows the latest code as well as the history. Work is where we're going to do our planning. Build is used for a continuous integration and Test is for automated tests. Let's go to Work. Alright, this is where we plan and manage the requirements of our project. So, let me close this ToolTip. With Stories selected in the backlog, here we can enter our use cases. So I'm going to enter a couple of them and then I'm going to pause the video to save your time. So, let's say Add a gig. Enter, that's it. Edit a gig. So I want you to pause the video now and enter all the use cases that we extracted in the last video into our backlog.
33
34Dependency Between Use Cases
35So we have extracted the use cases and entered them into our backlog. In order to identify the core use cases that affect the architecture of our application, we need to work out their dependency first. For example, we cannot unfollow an artist without following them first. Also, in order to follow an artist, we need to view the list of gigs or the details of a gig, because that's where we're going to display the name of an artist. So next to each artist, we can have a button to follow them. So in this diagram, I'm showing the dependency between use cases using a dashed arrow. Based on these dependencies, the order in which we need to implement these use cases is like this: So we implement view gigs first, then follow an artist, and finally unfollow an artist. So here's your exercise. Pause the video and spend a few minutes working out the dependency between these use cases. Don't worry about the use cases related to authentication. Just focus on the core of the application. And by the way, to keep things simple, assume that each use case is dependent only on, maximum, one other use case, not many use cases. Once you work out the dependency between all use cases, start with the ones that have no dependency to any other use cases. Put a number next to them. I call this number, Order. Once you determine the order for each use case, organize them in a layout like this. In the next video, you can compare your solution with mine.
36
37Order of Use Cases
38Okay, I hope you spent a few minutes and did your exercise. Here's my analysis of use cases and their orders. In the first column, we have add a gig. This is the most fundamental use case. If our application doesn't have the ability to add a gig, there is nothing a user can do. They cannot browse or search them, neither can they add them to their calendar. So everything starts from adding a gig. Once we implement add a gig, we can implement view my upcoming gigs. This is going to be the page where an artist can see all the gigs they have added. And from there they can edit or remove a gig. Also, once add a gig is implemented, we can display all upcoming gigs on the home page. On this page, we can give the user the ability to add a gig to their calendar. Then we can create a page where they can view gigs they're attending and remove them from their calendar. In the list of upcoming gigs, next to each artist you're going to put a button to follow that artist. So once we implement view all upcoming gigs, we can implement follow an artist. Subsequently, we'll create a page for the user to see who they are following and, on that page, they will be able to unfollow an artist. Also, when they follow an artist, they should be able to view their gigs in the gigs feed. And finally, when we implement view all upcoming gigs, we can give the user the ability to search for gigs or click on a gig to view its details. Now, if you're solution was similar to mine, that's great. But if not, it doesn't matter. It doesn't mean your solution is wrong. Chances are you envisioned the application and the flow data in a different way and that's perfectly fine. What matters here is that there is always an order when it comes to implementing each use case.
39
40Extracting the Core Use Cases
41Okay, we have determined an order for implementing the use cases. Now it's time to identify the core use cases. These are the use cases that shape the domain of our application. They often involve capturing data and change the state of the application. So from this list, which use cases do you think are the core use cases? Adding a gig changes the state of our application. So it's definitely a core use case. In the second column, we don't have any use cases that change the state of the application. They all are reporting use cases. What about the third column? Here we have a few use cases that change the state of the application, such as edit a gig, remove a gig, add a gig to calendar, and follow an artist. But I don't see edit a gig as a primary or core use case because it's very similar to add a gig. Once we build a domain model that allows us to capture a gig, editing or removing it shouldn't have a major impact in our domain. So they're out. Adding a gig to calendar, however, requires extending our domain model. For each user, we need to keep track of the gigs they're attending. So this is another core use case. And the same applies to follow an artist. For each user, we need to keep track of the artists they follow. Now look at the fourth column, we don't have any primary use cases because all these are for reporting. What about the fifth column? Removing a gig from calendar is kind of similar to adding a gig to calendar. Same goes for unfollowing an artist. Both these use cases are extensions of the core use cases in the third column. So we have add a gig, add a gig to calendar, and follow an artist. These are the most important use cases that we need to tackle first. Now there's a tiny problem here. If we implement only these three use cases in our first iteration and show the application to a user or our client, there's no way they can see if a gig is added to the database or not. So we need to pick one or more use cases as supporting use cases to report on the state of the application. We can pick either of the use cases in the second column, but I prefer to pick all upcoming gigs. Because on this page, we're going to allow the user to add a gig to their calendar or follow an artist. So this page, or this use case, bridges the gap between the core use cases in the first and third columns. We're going to use this technique one more time. Once we implement the use cases in the third column, there is no way for the user to see if the application is working. So I'm going to pick two use cases from the fourth column. View gigs I'm atttending and Who I'm following. Again, these use cases are not really core use cases, but I use them as supporting use cases to build a piece of functionality end-to-end. This will help us build the skeleton of our application and gradually add new features to it. Once the skeleton is ready, we can also write automated tests using Selenium to test the application functionality end-to-end.
42
43Planning the First Iteration
44Introduction
45Okay, so we got our Core Use Cases. Now, we're going to put that in Team Foundation Service, or TFS, to keep track of our work. You could use any software that gives you the ability to keep track of what you have done, what you're currently working on, and what is remaining. Next, we're going to sketch a basic user experience for our application. Sometimes, if you're working in a team, you might have a person dedicated as a web designer or UX Designer, but other times, you have to do it yourself. What I want you to take away from this section is to give yourself the habit of grabbing a piece of paper and sketching a basic user experience. Decide how the user will navigate from one page to another, what elements do we have on the page? How does the navigation bar look like? It's much easier to draw this on a piece of paper than jumping into HTML & CSS. With all that, now, let's get started.
46
47Assigning Use Cases to the Iteration
48All right, so we are in Visual Studio Online. With the Word tab selected, under Stories, here, we've got the Use Cases we extracted in the last module. Now, I'm going to move the Core Use Cases that we identified into Iteration 1. So to refresh your memory, we've got Add a gig, All upcoming gigs, Add a gig to calendar, Follow an artist, View gigs I'm attending, and Who I'm following. So back here, I'm going to drag Add a gig and drag it into Iteration 1. Now, we can see that in the Iteration path column, it's set to Iteration 1. I'm going to do the same thing with other Core Use Cases. So View all upcoming gigs, Add a gig to calendar, Follow an artist, View gigs I'm attending, and Who I'm following. Now, let's click Iteration 1. So here are the six Use Cases that we're going to focus on in the first situation. Just to clarify something, in case you have experienced working in Agile Teams, you probably know that the concept of Iteration (mumbles) is usually two to three weeks long, and often, it involves other practices which are beyond the scope of this course. So here, I'm purely using Iterations as a way to organize my thoughts, as a way to keep track of what I'm currently working on and what I should do next. Now, one last thing I want to do here is I want to reorder these Use Cases in the order that we determined in the last module. So we should implement Add a gig first. I'm going to drag this and drop it on top of the list. Next comes View all upcoming gigs. So drag and drop. Then, Add a gig to calendar, Follow an artist, View gigs I'm attending, and finally, Who I'm following. So this is the order we're going to implement them. Now, we go to Board tab. I'm going to change this date of Add a gig Story from New to Active. Later on, when we finish this Use Case, we're going to change its state to either Resolved or Closed, and this way, we can keep track of what we're currently working on and what is left.
49
50Sketching a User Experience
51Before we start coding, wanted to sketch a simple User Experience. We want to determine how a user will navigate through the application, and remember, this User Experience does not have to be perfect at this point. It's based on the scope of this Iteration, so don't try to figure it out what the final application with all its features is going to look like. We want to sketch the simplest User Experience, based on the features we're going to implement in this Iteration. Later on, as we implement more features, we can tweak the User Experience and make it better in a step-by-step fashion. So we're going to give the user the ability to Add a gig to start with. We need a form like this where they can enter the gig details. Now, the first question we should ask here is, "What should happen when the user clicks the save button? " Ideally, we should redirect them to the list of their upcoming gigs so they can edit or remove a gig if they made a mistake, but we don't have this Use Case in this Iteration. Instead, we have View all upcoming gigs. So temporarily, we'll redirect them to the list of all upcoming gigs, which can be on the Home page, for now. In this list, in front of each gig, we can put a button called Going with a question mark. When the user clicks on this button, the color and the label of this button will change, and this gig will be added to the list of gigs they're attending. This is similar to how we follow people on Twitter. Now, once the user adds a gig to their calendar, they should be able to see it. So we can dedicate a page for this and put a link to it on the navigation bar. Similarly, in front of each artist in the list of gigs, we'll have a link or a button called Follow. When the user clicks on this button, its label will be changed to Following, and the artist will be added to the list of artists they're following. We'll add another link on the navigation bar called Who I'm Following, which takes the user to the list of artists they're following. So our Navigation Bar is going to look like this. On the left, by convention, we should have the name or logo of the site which takes us to the Home page. On the right, we'll have a Login link, which will be replaced by the name of the user once they log in. Now, when we click on this link, a drop-down list will appear, which will include the pages that are accessible only by this currently logged in user. So here, we'll have two links, Gigs I'm Attending and Who I'm Following. We'll also have a link to Sign Out.
52
53Building a Model Using Code-first Workflow
54Introduction
55In this course, I'll be using Code-first Workflow of Entity Framework to build a domain model. So in this section, we're going to build a very basic domain model for our gigs, and use Code-first migrations to generate the database and populate it with some reference data. Now, let's get started.
56
57Enabling Migrations
58The first time we use Code-first Workflow, we need to enable migrations. To do this, we go to the TOOLS menu, under NuGet Package Manager, Package Manager Console. Here we type enable-migrations. Okay, done. Just remember that this is a command that you run only once, at the beginning of your project. The first time you're going to use Code First Migrations. Now, if you have never worked with Code First Migrations before, the idea is that every time we make a change to our domain model, we create a migration, and run it on the database. Entity Framework will update the schema of the database, so we never have to go to SQL Server and manually modify tables. We do everything with code, which is much faster and easier. Plus, as you will see shortly, we'll get full versioning of our database. Now, in terms of best practices, we should aim for small migrations. So, we'll make a small change to the domain model and create a migration. We'll review it, and run it on the database. One of the reasons some developers fail to use the Code-first workflow is because they don't follow this practice. They make a lot of changes all over the place to the domain classes, and then end up with a gigantic migration, which may totally mess up with the schema and the data in the database. So remember, small changes, small migrations. Now, the default ASP. NET project already has a few domain classes, so the first thing we should do is create a migration for these domain classes before creating the domain classes for GigHub. Otherwise, we'll end up with one big, fat migration. Let me show you these domain classes. So, under Models, open up IdentityModels, look, here we've got ApplicationUser, which derives from IdentityUser. IdentityUser is part of ASP. NET Identity, which is a package that controls all the aspects of authentication and authorization. That's why earlier, I told you that we don't really have to write any code for signup, login, log out, change password, and stuff like that. Everything is automatically done. So ASP. NET Identity package has a few classes that are encapsulated in its assembly, like the concept of a user, role, and stuff like that. I'm going to create a migration so you can see the tables that will be used by ASP. NET Identity to control authentication. So, we go back to Package Manager Console, cls to clean up, add-migration. We need to give it a name. This is an arbitrary name. So I'm going to call it InitialModel. All right, now, take a look at the Migrations folder here. Inside this folder, we have a file. The name of this file starts with a date time stamp. That's the time we created this migration. After the date time, we have _ and the name of our migration. Now look at the code here. InitialModel is actually a class that derives from DbMigration. It has a method called Up, and inside this method, we have a number of calls to the CreateTable method, so this migration expresses in C# what tables need to be created in the database. So as you see, we're going to have a table called AspNetRoles. So these are the roles in the system if you're going to use them, like admin, user, whatever. Let's scroll down. We've got AspNetUserRoles. So these are the roles for each user, and a few other tables like AspNetUsers, AspNetUserClaims, and so on. So I'm going to go back to Package Manager Console and run this migration on the database, cls to clean up, update-database. So you see, the initial model migration is now applied to the database. Let's take a look at the database and see the generated tables. So where is the database? In Solution Explorer, go to App_Data, and note that there is currently no files in this folder because by default, files that are not part of the project are not displayed here, so we need to click this icon here, Show All Files. And you see here, we have a file with extension. mdf, so this is our database file. I'm going to double click it, let me close all these windows. All right, here is the database, under Tables. So we have a table called _MigrationHistory, which is used internally by Entity Framework, so it keeps track of the migrations that have been run on the database. And here are the tables that are used by ASP. NET Identity. Now, before going to the next step, which is creating domain classes, we need to commit our code to the repository. So this is a mindset that I want you to get used to. You make a small change, and commit your code to the repository. When I first started with version control systems, I thought that I had to implement a feature end-to-end before committing my code to the repository, but that was the wrong mindset, and it created a lot of headache for me. So, you've done a small change. Let's commit our code to the repository. We go to Team Explorer. If you don't see this here, go to the View menu, and select Team Explorer. And let me close this because we don't need it. So here, click Pending Changes. As you see here, under Included Changes, we have five modified or new files. Now let's give it a comment. So what did we do? We enabled migrations. That's it. I'll Check In. Beautiful.
59
60Creating Domain Classes
61All right, now let's start creating our domain classes. So, back in Solution Explorer, now under Models, I'm going to create a new class called Gig. Right click, Add, Class. Call it Gig. What properties do we need here? That was in our requirements document. So, for each Gig, we need to capture who's performing it, when, where, and what genre it is. So, let's start with the who part. We need to associate this class with another class that represents a user in GigHub. That class only exist in our default ASP. NET MVC project. So, open up IdentityModels. Remember ApplicationUser? That's the class we're looking for. So I'm going to close this window, and here, create a property of type ApplicationUser, and I'm going to call it Artist. Next, when is this going to happen? So another property. Just type prop, that's a code snippet, press Tab. Here we specify the data type, so DateTime, Tab, and we call it DateTime. Where is this going to happen? So we need to capture the name of the venue. So prop string Venue. What genre is it? For genre, we need another class. The class that has an ID and a name because we don't want to duplicate all these genres in the database. So, I'm going to create another class here, give it an ID. I believe byte is enough because we are not going to have more than 255 genres. And Name. Now, back here, and load the property, Genre, and we'll call it Genre. Now to keep my code clean, I want to move Genre class to a separate file. With ReSharper, that's pretty easy. We put the cursor here, press Alt and Enter, and the first option is Move to another file to match type name. If you don't have ReSharper, you need to manually copy this class, create a new file or a new class, and paste this into the new file. That's it. Now look, we've got a new file, Genre. cs, and our class is here. Back to the Gig. We also need an ID for each Gig. All right, now let me show you a cool trick. Look at these using statements on the top. Only the first one is used because the last three are grayed out. Now if I save the file, all those unused namespaces disappeared. How? So this is one of the features of Visual Studio Productivity Power Tools plugin. I love this feature 'cause I hate going and removing all these unused namespaces. I just write code, save my file, and the plugin will remove unused using statements on the top. So how does this happen? You need to enable this feature. So, go to the TOOLS menu, Options, collapse Environment, find Productivity Power Tools, expand this, click PowerCommands, and note that here, Remove and Sort Usings on save is checked. By default, it is not checked, so you need to come here and enable it yourself. You can also take the first one, Format document on save. All right, so we created our domain classes. Currently, we have only Gig and Genre. Not that I didn't create anything for keeping track of the Artists a user is following, or the Gigs they are attending because they are part of the future use cases, and the whole idea about iterative development is you write a bit of code, you test it, you make sure everything is working, and then move to the next step, as opposed to creating a gigantic domain model with a lot of capability and flexibility that we may not necessarily need, so we keep it simple and lean, step by step. Now, we created the domain classes, the next step is to create a migration to update the database. So, we go back to Package Manager Console. Now, one way is to open it up via the TOOLS menu as we did in the last video, but I'm going to show you how to create a shortcut so you don't have to do this all the time, 'cause we're going to use Package Manager Console a lot in this course. So go to the TOOLS menu, under Options, scroll up, under Environment, click Keyboard. Here you can define custom shortcuts for Visual Studio. So here, under Show commands containing, we type packagemanagerconsole. There you go, that's the name of the command. Now, note that here, I already have a shortcut for this command. I hold down Alt, and then / and. I found this a very easy combination, and it doesn't interfere with other shortcuts in Visual Studio. So, put the cursor here, hold down Alt, and press / and then. which is on the left of /, and then click Assign, and finally, OK. So, Package Manager Console, clean up, add-migration. We should give it a name. CreateGigTable. This is an arbitrary name. You can call it anything you want. All right, now let's take a look at this migration. So it's right here. There is nothing there. It's one of the issues that sometimes you may encounter when using Code-first Workflow. So I missed one step, and it's great that happened, so I can show you how to fix it. We created this domain class but nowhere there is a reference to it, so Entity Framework does not know about the existence of this class in our domain model. How do we add a reference to it? We go to Solution Explorer, and Models, open up IdentityModels. Now here we have two classes. One is ApplicationUser, which you saw earlier. Another one is ApplicationDbContext that derives from IdentityDbContext. So here we need to add a DbSet of type Gig, so Entity Framework will know about our Gig class. And we're going to call this Gigs. Now Gig already has a reference to the Genre class, so Entity Framework will be able to find the Genre class, but if you want to query the list of Genres, you need to add a separate DbSet here. Genres. Now, before going any further, I want to clean up this code because I don't like to have two classes in one file. So, put the cursor here, with ReSharper, it's very easy, Alt and Enter, and Enter. Now Control + Tab to get back. So, in IdentityModels, we have ApplicationUser, and I don't like that the name of this class is different from the name of the file. So again, we can fix it with ReSharper very easily. If you don't have ReSharper, you need to manually rename this file in Solution Explorer to ApplicationUser. So Alt and Enter. The first option is Rename file to match type name. Beautiful. Let's review what we have in the Models folder. So now we have ApplicationUser, Genre, Gig, ApplicationDbContext, and a couple of other files that we'll take a look at later. So, let's clean up our workspace. First, we need to save all files, so the shortcut is Alt and F, and L. Save all. Now close all windows, Alt and W, and L. Now we go to Package Manager Console again, with our shortcut Alt with a / and. clean up, and execute add-migration one more time. Now if I do this now, we're going to see an error because we only have a migration by that name, so I'm going to use the force switch to overwrite it. All right, now let's review this migration. Beautiful. So this migration tries to create the table called Genres, with two columns, Id and Name. Id is a Byte, it's not nullable, because in C#, the Byte type is not nullable. Genres also has a column called Name, which is a String, and its PrimaryKey is set to the Id column. Let's scroll down. We also have the Gigs table, with the columns you see here. So these columns are based on the properties in our domain classes. Note that here, the PrimaryKey of this table is set to Id column, and here we have two ForeignKeys. One on Artist_Id column, which is linked to AspNetUsersTable. Another one is on Genre_Id column, which is linked to the Genres table. So the last step is to run this migration to update the database. Back to Package Manager Console with Control and Tab, Update-Database. Beautiful. Now let's inspect the database and make sure everything is fine. So, we go to Server Explorer, right click Tables, Refresh. Look, we've got two new tables here, Genres and Gigs.
62
63Overriding Code-first Conventions
64All right, now there is a tiny problem here. Let's right click the Gigs table, and go to Open Table Definition. Note that the type of the Venue column is nvarchar of MAX, and it allows Nulls. The reason for that is because in C#, strings are nullable, so Entity Framework Code-first uses a concept called convention over configuration. So it has a lot of conventions built into it, and based on these conventions, it creates these tables. These conventions work most of the time, but not always. In this case, I don't want to have a Gig without a Venue. It doesn't make sense. Also, the length of this column is a bit too much. I think 255 characters is enough. Look at the next column, Artist_Id. This column is also nullable, which doesn't make sense because each Gig should have an Artist. Now I guess you're curious why its type is nvarchar and its not an integer. The reason for that is, in the ApplicationUserTable, the PrimaryKey is of type nvarchar of 128, so that's how ASP. NET Identity is designed, and at this point, I don't have a comment whether it's a good practice or not, so, we'll just leave it for now. Look at the last column, Genre_Id. Again, this column is nullable. So now, we should override Code-first conventions. How do we do it? There are two ways. We can use Data Annotations or Fluent API. Data Annotations is easier, but it has limitations. Fluent API is more powerful, but it's a little bit more complex. So for now, I'm going to Data Annotations to keep the ball rolling and we don't get lost in detail. And later on, we can refactor our code and use Fluent API. So we need to open up the Gig class, and apply a few attributes. First, let's clean up our workspace, so Alt and W, and L. Now, to open up the Gig class with ReSharper, it's very easy. We don't have to go to Solution Explorer, and scroll up and down. You press Control + Shift and N, and here we type gig. There you go, the first option is Gig. cs. Obviously, if you don't have ReSharper, you'll need to go to Solution Explorer, and find that class here. In case Control + Shift + N shortcut does not work for you, that's because you're using a different keyboard scheme, so go to the RESHARPER menu, under Options, under Environment, click Keyboard & Menus. So I'm using ReSharper 2. x or IntelliJ IDEA keyboard scheme. So if you want to use the same shortcuts as me, change your keyboard scheme to ReSharper, in case it's set to Visual Studio. All right, so in a Gig class, first, we want to make sure that Artist is not nullable, so we apply the Required attribute. This class is part of System. ComponentModel. DataAnnotations. So because I have ReSharper here, as we press Enter, it automatically adds this using statement on the top. If you don't have ReSharper, you need to right click here, and you will see an option on the top called resolve using statements. Next, I should make Venue Required, so... Required, and I want to limit its length to 250 characters, so StringLength is another attribute, and here, we're specify 255. And finally, Genre should be required. Now in terms of clean coding, note that here, the properties that are decorated with attributes have a vertical line break. Like Genre, with Required, there is a line break here. Venue, there's a line break here. But in case of Artist and DateTime, they're right next to each other, so when you quickly look at this code, it's a little bit hard to distinguish them, so I'm going to put a vertical line break before DateTime to have consistency in my class. All right, let's save the file. Now we need to go to the Genre class and apply another DateTime notation. So again, with ReSharper, we can use Control + Shift + N, and go to Genre. So I want to make sure that Name is Required. Here, ReSharper detected that this attribute is part of System. ComponentModel. DataAnnotations, so we can immediately resolve it using Alt and Enter, and I want to limit its length to 255 characters, so StringLength(255). Save. Now Package Manager Console, hold down Alt, /. clean up, add-migration, OverrideConventionsForGigsAndGenres. Let's review this migration. So the first four statements here try to drop the ForeignKey and the Index on the columns we are going to modify. Next, we have AlterColumn, so in the Genres table, the Name column now is being changed to String that is not nullable, and its length is 255 characters. Similarly, in Gigs table, the Venue column is going to be set to a String that is not nullable, and is limited to 255 characters. So the other AlterColumn statements are similar, and finally, we have CreateIndex and AddForeignKey because they were removed at the beginning. So you see, with a small change, our migrations are small. When we make a lot of big changes, our migrations are going to be huge, and it's hard to know the impact on the database. All right, now let's go to Package Manager Console, clean up, Update-Database. Beautiful. Let's inspect the database, so Server Explorer, right click Tables, Refresh, right click Genres, Open Table Definition. Note that Name column is now nvarchar of 255. It's no longer MAX, and it's not nullable. Let's take a look at the Gigs table. Similarly, none of these columns are nullable. Venue is set to nvarchar of 255. All right, now it's time to commit our code to the repository. So again, clean up our workspace, Alt + W + L. We go to Team Explorer, under Included Changes, we have 11 changes, so you see we have a bunch of migration files, and under Models, we've got ApplicationDbContext, ApplicationUser, Genre, and Gig. Every time you want to to commit your code to the repository, I want you to go and inspect each of these files. If they're new, like the Genre class here, just double click it, open it, make sure your code is clean, everything is fine. If you have modified a file, you need to compare it with the old version to see what has changed, and I will show you that later in the course. So now, to save your time, I'm not going to go through each of these files. I'll leave it to you as an exercise. We just need to add a comment here, Create the gig model. Check In. Beautiful.
65
66Making Design Decisions
67OK, our model is ready. We also generated the database using Code-first migrations. Now, when it comes to adding a gig, I want the user to select a genre from a drop down list. We have two choices here. We can either implement a page for the admin to manage the list of genres, or we can simply populate the Genres table using a SQL script. Which solution is better? Well, first of all, implementing the Admin Page is not part of the project scope, so if you do that in the middle of creating a form to add a gig, we'll get distracted from the actual problem at hand, and this is one of the common issues among many software developers. They start working on problem A, and then they end up somewhere else. In situations like this, before adding anything to the scope of the project, the first question you should ask is, what is the cost of each solution and what are the benefits? The benefit with creating an Admin Page is that an admin can always come back and add a new genre to the list. They don't need developers' involvement, but implementing an Admin Page is a lot more costly than writing a simple SQL script to populate the Genres table. Now, the question I'm going to ask here is, how likely is it that the list of genres will change or grow? In reality, we have limited number of music styles. They don't change that often, so in my opinion, in this case, implementing an Admin Page is an overkill. It's waste of developer time and the project budget, so I'm going to go with the second solution. And by the way, it's your job as a software engineer to make such decisions. You should not rely on the business or the client to tell you which solution is better, because often, when you offer these two solutions to the business, they say they would rather the Admin Page because of the flexibility it gives them, so they don't need to get back to you to add one more genre to the database, but they may not take into account that the likelihood of them needing this page in reality is very low, so the scope of the project changes, and you will end up in an endless loop of adding new features. What's the end result? You'll pass the deadlines and the business blames it on you as the software developer. Then you'll have to work harder, and under pressure and stress, you won't be able to build quality software, so you will release many features without proper testing, and you know what's going to happen next. So, while it's good to keep the business informed of various solutions, at the end of the day, it's your job as a software engineer to make decisions that will impact the quality of the final product, and that's why we're called software engineers.
68
69Populating the Database
70So, I'm going to create a SQL script to populate the database. Now, since we're using the Code-first Workflow, everything starts with the code, so we are not going to make any modifications to the database directly. Instead, we're going to create a blank migration, and use that to execute our SQL script. So, let's open up Package Manager Console, add-migration, we give it a name, like PopulateGenresTable. Let's take a look at the migration. So, look, since we have not made any changes to our domain model, this migration is empty, so now, lets go to the Up method, and here, we can use the SQL method to execute any scripts. For example, INSERT INTO Genres, Id and Name, 1 and Jazz. We can duplicate this line with ReSharper using Control and D. If you don't have ReSharper, you need to copy and paste. Blues, Rock, Country. That's enough for now. Now one thing I want you to pay attention to is this Down method here. This method is called when we downgrade the database. With Code-first Workflow, it's possible to take the database to any versions. When we run Update-Database, by default, it goes to the last migration, but we can specify a target migration. In that case, it's possible that the database would be downgraded. So, as a good practice, whenever you're changing the Up method, make sure to modify the Down method to put the database in the right state. In this case, I have added four records in the Genres table, with Id's 1 to 4, so in the Down method, I should remove them. So whatever happens in the Down method is the opposite of what happens in the Up method. Now let's run this migration on the database. Back to Package Manager Console, clean up, Update-Database. Beautiful. Let's take a look at the database, so, right click Genres, Show Table Data. There you go, we've got four records here. So you see this approach is a lot simpler and faster than creating an Admin Page to populate the list of Genres. In this case, I only added four records here, but I could spend 10 minutes coming up with all possible music styles and put them here in this table. Plus, in the future, if we come up with a new genre, we can always create another SQL script and populate this table. All right, now that we have written a piece of code, it's time to commit our code to the repository. So, Team Explorer, under Included Changes, you see we have four changes, and these are the new files for our new migration, so let's give it a comment. Populate Genres table. Check In. Beautiful.
71
72Summary
73All right, let's quickly review some of the key points in this module. When it comes to building a piece of functionality, you can start from the UI, or the database, or domain. In this course, the emphasis has been on the domain. When building a domain model, build the simplest model that will work for the problem at hand. Don't try to model the entire universe. Only focus on the use case you are working on. You can gradually extend your model. With this, you will also end up with small code-first migrations. If you make a lot of changes in your domain, and then create a migration, you will end up with a big, fat migration that's hard to read, so it's going to be hard to assess the impact of the migration on your database. Also, as you write a little bit of working code, review your code, and commit it to the repository. Again, similar to migrations, if you make a lot of changes to your code, and then try to commit, chances are, you may commit some messy or broken code into the repository, and if you're working in a team, it's likely that this broken code affect the other developers in the team, so make small changes, review your code, make sure it's working and it's clean, and then commit. I can't emphasize the importance of shortcuts. If you want to be fast at coding, try to memorize the shortcuts for common actions you use. You don't need to memorize all shortcuts in Visual Studio. That's useless. Although remember the key things that you use often, so every time you try to switch to mouse, stop for a second, and see if there is a shortcut for what you're trying to do. And finally, remember, when solving a problem, evaluate different solutions, and assess the benefits and cost of each. At the end of the day, it's your job to make design decisions that impact the quality of the final software product. I hope you enjoyed this module, and I'll see you in the next module.
74
75Building a Form with Bootstrap
76Introduction
77Okay, our model is ready. Now we're going to build a form to create a new gig. As part of this section, I will show you how to use Bootstrap to build modern and pretty forms. You will also learn about view models, what they are, why we need them, and how to create them. Now let's get started.
78
79Adding a Basic View
80All right, we're going to build the view. In this video our focus is entirely on building a view. We are not going to worry about saving the data or validation, or anything else, just purely user interface. And by the way, I'm also not going to worry about aesthetics. I just want to have a simple form that allows us to capture a gig. So the first thing we should do is create a controller. Solution Explorer. Controllers, right-click. Add, Controller. So again, I'm assuming before watching this course you already have watched a course on ASP. NET MVC, because here I'm not going to talk about what is a controller, what is a view. You should already know all this stuff before taking this course. Now from the template, I'm going to go with an empty controller, because I'm going to create all the code from scratch. Add. I'm going to call it GigsController. Add. Beautiful. Now I'm going to change the name of this default action from Index to Create. Now let's build a simple view for this action. So, Solution Explorer. Under Views, create a new folder. Add. New Folder. We're going to call it Gigs, because it has to be the same name as the controller. Right-click. Add. View. The name of the view should be Create. Let's click Add. All right, before implementing the form I just want to make sure what I have done so far is working. So let's run the application with Control and F5. Beautiful. So if you go to /Gigs/Create, we're going to see this page. Now to make things easier, I'm going to put a link to this page on the navigation bar. So. Let's go to Solution Explorer. Scroll down. Under Views, Shared, expand this folder. Open up Layout. All right, let's scroll down. Okay. Here is the implementation of the navigation bar. So we have three links. Home, About, and Contact. I'm going to remove About and Contact and add a link to create gig. So that's the label, Add a Gig. The name of the action is Create. And the controller is Gigs. Before going any further, let's test this. Back to the browser. Control and R to refresh. Let's click Home, all right, here's the home page. Add a Gig, beautiful.
81
82Basics of Building Forms with Bootstrap
83Now let's build a form. So I'm going to right-click Create. cshtml. And select Close All But This to clean up my workspace. Now the first thing we need to specify here is the model behind this view. So the model is going to be Gig. ReSharper is detecting that the Gig class is defined in GigHub. Models namespace. So as I press Enter, it automatically resolves that. If you don't have ReSharper, you need to type the fully qualified name of the class. GigHub. Models. Gig. Now, to build a form, we're going to use Bootstrap. In case you are not familiar with Bootstrap, it's a CSS framework for building modern and responsive web applications. In this course, I don't have time to go through all features of Bootstrap, because that really requires its own course. But I'm going to give you some touch points that help you get started. So let's go back to the browser. Open a new tab. And go to getbootstrap. com. Now we go to CSS. On the right side, let's go to Forms. So here's the idea. If you want to build a form like this, you will have to use a layout as you see just below this form. So here's the layout. So on the top level, we have the form element. Then we have a few divs, each with the class form-group. Each form-group includes a label and an input. So you see the same structure in every form-group. Then for each input, we need to use the class form-control. This class gives your input element a modern look and feel. For example, look at this text box here. It has rounded corners, and if I click it, now it has a hover effect with a blue border. So this is the default theme for Bootstrap. We can always change it, which is what we're going to do later in this course. So all our input elements should have the class form-control. Now let's go ahead and implement a form with this structure. So back to Visual Studio. Form. I'm going to create a div with class form-group and use Control D to duplicate this line a few times. Now for the first one, let's put an input for the venue of the gig. So we're going to use MVC helper methods. Html. LabelFor. We use a lambda expression. m as in model goes to m. Venue. Next, we need a text box. Html. TextBoxFor. m goes to m. Venue. Let's save the form. Back to the browser with Alt and Tab. Control Tab to switch the tab, Control R to refresh. Now you see our text box does not have rounded corners. And that's because we didn't add the form-control class. So back to Visual Studio. As the second argument to the TextBoxFor method, we can supply an anonymous object for the attributes we're going to add to our HTML element. So I'm going to add the class attribute and set it to form-control. Note that here I have prefix class with an @ sign, because class is a reserve word in C#. Save, Alt and Tab back to the browser, Control and R to refresh, beautiful.
84
85Extracting a View Model
86Now let's add a text box for date. So in the second form-group, Html. LabelFor, m goes to m. DateTime. Now there's a problem here. The problem is our gig model has a property called DateTime, which captures both the date and the time. But typically, for usability reasons, we should provide two separate input fields, one for the date, one for the time. So how are we going to do this? That's one of the cases where what we're going to present to the user is different from our model of the domain. So in our domain model, the Gig class has the DateTime property, but we want a different kind of model where we have two separate properties. One for date and one for time. That's when we use a pattern called PresentationModel or ViewModel. So a PresentationModel or a ViewModel is a different class that is purely used for presentation. It's not part of the domain. So let's go to Solution Explorer. Scroll up. We're going to create a new folder called ViewModels. So right-click GigHub. Add. New Folder. ViewModels. And here I'm going to add a new class. Add. Class. I'm going to call it GigFormViewModel. GigFormViewModel. Add. So let's quickly create the properties we need. We need one for the venue, so string Venue. We need one for the date. Note that I'm using a string here, because on the client everything the user puts in a form is essentially a string. When it's posted to the server, we're going to parse these strings into objects of different types. So another one, prop string Time. Control Tab to get back to the Create view. On the top we're going to change the model of this view from Gig to GigFormViewModel. So delete. GigFormViewModel. Again, note that ReSharper automatically resolved the namespace for me. With that, now we can change this DateTime to Date. Now I can simply copy this TextBoxFor line and paste it here. And then change Venue to Date. Now we need a similar structure for the Time field. All right, now I want these two lines. Copy, go to the next form-group. Paste. Now we change this to Time. And similarly, here. Let's preview our changes up to this point. So I'm going to build a project because we added a new class, GigFormViewModel. To build a project, Control Shift B. Now Alt and Tab back to the browser. Control and R to refresh. Beautiful. Now later we can add a date picker and a time picker here. But that's going to come later. Let's just build the skeleton first.
87
88Adding a Drop-down List
89We need one more input field for genre. But that's going to be a dropdown list. So, back here. First we need the label, Html. LabelFor. m goes to Genre. Our view model does not have a property called Genre. So we can ReSharper to automatically create this. If you're not using ReSharper, just go back to the class and create a property. So here I press Alt and Enter. The first option is Create property Genre. I'm going to set the type of this property to integer, because with dropdown lists, we need the numeric value for each option. So this is going to be the Genre Id, as stored in the database. Now Control Tab back here. So we got the label. Let me scroll down a little bit. Now let's create a dropdown list. So Html. DropDownListFor. m goes to m. Genre. Now the second argument is the source of the dropdown list, the options we're going to put there. So in our view model, we need the list of genres from the database. So Control and Tab. A new property. IEnumerable of Genre. And I'm going to call it Genres. You could use a list here or a collection, but we're not going to add anything to this list or use any of its options using an index. So IEnumerable is the simplest interface that gives me what I want. Now back to the view. We need to create a SelectList. The first argument is the source of data, so that's going to be Model. Genres. The second argument is the name of the property and the Genre class that should be used for the values of these options. So that's going to be Id. The third argument, Name. So the Name property of the Genre class is going to be used for displaying the label of these options. Now, because we have changed our C# code, the view model, we need to build the project again before previewing. So Control Shift B. Alt and Tab back to the browser, Control and R to refresh. We got a null reference exception because we didn't populate the Genres property in the view model. So. That's the job of the controller. Let's open up GigsController. Control Shift N, GigsController. If you're not using ReSharper, you need to go to Solution Explorer and under Controllers open GigsController. So you see, ReSharper is a lot faster. So here, we need to get the list of genres from the database. The first thing we need is a DbContext. So. private ApplicationDbContext, that's the DbContext that comes in our project template by default. Namespace is resolved, and I'm going to call it _context. We need to initialize it in the constructor, so ctor, Tab, that's the code snippet. _context equals new ApplicationDbContext. Now in case you're a bit more experienced, you might ask, what about dependency injection? What about the repository pattern and stuff like that? Don't worry about these stuff at this stage. Let's focus on the problem we're working on, come up with a solution, and then we can gradually improve our solution. So don't get distracted by all this kind of architectural and design patterns. Now you got the context. We need to create a view model and set as Genre property. var viewModel equals new GigFormViewModel. And Genres equals _context. Genres. ToList. That's it. Now I'm going to put this view model inside the view. Let's build the application, Control Shift B. Alt and Tab back to the browser, Control and R to refresh. All right, we got a dropdown list here populated with our genres from the database. But there are two problems here. First, Jazz is selected by default. I want to have a blank item. Second problem is it doesn't have the look and feel of BootStrap. So it should have rounded corners, a bit of padding. That's because we forgot to add the form-control class. So back to view. Control and Tab. So here's a DropDownListFor method, right? Now I'm going to add a third argument, which is a blank string. That's our blank or default option. And the fourth argument is an anonymous object to add additional HTML attributes. Okay. Save, Control S. Alt and Tab. Control R. Beautiful.
90
91Adding a Bootstrap Button
92All right, and one last thing. We need to add a button here. So, back to Visual Studio. I'm going to delete these two form-groups, because we don't need them anymore. And instead, add a button. So, button, type should be submit. And value is going to be Save. Next we need to give it a class to give it Bootstrap look and feel. Now with buttons, all buttons should have a class called btn. Now depending on the type of button that you're going to add and the color you want to use, you will use a secondary button class. Let me show you what I mean by that. So back to the browser. Let's go to the Bootstrap page. And on the right side, click Buttons. And scroll down a little bit. Okay, look, we've got buttons of different colors. All these buttons have a class called btn. But they also have a secondary class that determines their color. For example, btn-default presents a white button. btn-primary is used for primary actions on a page and by default is dark blue. We can always change the color to match our theme. But the important thing here is, semantically we should use primary buttons or primary actions on a page. So I'm going to use btn-primary on our form. Back to Visual Studio. So btn-primary. Save, back to the browser, Control Tab. Control R. Mmm, the button appeared but the label is not there. That's because with buttons we should add the label not using the value attribute. So I'm going to remove this value here. Save, back to the browser. Refresh, there you go. So we've built a reasonable form. Now it's time to review our code and commit it to the repository. So back to Visual Studio. Alt and W and L. Let's go to Team Explorer. Look, we've got five changes. We've got GigsController, which is a new file. So double-click, let's look at the code. So the first thing I see is this green underline here by ReSharper. Whenever you see a green underline, that's where ReSharper has suggestions to make your code better. So let's put the cursor here and we can activate the suggestion using Alt and Enter. So ReSharper is suggesting to make this field readonly, because it's only initialized in the constructor and it's not going to be re-initialized anywhere else. Okay, now the green underline is gone. And also look at this comment. This was there for the index action that was part of the auto-generated code, so we don't need it. We can simply remove it with Control and L. Now let's go to the top of the file. We've got a bunch of unused namespaces, so Control and S. They disappeared. So this feature as I explained earlier is part of Visual Studio productivity power tools. So I'm pretty happy with this code and you see we've got a green tick here, which comes with ReSharper. So if your code is clean from ReSharper's perspective, you see a green icon, otherwise you're going to see a yellow if there are areas that can be improved or red if there is a compile-time error. Now back to Team Explorer. So we reviewed GigsController. Let's review GigFormViewModel. All right, the only problem I see here is these using statements on the top. So Control S. Done. And code is pretty clean. Team Explorer. We've got Create. cshtml. So that's our view. Seems all right. The only thing I want to change here is the label. So I'm going to change this to Add a Gig. Save. Team Explorer. Now look at Layout, Layout is modified. So we need to compare it with the old version to see the changes. So right-click, Compare with Workspace Version. So here on the left we've got the old version, on the right we've got the new version. And here we've got these highlights, so red indicates some code was deleted, whereas green indicates something was added. So if you scroll to the right, you can see that these two links on the navigation bar were deleted and instead we have a new link called Add a Gig. So that seems fine, there's nothing to improve here. Let's close it. Team Explorer, and the other changed file is the project file. And that's because we added a few new files to the project. So again, every time you write a piece of code, review it, make sure it's clean, improve it if required, and then commit it to the repository. Now we give it a comment. Create Add a Gig form. And Check In. Beautiful.
93
94Summary
95So let's quickly review what you learned in this module. We built a form using Bootstrap. Bootstrap is a CSS framework for building modern and responsive web applications. So if you use Bootstrap, not only can you give your applications a modern look and feel, but you will also get the benefit that your applications will look pretty good on mobile devices. And that's because of the responsive features of Bootstrap. Throughout the course, I will try to introduce you to more components in Bootstrap, but again, Bootstrap really requires its own course. You also learned about the View Model. We use view models in situations where what we want to display to the user is different from the model of the domain. A view model class gives us a clean separation and prevents user interface concerns to leak into our domain model. For example, in this module, in our form we wanted separate fields for date and time. We also wanted a dropdown list for genres. It would be a poor practice to modify our Gig class, which is part of the domain model, and add these extra properties to it. What would happen if we use this class in five other pages and every page caused a few more properties to be added to the Gig class? It would start to smell. So that's when we use a view model. All right, that's it for this module, I hope you enjoy it. In the next module, we're going to save a gig to the database.
96
97Saving Data
98Introduction
99OK, our form is ready. Now we need to save data. As part of this section, I'm going to talk about separation of concerns. Which is one of the areas that a lot of junior or even intermediate level developers struggle with. They write code where it does not belong. That makes their methods fat and un-maintainable. I will show you an example of a controller doing something that it shouldn't. Then, we will re-factor that and move that code somewhere else to improve separation of concerns. Now, let's get started.
100
101Limiting Access to Authenticated Users
102Before we implement saving, first we need to limit access to our gig form. We should only allow authenticated users to access this page Why? Because we need to associate the gig in the form with the currently logged in user as the artist. Let's open up GigsController. Control + Shift + N GigsController. We need to decorate or create action with the Authorize attribute. That's it. Let's run the application. Control + F5. And click Add a Gig, there you go. We are redirected to the Log in page. Let's quickly register a new user. Alright, I registered a new user. As you see on the top, I'm currently logged in. Now, if I go to Add a Gig, I can see the form. Now we are ready to save the Gig because we'll capture all the details of the Gig and we know the currently logged in user.
103
104Adding the Target in the View
105Okay, back in Visual Studio. Let's open up the Create view. Control + Shift + n Create If you are not using Re Sharper, you need to go to Solution Explorer, expand views under Gigs, open up create CSHCML. Alright, now we need to change something here. We need to specify the target for this form. So that's the action that's going to be executed when we post this form. I'm going to replace this form element here with begin form method in asmap and anbc Again, I'm assuming you already know how to create forms with asmap and anbc. So, let's quickly get this done, using HTML, begin form, We need to specify the target action. I'm going to call it Create that's in the GigsController. Now, I'm going to cut the content of the form element and paste it into my using block. Let me show you an awesome Re Sharper shortcut. So imagine you want to select everything inside the form. The slow way is to hold down the shift and use the down arrow like this. A better way is to use Control + W. This is Re Sharper's super awesome selection tool. So I can hold down the control and continue pressing W. As you see, my selection is being expanded. If I make a mistake, and I want to shrink my selection, as I'm holding down the control, I will also hold down the shift and use W. Now, I have selected the content of the form element. Cut. Paste. Let's delete this form element here. Next, we should implement the Create action.
106
107Saving Data
108So, let's close this window, Control +F4, Open up GigsController, Control + Shift + N. Gigs, Controller. I can hold down Alt and press down arrow. So, we can jump between different methods of a class. See? That quickly brings me up here. Let's add the new action. So, I'm going to call it Create. But here we're going to have a parameter of type GigForm ViewModel, because that's the model behind the view. So when we post the form, that's what we're going to get in the create action. So, GigForm, ViewModel. Now, we need to decorate this action with a couple of attributes. The first one is Authorize, because we want to make sure that only authenticated users can call this action. The second one is HTTP Post. Because we want this action only to be called only by our HTTP Post method. Next, we need to convert that ViewModel to a GigObject added to our context and save changes. So, gig equals new gig. We need to set the artist. We need an application user object here, so we have to get it from the database first. Something like this, context. Users. Single use a lamnda expression I want to get a user whose ID is. now to get the ID of the currently logged in user. We use the user property of the controller.. identity. GetUserId so that returns an application user object that I can associate with this Gig. Next we need the daytime, so our view model has two different properties, one for date and one for time. We need to combine them into daytime object. For the purpose of this video don't worry about validation. We are assuming everything that the user has put in the form is valid data. We are going to address validation next. So that is the kind of mindset I want you to get used to. Instead of trying to tackle all aspects of a problem, focus on one aspect, solve it, then move to the next aspect. So, assuming the values that the user puts into the date and the time fields are valid, we can combine them using daytime. parce. So, daytime. parce, here I use string. format. Two place holders. The first one is going to be viewmodel. date. The second is going to be viewmodel. time. Next is the genre. Here we need to associate this gig with a genre object. So similar to the artist, we need to read it from the database first. So, context. genres. single, I want a genre whose ID is viewmodel. genre. So the genre we have in view model is an integer and that is the value of the currently selected option. So we got the genre, we can set that here and finally venue, so viewmodel. venue. We have a gig object. We need to add it to our context, so it can be tracked by any of the framework and then we call save changes. At this point, a new framework will generate a sequel statement and execute it against our database. Now as we discussed during our planning, in this restoration, temporarily we are going to redirect the user to the homepage. Then in the next use case, we are going to replace home page with a list of all upcoming gigs in the database. So, return, redirect to action, then the name of the action is index and the name of the controller is home. Now let's run the application, control +F5. So as you see I am still logged in. Let's go add a gig, fill out the form. We got an exception. Link to edit does not recognize the method get user ID. So that is happening in our create action in the first line. I deliberately wrote this code so you could see this error. That is one of the errors that sometimes you may encounter with editing framework. So basically, the lambda expression we have here is going to be stored as an expression object. When editing framework tries to execute a query, it gets this expression object and tries to translate it to sequel statements. When translating this expression to sequel, editing framework has no idea what is user, what is identity, what is get user ID. Because this is purely c sharp code that does not have representation in sequel. So to work around that is to extract that expression and store it's value into a separate variable. So, back here, in the first line I am going to declare an integer, artist ID, and set it to this expression here and replace it. Now artist ID will have a numeric value, so this lambda expression here can be successfully converted to sequel. So let me show you a technique now. I saved the changes with Control + S. Build the application with Control + Shift + B. Back to the browsers with Alt + Tab. Now instead of wasting my time and filing out the form again, I am going to post this form one more time. So simply press Control + R and click continue. Okay, we are redirected to the home page, so I am assuming that the record was inserted into the database. Let's verify that, back to visual studio. Let's go to server explorer, so that's the gig stable. Right click, show table data. Beautiful.
109
110A Bit of Optimization
111Alright, so here is the implementation of our create action. There is something here that I don't quite like. Look at these two lines here. These lines will issue two queries to the database which are not really necessary. So, when the user tries to add a gig, we will end up with three round trips to the database. Two for getting a genre artist and a genre object and three for adding a gig to the database. The reason we are querying an artist and a genre here is to associate them with our gig object here. So how can we resolve this issue? Let's take a look at our gig class. So, I put the cursor here, with Control + B we go to the definition of the gig class. Alright, here is the artist and genre properties. We call these properties navigation properties, because they allow us to navigate to a different entity in our domain model. To address the issue in the controller we can introduce what we call a foreign key property like artist ID or genre ID. This way we can simply set their value without querying a complete application user or genre object, so I am going to add a property here. The reason the type of this property is a string and not integer is because in the application user class which is part of aspn identity, the ID property which is a key is defined as a string. So each user is uniquely identified using a guide, which is stored as a string. Now I am going to move this required attribute and apply it to artist ID, because we want to make sure that this foreign key property is set, not the artist navigation property. Now I am going to do something similar with genre. So prop, byte, genre ID. The reason this is a byte is because in a genre class earlier I defined the ID property which is the key as a byte and then I am going to move required to this foreign key property. Save. So we have changed our model. We need to create a migration. Package manager console, remember the short cut? Alt/. Add migration. Add foreign key properties to gig. Alright, so in the first line our new framework tries to rename artist ID column and the gig stable to artist ID and it is going to do something similar to genre and finally it will also rename the associated indexes. So now let's run this migration on the database. Cleanup. Beautiful, let's inspect the database. Double click gigs. So, not bad artist ID and genre ID no longer have an underline in their name. Domain model is modified, database is modified. Now let's go to gigs controller and remove those unnecessary queries. So I am going to replace artist with artist ID and genre with genre ID which is viewmodel. genre. Now we have a convert term here, let's see what's happening. Cannot convert source type ent to target type byte. The reason for that is in our view model I declared genre as integer and in our domain model I defined it as a byte, so it is easier to make them consistent as opposed to using the convert class to convert an integer to byte. So with the cursor on the genre property on the view model, I press Control + D, jump here in the view model and change ent to byte. Save. Control + tab, back here and the error is gone. Now look at this two lines here. Artist and genre are grayed out because they are no longer used, so delete. Also, we don't really need to get the current user ID, store it in this artist ID and then set it here. That is like an extra noise in the code, so we can get rid of it, with Resharper, it is very easy. I am going to press Control + Shift + R, to activate refractory commands. The first option is inline viable, so Resharper got rid of the viable and simply added this expression here in front of artist ID. So now as you see the code, it is cleaner and it doesn't involve two unnecessary round trips to the database. Let's run the application and make sure everything is working. So add a gig. Redirection worked, so I am assuming the record was inserted successfully. Let's verify it, back to visual studio, server explorer, right click gigs, show table data. There you go, you've got two records here. It's time to review our code and convert it to the repository, so to save your time I am not going to review the code. I'll let you do it as an exercise. I am just going to open up team explorer and check in the latest changes. Implement saving a gig.
112
113Refactoring for Better Separation of Concerns
114There is one more thing I don't like about the implementation of this action and that is this line here. The problem we have is poor separation of concerns. You are making controller responsible for parsing a string value into daytime object. This is not the responsibility of a controller. The controller should act as a coordinator for the application logic. What should happen next? That is the job for a controller. So p arcing value it is too detailed for the controller to know as a metaphor, think of a manager, a manager often doesn't do the actual work, well it depends, but usually the job of a manager is to manage one or more people. Those people do the actual work and the manager is purely for the coordination for the supervision, so our controller here should be like a manager. Now where should we implement this functionality of parceing a string into datum object. In object oriented programming, we have a principle called information expert and that means that the class or the object, that has the information to do something should be the one that will carry that responsibility. Again I use a metaphor, think of a chef. A chef knows about recipes, food poisoning, and stuff like that, so he is the one that does the cooking, not the waiter. In this case our view model is the class that knows about date, and time. So combining these two values and returning a datum object should be the responsibility of the view model. So I am going to select this line with Control + W, so I hold down control and press W, There you go, cut with control + X. Here I am going to type view model. datetime. Obviously we don't have this property, that is why it is red, so I am going to create it with alt + enter. The second option is to create read only property datetime. There you go, resharper brings us to gig form, viewmodel. The type of my new property is set to daytime, so I accept it by pressing enter. Now I am going to get rid of this private set and turn this get into a block of code. Return, Control + V, to paste, semi colon. Now because we are inside the view model, we don't need viewmodel here, so delete, delete. Let's build the application with control + shift + B. Beautiful, now ideally we should test the application now and make sure our re-factoring hasn't broken anything, but to save your time I am not going to do it during recording, but I want you to do it as a habit. Now the final step is to commit our code to the repository. I prefer to have my re-factorings in separate comments. So to explorer, again here I expect you to go and inspect each file, right click, compare with work space version, review what you have done. Make sure you are committing clean code to the repository, and let's give it a comment, move daytime calculation to gig form, view model, check in.
115
116Summary
117All right, let's quickly review the key points in this module. We used the authorize attribute to limit access to an action to authenticated users and then we used User. Identity. GetUserID to get the ID of the currently logged in user. As we explained in this module, in aspn identity the ID property of the application user class is a string, which is actually going to be stored as a string, so remember that. Next we looked at foreign key properties. The benefit of foreign key properties is that they save us from unnecessary queries to load related objects. Now while this is a benefit on one side, some developers don't like foreign key properties, because they think they add a bit of noise to our domain model and they are not really object oriented. I personally do not have any problems with adding foreign key properties to my domain model, because in my opinion, adding a few properties is better than running unnecessary queries on a database. And finally we looked at the information expert principle of object oriented programming, which helps us to determine where to delegate responsibilities, so we use this to move the responsibilities of parceing a data object from controller to the view model. So in your projects, when you are trying to assign responsibility, first you need to determine the information required to fulfill that responsibility and then you need to see where that information is stored. So wherever it is stored, that is where you should put that responsibility. I used a metaphor. A chef knows about the recipes, so he or she is the one that will be responsible for cooking, not the waiter, at least in the restaurant and that brings us to the end of this module. In the next module, I will show you how to add validation to our form. I hope you enjoyed this module and thank you for watching.
118
119Implementing Validation
120Introduction
121Okay, this section is all about validation. So, we're going to apply some standard data annotations on our input fields, and we'll also implement custom data annotation, from validating date and time fields. Well, let's get started.
122
123Adding Server-side Validation
124All right, now let's implement validation. I'm going to start with server-side validation. So, let's go to our view model, Ctrl + Shift + N, GigFormViewModel I'm going to decorate the properties here with data annotations. As a first step, I just want to mark them as required. Later, we'll work on custom validation for date and time. So, required, again, ReSharper is resolving the namespace, if you're not using ReSharper, these data annotations are in system dot component model dot data annotations. Now, a line break, for clean coding, required again. I'm going to copy it. Line break, paste it. Line break, paste it. Add another line break between genre and genres. Save, that was the first step. Now we should go to the view and add placeholders for validation messages. So, close with F4, Ctrl + Shift + N, Create, I want to add a validation message placeholder for each input field. So, let's start with the venue, html dot validation message for, m goes to venue. Copy, paste. This one is going to be for date, next one for time. And, last one, for genre. And the last step is to modify the controller. We don't need this view anymore, so I'm going to close it with Ctrl + F4. Gigs, controller. So in the Create action, we should check to see if the model is valid. If not, we're going to the same view. Otherwise, we're going to redirect the user to the home page. So if Model State, which is a property of the controller, is valid, I'm going to apply the NOT operator here, so if it's not valid, return. I'm going to return the Create view, and use the view model past to this method. So when they return the view, all the existing values will be displayed in the input fields, along with validation messages. Let's run the application with Ctrl + F5, add a gig. So I'm just going to click the Save button. You got an exception. String was not recognized as a valid DateTime. So this is in our DateTime property in the view model, where we are trying to parse the date and the time. Technically, this code should not be executed. Let me show you why. So, Active Visual Studio. So here in the action, in the Create action, this is where I have referenced that DateTime property. But look, here I added a conditional check. So if the model state is not valid, I'm going to return to view. So, we should never get to this point. Then why are we getting that exception? The reason is, when a sped up dot embassy tries to call this action, it uses reflection to construct the view model here. And as part of this construction, it's going to touch all properties of the view model. So, for each property, it inspects the HTTP request to see if there is a value by that key. So in order to fix this issue, we need to convert this property to a method. This way, isp dot but embassy is not going to touch that DateTime property using reflection. So, let's go to Gig Form View Model. My cursor is right here, on the Gig Form View Model. I press Ctrl + B to jump there. Hold down the Alt and press down, come down here, I'm going to rename these to Get DateTime. To rename, we use F2. So all references are renamed automatically. F2 GetDateTime. And now I'm going to convert it to a method which means we don't need the getter anymore. So I'm just going to select this expression using Ctrl + W Ctrl + X, get rid of this, Ctrl + V. See, when you use your shortcuts, coding is very effortless. Now, back to the controller. We need to make a tiny change here. So, because GetDateTime is a method, we need parentheses here. Ctrl + Shift + B to build, Alt + Tab, back to the browser. I'm going to repost the form by pressing Ctrl + R. Continue. Okay, that exception is gone, but we got another exception. Value cannot be null. And, that's happening here, in the view, when we are trying to render a drop-down list. The reason for that is because Genres is not populated. Let's go back to the code. So when we get here, model-state is not valid. We have a Gig Form View Model. You're going to return the Create View with This Object. Genre's property in this object is not initialized. Because this view model is just a new object that is initialized with the values in the extra TV request. So, I'm going to put a code block here. Before returning the view, I'm going to set the genre's property of view model, using context dot genres dot ToList. This is exactly what we did earlier when returning the Gig Form. All right. Ctrl + Shift + B to build. Back to the browser. Refresh. Beautiful, our validation is working. So we got an error message next to each input field. Now ideally, these error messages should be red. But I'm going to work on that in a later video where my focus is purely on the user interface. For now, I just want to make sure everything with validation is working.
125
126Implementing Custom Validation for Date
127Okay, now that we got basic validation working, we need to implement custom validation for date and time. I want to make sure what the user puts in the date field is a valid date and is in the future. Now, at the time of recording this, we don't have a validation like that in our data annotation's namespace in dot Net. So we need to implement it ourselves. So, let's go to Visual Studio. Solution Explorer, under View Models, I'm going to create a new class. And call it FutureDate. This class should derive from Validation Attribute. Resharper resolves the namespace. Now we need to override is valid method. This method has two overloads. The first one is protected and gets two arguments. I'm interested in the second one, which is the easier one. This one takes only one parameter. Before implementing this, let me show you how we're going to use this. So let's go to our view model, Ctrl + Shift + N, Gig Form, View Model. I'm going to apply this to the date property, FutureDate. So, at run time, let's go back to the FutureDate class, this value here would be the value of the Date property. First we want to make sure it's a valid date. So we need to parse it. Now, date time dot, we can use the parse method, and then catch an exception, or alternatively we could use triparse. This method returns a Boolean. So if the conversion is successful, it will return true. Otherwise, it will return false. We also have triparse exact. With this method we can specify a format for the date or the time. Typically with dates and times, it's easier if we assume a default format for our web application. So on the forum later, I can show you how to add watermarks to our input fields so the user knows what is the format that application is going to accept. And in the future we can also extend the application such that if the user enters a value in a different format, we can automatically convert it to our acceptable format. So let's use triparse exact. The first argument is a string. So we need to convert the value past here to a string. Convert dot to string. I didn't call the two-string method on the value because it can be null. Second argument. Best of format. So let's say I want a one-digit day, three-letter month, and four-digit year. The third argument is an I format provider. Which is an object that supplies culture-specific formatting information about the string. So by default the culture is English and United States. So I'm just going to go with that. We can get that from culture info dot current culture. The benefits of using this property is if you override the culture in web dot config, you can get it here. Next parameter is an enumeration called date time styles. Honestly, I have no idea what this does. And I read the documentation, I couldn't figure it out. So, I'm just going to go with the simplest one which is date time styles dot none. That does the job for me. And the last argument is a date time object. So if the conversion is successful, that will hold the date time representation of this string. So, we need to declare a date time here, and then use the out modifier and pass it here. Now the code is looking a little bit ugly in terms of formatting because on the first line we've got three arguments and then we have two arguments here. So I'm going to break it up like this. One argument on each line. Now, I'm going to store the result of conversion in a Boolean variable called isValid. The next thing I want to check here is that this date time is in the future. So, we can write a Boolean expression like this. And get rid of the last line. We save the file, let's build an application, Ctrl + Shift + B, back to the browser. First I'm going to put a number there. So, one, one, one, save. Alright, we've got the message the field date is invalid. So far, so good. Now let's try a date that is in the past. The first of January 2010. Okay, so the validation is still working. Now we could customize this error message to differentiate between an invalid date and a date that is in the past. But at this point, I wouldn't worry about it.
128
129Implementing Custom Validation for Time
130All right, now we need to implement a validator for the time field. This is pretty similar to what we did in the last video. So I'm not going to explain everything one more time. Instead, I'm going to quickly write the code. So, in the FutureDate class, I'm going to select this class with Ctrl + W and duplicate it with Ctrl + D. There you go, here's a duplicated class, rename this to validTime. Alt and Enter to move it to a different file. Now it's in valid time dot C S, and last step I'm going to change the validation logic so we are looking for an hour and minute here. And at the end we're simply going to return isValid. That's it. Now we need to apply this attribute to our view model. So, Gig Form View Model. Here's the time property. Valid time. That's it. Let's run the application. So I put a valid date here, in the future. Let's say 20th of November 2016. I put one for the time. The field time is invalid.
131
132Enabling Client-side Validation
133Alright, here we are on Add a Gig page. Let me show you something. Right click on an empty area. And select Inspect Element. Then go to the Network tab. Now if we scroll down a little bit and click the Save button, look at the requests sent to the server. So on the top we have a request to the Create action, so it's a post to the Create action as you see here, which is followed by a number of other requests. And the reason for that is because we have not enabled client-side validation. So let me show you how to enable client-side validation. Back to Visual Studio. We go to Solution Explorer. Under App Start, open BundleConfig. So in case you're not familiar with the concept of bundles, the idea is we can get one or more Javascript or CSS files, put them in a bundle, and then I'd runtime aspe dot net will combine them and compress them before returning to the client, and this is for optimization. So in the default project template, we've got a few bundles here. The first one is jquery, and it includes any files with this pattern. Any files that is in the Script folder, starts with jquery dash and then there is a version number there. We also have another bundle called jqueryval, which is for validation. And here's the pattern for the files in this bundle. So if we go to Solution Explorer, under Scripts folder, we have two files that are from validation. One is jquery. validate, another is jquery. validate. unobtrusive. The size of these two files together is about 50 kilobytes. And I think that's the reason Microsoft team decided to put them in a separate bundle. So instead of returning them on every page, we can return them only on pages where we need them. So we're going to add this bundle to our Create view. But before doing so, let me show you one more thing. Let's go to Views. Shared, layout. If you scroll down, look, at the end of this page, we've got jquery bundle, we've got bootstrap bundle, but there is no jqueryval. So, that's the reason we need to manually add it to our Create view. We also have this line, RenderSection, which is used for adding additional scripts to a page. So in that section we're going to add jquery validation. Now let's open up Create View, Ctrl + Shift + N, create. So here, at the bottom of the page, I'm going to add the script section, so section, scripts, and here, similar to the layout, I'm going to add a bundle. So, let's take a look at the layout one more time. We need a line like this. So, going to copy this, back to the Create view, paste. And change the name of the bundle to jqueryval. The reason we need this script section here is to ensure that the jqueryval bundle comes after jquery definition. If we don't add section scripts, this is what's going to happen. Let me show you the layout one more time. Look at this renderBody statement here. So the content of our view is going to be placed here, and at this point we don't have jquery. Because jquery is referenced here. So that's the reason we need to add any additional scripts in the script section. At this point, both jquery and bootstrap are downloaded. All right. That was all we had to do for enabling client-side validation. Let's test it. Back to the browser. Now, I'm going to add a question mark in the address of this page to ensure a fresh download. Alright. Now, let's go to the network tab. I'm going to clear all the existing requests and now, let's scroll down and click save. Look, we got all the validation messages, but there is no request to the server in the network tab. And that's because of the client-side validation. Now, one thing you need to know about client-side validation is that they work with the standard data annotations implemented in dot net. So annotations like required data range, string length, and so on. In this case, we implemented two custom validations, one for date, one for time. And client-side validation, jquery validation, does not know about this. So we need to manually implement them. Now, that was originally part of my plan, to do it as part of this module, but I think the length of this module is getting a little bit too long, and there is still a lot of things I want to cover in this course. So personally, I think the fact that we don't have client-side validation for date and time is not really the end of the world, it's just to make the application a little bit nicer. What is critical is to have validation on the server, which we have already implemented. So I'm going to park that for now, and if time permits, I'm going to get back here later in the course. So, the last thing we should do here is to commit our code to the repository. Back to Visual Studio, close all files, Alt + W + L, Team Explorer, we've got six changes here, so I leave it to you as an exercise to review each file, look at the before and after, make sure the code is clean, and finally we give it a comment. Implement validation. Checking. Beautiful.
134
135Summary
136So, in this module, we implemented validation using data annotations. The benefit of data annotations is that we get both the server side and the client side validation. All we have to do is to decorate the properties of our view model using attributes. In this module, we used the required attribute but there are other annotations that we didn't cover, because we didn't need to use them in our form. Examples of these annotations include range, MinLength, MaxLength, Phone, EmailAddress, RegularExpression and so on. In the future models, depending on the futures we'll be implementing, we may explore more of these data annotations. When using data annotations, remember, to enable client-side validation, you need to add jqueryval bundle to your page. In the next module, we'll take a look at securing our form and preventing CSRF, or c-surf attacks. I hope you enjoyed this module and thank you for watching.
137
138Preventing Common Web Application Vulnerabilities
139Introduction
140Okay, in this section, I'm going to talk about a few common web application vulnerabilities that every web developer must be familiar with. I'm going to talk about SQL injection, cross-site scripting, and cross-site request forgery. Now let's get started.
141
142SQL Injection
143The first kind of vulnerability I'm going to talk about, is SQL injection. This vulnerability allows an attacker to execute malicious SQL statements in your application. For example they can get the list of all users, or delete records and so on. Depending on how the attack is done and how much vulnerability is there the impact can vary. So how does it work? Imagine in our application we have a code like this. We get the user with the given ID and this ID is to be supplied as an input. It could be a text box where the user enters a number or it can be a hidden field or a query string. Now the problem with this code is that the SQL statement is generated at runtime. And that is based on the input to the application. So the attacker can use this opportunity to modify the final SQL statement at runtime. So in this example they can supply an input like this. So here it doesn't matter if there is a userId with the value 1, 2, 3, 4 in the database or not. The important thing is the second part of this input: or 1 = 1. This statement is always true, so as a result our SQL statement will return all users from the database. The way to protect against SQL injection is to use parameterized queries instead of string concatenation. So in this case if we changed our SQL statement to something like this, then the attacker could not modify the final result. Whatever they pass as the input will be stored in userID parameter. Now in the context of our application, do we have this vulnerability or not? No. Because we are not generating SQL at runtime, instead we are using entity framework and we let entity framework generate the SQL statements. We simply add an object to a Dbset and entity framework will take care of the rest. But if instead we used the SQL query method of a dbset and generated SQL statements using string concatenation we could have SQL injection vulnerability. So that's something we should remember for the rest of our development.
144
145XSS
146The next common vulnerability is cross-site scripting, or XSS, which enables an attacker to execute a malicious script on the victim's computer. Then they can steal the user's cookies and hi-jack their session. Depending on the sophistication of the attack they can also get access to the user's geolocation, web cam, file system, and so on. So how does it happen? The attack starts by the attacker inserting malicious JavaScript into the pages of a trusted website. For example, in a forum they can reply or create a post, and include some JavaScript there. Later when the victim visits the pages of this trusted website, the malicious script is loaded along with the page content and executed on the user's browser. How can we prevent this? The primary way to disable cross-site scripting attacks is to escape content, which tells the browser to treat the content as a simple string and not interpret it in any other way. If the attacker puts a script on your page the victim will not be affected because the browser will not execute the script if it's properly escaped. In the context of our application, do we have this vulnerability or not? No. First of all ASP. NET MVC applications by default, have a protection mechanism that detects Javascript in the input fields of a form. So unless you explicitly disable this mechanism in web. config, that's going to stop the attacker from exploiting this vulnerability in the first place. Also Razor views by default automatically escape content. The only exception is if you're using Html. Raw method. So currently we are not using this method, but that's something we should keep in mind in the future.
147
148CSRF
149The final vulnerability I want to talk about in this module is cross-site request forgery or CSRF, which allows an attacker to perform actions on behalf of a user without their knowledge. How does it happen? Imagine PayPal is vulnerable to CSRF attacks, and here's the URL to transfer money from one account to another. So when the victim logs into their PayPal account and fills out the form to send money to someone a post request will be sent to this URL. Let's imagine that the body of the request contains two fields: targetAccount and amount. Now the attacker can create a page and somehow try to get the victim to visit that page. Perhaps promising to offer something for free, or get a prize. The possibilities are endless. On that page there is a button that is supposed to give the victim that ultimate reward. When the victim clicks that button a post request will be sent to the money transfer end point on PayPal, but with modified body. So the attacker can put their own account ID in the target amount field and set the amount to whatever they'd like to get from the victim. Now, at this point if the victim happens to have an active session on PayPal, when they click this button a request will be posted to PayPal which will cause a money transfer from their account to attackers account. And interestingly everything looks legitimate here. If PayPal tries to trace the issue all the records show that the victim did transfer the money just as if they filled out the form and clicked the transfer button. That's why this attack is called Cross-side request forgery. Because the attacker forges the request on another site. So that's how it works. By the way, this attack is not always about transferring money. An attacker can perform any actions on behalf of a user. In the context of gigHUB an attacker can use the technique to create fake gigs on behalf of an artist without their knowledge. They can send people to a venue where there is no gig. Now how can we prevent this? Preventing CSRF attacks in ASP. NET MVC is pretty easy. The framework itself has taken care of all the complexity. All we have to do is call Html. AntiForgeryToken method in our forms, and then decorate the target action with ValidateAntiForgeryToken attribute.
150
151Preventing CSRF Attacks
152Alright now let's disable all CSRF attacks in gigHUB. So first we go to our create view. Control shift and create. Okay here is the form. I'm going to put an anti-forgery token inside this form. So Html. AntiforgeryToken. That's it. Save. Next we need to go to the controller. Control shift and GigsController. And decorate our create action with That's all we had to do. Let's run the application. And go to Add a gig. Alright now I'm going to right click here. Inspect element. Take a look here. Here's our form and here we have a hidden field, that includes a random token. So when we call Html. AntiForgeryToken ASP. NET MVC is going to put a hidden field here. But that's the first part. It's also going to create a cookie that includes the encrypted version of this token. So let's go to resources, expand cookies, local host look, we got RequestVerificationToken. And the value you see here is the encrypted version of our token. When we post this form to the server, because we decorated our action with, ASP. NET MVC is going to compare these two values. It's going to get the hidden field from the form, encrypt it and compare it with the value in the cookie. If they match that's a legitimate request. Otherwise it's a CSRF attack. Why? Because the attacker may be able to steal the user's cookie, but they won't have access to the hidden field. The only way to get the hidden field is to get the user visit to trust the page. Not the malicious page. Which is completely opposite of the idea of a CSRF attack. So now let me simulate this scenario. I'm going to fill out the form, but remove the anti-forgery token in the hidden field. So... some values here... now we go to elements. Here's our token. I'm going to delete this. And finally click save. The required anti-forgery form field is not present. So we cannot create a gig without having a valid anti-forgery token. And now it's time to review our code and commit it to the repository. So back to Visual Studio. Team Explorer. We've got two changes: One in the controller, one in the view. Give it a comment. Implement anti-forgery token. Check it.
153
154Summary
155Alright now let's quickly review the key points in this module. In this module you learned about three most common security attacks in web applications. Again there are many other attacks out there, and new ones come out all the time, but what we explored in this module are the bare minimum that every web developer should know. The first one is SQL Injection, which allows an attacker to execute malicious SQL statements on your application. And that's possible if you're building queries dynamically at runtime using user's input. So the workaround is to use parameterized queries, and not using string concatenation. In gigHUB we don't have such a vulnerability, because we don't generate queries at runtime. Instead we use entity framework and work directly with a Dbset. Entity framework will take care of the query generation. You also learned about cross-site scripting, which enables an attacker to execute a malicious script on the victim's computer. And as I explained the way to do this is by inserting Javascript into data entry forms. Again we don't have such vulnerability in gigHUB because ASP. NET MVC detects Javascript in the request body and immediately stops the request. Plus, Razor Views escape content so they wont be executed by the browser. And finally you learned about Cross-site request forgery, or CSRF, which allows an attacker to perform actions on behalf of a user without their knowledge. The way they do this is by finding requests in a trusted web application and then trying to forge the request on a different site. They create a malicious page getting you to click a button or a link, and then they will post a request to the trusted site. At this point if you have an active session on the trusted site that request will be executed on your behalf with your identity. So we had this vulnerability in gigHUB and we disabled it by using an anti-forgery token. In our create view we use Html. AntiForgeryToken method, and we decorated our action with And that brings us to the end of this module. In the next module we're going to work on our front end skills, and get really creative. I'm going to show you how to give a nice look and feel to our application. So I will see you in the next module.
156
157Moving Towards a Beautiful Design
158Introduction
159As I said before, sometimes we have a dedicated designer in the team purely responsible for the look and feel of your applications. The other times, you don't have someone like that and building a beautiful user interface is your job. So in this section, I'm going to talk about the artistic and creative aspect of web development. I'm going to talk about colors and their meanings, fonts and typography. And then I will show you quite a few simple techniques that you can use to improve the look and feel of your applications. Now, let's get started.
160
161Choosing a Color
162So our Gig Hub application looks pretty boring. I hate this black navigation right here. It has no character. It's just so dull. The first thing we should do to improve the user interface here is choose a primary color for our website. And that's what we're going to reflect in the navigation bar. Now I got a question for you. What color do you think should Gig Hub be and why? The why part is very important. Don't just pick blue or red because you like these colors. I want you to think why Gig Hub should be that color. Just pause the video and think for a second. Then in the rest of the video, I'll briefly overview the meaning of different colors and based on that, I will choose a color for Gig Hub. Okay, before we get into the meaning of each color, you need to know that color in design is very subjective. What evokes one reaction in one person may evoke a different reaction in someone else. And this can be due to personal preferences or cultural background. So we have three categories of colors. Warm colors, cool colors, and neutrals. Let's start with warm colors. In this category, we have red, orange, and yellow. Red is often associated with fire, power, energy, passion, and love. Orange is very vibrant and energetic. It's fun and exciting. Yellow represents happiness and sunshine. In the category of cool colors, we've got green, blue, and purple. Green often represents calming, healing, natural protection. Blue is often associated with trust, loyalty, friendliness, and calmness. Pink represents romantic, feminine, love, and beauty. And finally in the category of neutrals, we got black, white and gray. Black is associated with powerful, sophistication, and formality. It can also be associated with evil, death, and mystery. So that's why I said the color in design is very subjective. White often means clean, perfect, and pure. Have you noticed that Apple uses white in their branding a lot? Like a white background or a white package, or white cables, it's associated with clean and perfect. And finally we got gray, which often means conservative and formal. Now we want to choose a color. Out of all these colors, personally I'm leaning more on red and orange for Gig Hub. Why? Because Gig Hub is about live music. And I want to evoke a sense of excitement, fun, and passion when visitors use Gig Hub. So somewhere between red and orange.
163
164Overriding Bootstrap Styles
165Okay so we picked a primary color for Gig Hub. Now I'm going to change the color of navigation bar. So right click on the navigation bar. And go to Inspect Element. In case you have not worked with Chrome developer tools before, basically here on the left side with the Elements tab selected, we can see our HTML elements. And on the right side we can see this does apply to those elements. So let me expand this a little bit. Alright, that's better. So currently we have selected this element on the left side. And on the right side, you can see the styles applied to this element. I'm looking for a style that sets the background of the nav bar to black. So currently it's not this element. Let's select it's parent. So scroll up a little bit. Here's the parent. So this is the div with a class nav bar right below the body element. And on the right side, look we've got background color set to black. Same for the border color. Now I'm going to change both these colors by clicking here. The color I picked for Gig Hub is FF4342. Okay now look on the top. The navigation bar is red. Now the links are not quite visible because they're gray and they don't have contrast with the red background. Before going any further, I want to add these changes to our stylesheet. Because the changes we have made here are purely in the memory. So I'm going to select this piece of code here. So the entire nav bar dash inverse class. Copy, back to Visual Studio. Let's go to Content. And open site. css. So these are just styles that come in the default project template. I'm going to go to the end of this file. Add a comment here. Bootstrap Overrides. Because this nav bar class is part of Bootstrap, I'm going to override it here. I'm not going to change the Bootstrap file that you see here in the Content folder. If I modify this Bootstrap file here, next time Bootstrap releases a new version and I get that all my changes are lost. So I'm going to override them inside. css. At the moment, the scope of our work is small. So there are only a few styles that we need to change. In the future, if Thesis does grow, we can extract them from site. css and put them in a separate stylesheet. Like BootstrapOverrides. css. For now that's enough. Paste. Back to the browser. Now let's make the links white. So I right click on a link, Inspect Element. That element is selected on the left side here. And on the right side, here's the style that sets the color of links to gray. So I'm going to copy this. Back to Visual Studio. Paste it here. Change the color to white. Save, back to Chrome. I'm going to refresh the page by control and R. Okay so my changes are working fine. But look at application name. It's still gray. Because it has a different class. So right click, Inspect Element. Here is the element. And on the right side, let's scroll down and look for gray. There we are. So nav bar dash brand class applies a gray color to the application name. So select, copy, back here. Paste, change the color to white.
166
167Choosing a Font
168So we changed the color of the nav bar. Next I want to choose a nice font for Gig Hub. We've got a few options here. We can use Google Fonts, which is free. But it has limited number of fonts. Some fonts, especially nicer ones are only available commercially. So in that case, you may want to try fonts. com or fontsquirrel. com or typekit. com, which is run by Adobe. I've tried all these services. I've been pretty happy with all of them. So generally you pay somewhere around 10 dollars a month and you get access to lots of awesome fonts. And I think it's really worth paying the price. Now in this video, let me quickly walk you through Google Fonts. So head over to google. com/fonts. Now here we can see some of the most commonly used fonts sorted by popularity. One font that you see in a lot of websites is Open Sans, it's pretty nice, clean, and modern. Let's scroll down a little bit. Here we got Lato which is pretty similar to Open Sans, but if you look at the details, you see that it's a little bit more chunky. Also it has less pixelation compared to Open Sans. I know if you compare it to Roboto, you'll see Roboto is more narrow on the horizontal scale. So these little details give each font a different character. Usually white and chunky fonts are more youthful, more modern. Whereas smaller, more narrow fonts are more professional and serious. So for Gig Hub, I'm going to try Open Sans and Lato. So we click Add to Collection. Let's scroll down. Same with Lato, Add to Collection. And let's scroll down a little bit more. Okay there's one more font that I'd like to try here. And that is Montserrat. I don't know how to pronounce that. So that is also a chunky and youthful font. So again, Add To Collection. Now here in the bottom, you see in our collection, we've got three font families. We can preview them. So here we can see their samples. And let's go to the use tab. Now here for each font we need to select the sizes we would like to download. By default Normal with 400 weight is selected. I would suggest do not select Light because often it gets pixelated on web. So usually Normal is good. We can also select Bold. In case we want to display something in bold. Let's scroll down. Now under Lato, look, thin, and light are pretty pixelated. Especially thin. So let's just take Bold, scroll down, and one more. Now let's scroll down a bit more. So in the third section here, you'll see how we should use these fonts in our application. So we can simply add a link to our layout. And then in our css, we can reference these fonts by their name.
169
170Overriding Bootstrap Fonts
171Alright now I'm going to select this line, copy, back to Visual Studio and go to Layout View. Control shift N, layout. And then I'm going to paste it just before the line that renders our css bundle. So paste. So this link references fonts. googleapi. com. And note that in the core string we've got font families. So we've got Open Sans. With two font sizes, 400 and 700. Then we've got a separator here. And then we've got the next font family, Lato. And similarly we got a third one. Now one thing you need to cautious about is all these fonts will increase the size of your HTTP response. So if there are fonts that you're not going use, we should remove them here for optimization. So let's save this file. Run the application. Okay so this is our current homepage with the default font. Now I'm going to open one more tab. So first I'm going to copy this address. Paste it into a new tab. So I'm going to make my modifications on this tab so we can compare them side by side. So let's right click anywhere on any character. Select Inspect Element. Let's go to the Computer tab here. So here we can see the result of all styles applied to that element. If you will scroll down, you see font family is Helvetica New. Which is actually a Mac font. But here I'm running Windows, so the first font that will be available for me would be Ariel. So I'm going to change these to Open Sans. We need to find out where in our stylesheet that font is set. So we click this magnifier icon here. That brings us to the styles tab. And look we've got a style definition for the body element, in boostrap. css on line 313. And there, font family is set to Helvetica New. So I'm going to click here. Select this Helvetica New. And change that to Open Sans. Enter. Alright now at this point, you might not notice any difference, but please bare with me. Now one more thing we need to change here, is these headings. These headings are still using the old font. So right click, Inspect Element, you scroll down. Look in bootstrap, line 465, we've got styles for headings, so I'm going to change font family here to Open Sans. Close, alright now what I want you to pay attention to is these headings here. These headings are using Open Sans. Now I'm going to switch tab so you can see the headings with the default font, which is Ariel. Can you see the difference? Ariel looks a little bit pixelated. Also some edges are thicker. The font is not balanced. Now look at Open Sans. It has more space, it's breathing more, it's more modern, it's more youthful. Now I'm going to open new tab and repeat these steps one more time to try the Lato font. You don't have to do it, just watch and see the difference and then we'll wrap up this video. Alright let's start with the default font. So this is what we had before. Now let's take a look at Open Sans. So obviously it's cleaner and whiter. And now let's take a look at Lato. Lato has more excitement to it. It's more fun and I think it matches the characteristic of Gig Hub. We want a fun, exciting, energetic, and passionate website. So I'm going to go with Lato. So back to Visual Studio. Open up Bootstrap. css. So Control Shift N. Bootstrap, here I'm going to find the styles that set Helvetica font. So Control F. Helvetica, that's it. So one is in the body. Press F3. One more time. Here is another. So it's all the headings H1 to H6, as well as classes. h1 to. h6. So I'm going to select everything here. Copy and open up site. css. As I explained, we should not change Bootstrap. css, instead we should override it here. So paste. We don't need to modify font weight or line height. Delete. And now I'm going to add Lato here. The reason I didn't delete the existing fonts is to use them as a fallback mechanism. So in case Google fonts is not working, the client can download Helvetica New on Mac or Ariel on Windows. We also need to add the body element here. So I'm going to put it on the top. Save and one last thing, we need to remove unnecessary fonts in the layout. So let's go to the layout. So scroll to the right. Look, we don't need Open Sans anymore. Delete. Same for the other font. Save.
172
173Improving the Look and Feel of Forms
174Okay this is what we currently have. It's not bad, but it can be better. One thing I don't like about this form, is that the font is too small. So are the text boxes. I want a modern and youthful design. So I want to make this form a little bit chunky. I want to add a bit of padding. So the font can breathe more. Currently everything is too close to each other. So right click on Venue. Inspect Element. Here we select form group. Now look on the top. You see a blue and an orange area. The blue areas are div, with the class form group. The orange area is the margin below the form group. First I want to increase this margin so that the elements are a little bit more separated. So with the form groups selected on the right side, I'm going to increase margin bottom. I can use my up arrow. And increase it to 20. Okay I think now they are a little bit more separated. So I'm going to grab this part. Copy, back to Visual Studio. Go to site. css. And at the bottom of the file, where we are overriding bootstrap, paste it here. Back to Chrome. Next modification, I think the size of the labels is too small and that's why it has a more serious or professional look. So let's see where that style is defined. I'm going to right click on Venue, inspect element. Then we go to computer tab. Scroll down. Okay look, font size is 14 pixels. So we click the magnifier icon. So in bootstrap, the body element has font size set to 14 pixels. So let's see what it looks like if we make it 17 pixels. Okay now look on the top. Look at the nav bar. Look at the labels. I think it's better now. So back to Visual Studio. Now I would like to put body at the beginning of these overrides. So kind of starting from more generic ones and then leading to more specific ones. So body, font size 17 pixels. Now we have a purple underline here and the reason for that is because we already have another body element on the top of this file. But that's okay for now, I'm going to fix it in a second. Let's just finish up this task and then we'll get there. So back to Chrome. Let's type something in an input field. Okay here the font is too small. And it doesn't match the rest of the site. So let's see where that is defined. Again right click, inspect element. You see in the form control class, in bootstrap, font size is set to 14 pixels. So I'm going to make this 17 pixels as well. Now look at the input field, that's better. So back to Visual Studio. We go to the bottom of the file. And add form control here. Next. One thing I didn't like about our text boxes is that they are too small. With a modern, chunky, youthful look we want a bit more padding. So with the form control selected, in the styles editor, here is a padding attribute. I'm going to change this to 20 pixels and 15 pixels. So the first number determines the padding on the top and bottom. And the second number determines the padding on the left and right. I think that's okay for now. So we copy this padding. Back to Visual Studio. Okay let's continue. Another thing we can improve here, is the roundness of the text boxes. I personally prefer more curves on the edges. So we can change border radius attribute. Again with the form control selected, here we've got border radius. I'm going to increase it to nine pixels. Now look at the top. Input fields have a bit more curve. So... We add a border radius, now we have a blue underline which is coming from resharper. So if we put the cursor here and press alt and enter, resharper suggests to add vendor specific properties. And that's for compatibility with older browsers. Enter. So then add Microsoft border radius. Okay next. Let's take a look at our button. Our button compared to input fields looks a little bit small. So right click, inspect element. So here are the styles for the median glass in bootstrap. The first thing I want to change here is the font size. So I'm going to increase it to 17 pixels. That's better. I want to make it a little bit wider. So with the padding, we can increase the horizontal padding, let's say 20 pixels, that's better. Actually I don't mind to add a bit more padding on the top and bottom. So seven and 20 pixels is good. And finally, I would like to make the edges a bit more curvy. So that's border radius. I'm going to increase it to nine pixels. Alright now look on the top. That looks better. So back to Visual Studio. (working) And add vendor specific properties. That's it and we're done.
175
176Overriding the Focus Effect
177So this is where we are now. One more thing I would like to change here is this hover effect here. We've got a bit of shadow around the border. But these days, flat design is more in trend. Now this is purely personal preference, you don't have to do this. But with a flat design we should get rid of any shadows or gradients. Now what I'm going to teach with this video is not about flat design. It's about how to override the styles for the hover effect. Now right click on this input field while it's in focus. Go to inspect element. Now on the right side, by default you can not see the styles applied to the focus state. You only have form control here. In order to see the styles for the focus state, we need to click this icon. That's called toggle element state. And here you can take any of the states like active, focus, hover and visited. I'm going to take focus. And now take a look, we've got form control, call, and focus. Let me scroll down a little bit. Alright so here we got a couple of attributes, Webkit, box shadow, and box shadow. I'm going to untick both of them. Now take a look at the text box. The shadow is gone. Also I would like to change the color of the border. Currently it's a little bit muted. I'm looking for something a little bit more vibrant. So we click this color here. Now what you see here is I think the latest version of Chrome, I just saw this little color picker prior to this recording. It used to look different before. So if yours looks different, don't worry about it. I'm just going to pick this color. Which is 2196F3. Put the cursor here. Press Enter. Let me close this. So this is how it works now. I think it's cleaner without the shadows. So back to Visual Studio. Here is our form control class. I'm going to override the styles for the focus state right after it. So one is border color, 2196F3. Now with box shadow, because it's defined in Bootstrap, we need to set it to none here in order to override it. And one for webkit. This one is for older versions of Chrome. That gives us the webkit engine. Save, enter the browser, refresh. Okay that's better.
178
179Adding a Drop-down List to Navbar
180Okay now let me show you how to add a dropdown list to the navigation bar. That's something that we're going to use very soon. Remember our initial user experience? We need to have a dropdown list here on the right side with the name of the current logged in user. And under that we're going to have links like Artists I'm Following, Gigs I'm Going, and Sign Out. So how can we add a dropdown list here? First we need to go to getbootstrap. com. Then under Components, scroll down. You see NavBar here on the right side, click. Scroll down. Okay here's an example. Now this nav bar looks a little bit ugly because it's in two lines. And that's because I've increased the font size so we can see things more clearly. But irrespective of that, look at this dropdown here. That's what I'm looking for. So how does this work? This bar we have here includes three parts. The left part, which is an unordered list or UL with three LI's. The middle part, which is a form. And the right part, which is another unordered list with two LI's. So if you look at the mark below there is some ceremony around the main container. Don't worry about that, so scroll down a little bit. Here you see a UL with three li's. That's for the navigation bar on the left. Next to this UL you see a form, that's for the middle part. Now let's scroll down a little bit more. And here's the UL for the right part. Note that it has two children, two list items. The first one is just a link. The second one is a dropdown. So all I'm going to do is copy these LI back to Visual Studio. Control shift N. Go to layout. Okay here's our navigation bar. Let's scroll down. So here's the actual nav bar. A UL with two LI's. But these are the links on the left side, Home and Add A Gig. We also have a partial view here, log in partial and that's where we have another nav bar for the links on the right side. So that's where we want to add the dropdown list. Let's open up login partial. Look, it got a UL with two LI's. The first one is hello username and the second one is sign out or log off. So I'm just going to paste what we copied from Bootstrap website here. If we're making any modifications, I want to make sure this is working in terms of structure. Save, back to the browser. Refresh. Alright we got a dropdown here. But the icon is gray and this white it's not standing out. We're going to fix that shortly. Let's click it, there you go. That's exactly what I was looking for. So for now, don't worry about the styles. We're just going to focus on the structure. In the next step we'll improve the look and feel. So now I'm going to change the label of the nav bar from dropdown to the email of the currently logged in user. And then move the log off link down here. So back to Visual Studio. Here's our dropdown list. First we have an anchor. And that's where we have a label. There you go, dropdown. I'm going to replace this with the email of the currently logged in user. How do we do that? Let's scroll to the left. I'm going to borrow this code, hello username. Copy here. Paste. Now this is C sharp code so we need to prefix it with at sign. That's it. And here is the log off link. So I'm going to cut this. And put it at the bottom of the dropdown. Finally I'm going to remove this hello username. Save, back to the browser. Refresh, that's better. Now I'm going to rename action and another action. To gigs I'm going and artists I'm following. So back here. Here's another one. Artists I'm following. Now the implementation is going to come later, this is just a label. And we don't need the third link here. Delete, save, back to the browser. Refresh. That's exactly what I wanted.
181
182Cleaning up the Navbar
183Alright now I want to do a little bit of clean up in the navigation bar. First let's click this dropdown menu. This black background color does not go with our theme. So let's change this. Right click, inspect element. Look here's the background color set to black. I'm going to click this color icon. Now this is the new color picker dialogue. If you're not seeing this, you're probably using an older version of Chrome, it doesn't really matter. What matters is the final color code that I'm going to pick. So with this color picker selected, I'm going to go here and pick the color of the navigation bar. Now currently, this is selected so it should have a different color, so I'm going to make it a little bit darker. So in this color spectrum, I'm going to go somewhere here. Now look, it's a little bit too dark. So I can reduce the opacity and make it blend with the background a little bit more. So in the second slider here, I can go to the left. Alright I'm happy with this. So you can see the numeric values in the bottom. RGBA, red, green, blue and A is alpha which is the opacity. It's a floating point number between zero and one. So press Enter. That's it. Now I'm going to copy this style. Back to Visual Studio. Go to site. css. So I'm going to put this next to other styles for the navigation bar. So scroll up. Alright look, here we have the styles for the navigation bar. Paste, that's it. We don't need the color attribute here because we haven't changed it, delete. Now note the RGBA value here. So I guess you couldn't use the color picker. The number's we're looking for is 205, 40, 39, and 0. 55. Back to the Chrome. Another thing I want to change here is the shadow around the dropdown menu. So in the elements window, currently our anchor is selected. Let's select the UL right below it. That's the UL with the class dropdown dash menu. Now in the styles window, let's scroll down and look for box shadow. There we go. So on tick, and there's one for webkit. Now look at the top. The shadow is gone. So let's see what class is this. Scroll up. That's dropdown dash menu. So back to Visual Studio. Pretty simple. Back to the Chrome. Now I'm going to click on a white space. Look at the gray icon under right of the navigation menu. I'm going to change that to white. So right click, inspect element. So in the styles tab let's look for a style that sets the color of this band to gray. Scroll up. There you go. So FFF for white. There's the next one. Now look at the top. The color is fixed. Again, copy. Back to Visual Studio, paste. We're almost done, just a couple more changes. Save, back to Chrome. I'm going to change this application name to GigHub. Remove the link to home. Because by convention, the logo or name of the site on the left should take us to the homepage. So back to Visual Studio. Let's go to the layout. Control shift N, layout. So here is the application name. And delete home. Save, back to Chrome. Refresh. That's cleaner, the only problem is the application name and Add a Gig link, it looks similar. We want GigHub to stand out because it's supposed to be the logo. So at a minimum, I just want to make it bold. So right click on GigHub, inspect element. In the stylesheet window, let's scroll down. So navbar dash brand is the css class the defines their styles here. I'm going to set font weight. Remember when we selected the Lato font on Google Fonts, we selected two sizes. 400, which was normal and 700, which is bold. So 700. Now look, it's kind of standing out. So let's add this to our stylesheet. Back to site. css. That's it.
184
185Before and After
186So let's do a quick before and after comparison. This is where we started. And this is where we are now. So this new design has more character. It's more energetic, more fun, and more youthful. Of course we could take it to the next level, but we have to wrap up this module. In the future modules, I'm going to show you more techniques to take this design to the next level. And now it's time to read our code and come into the repository. So back to Visual Studio, Team Explorer. We've got three changes here. I want you to spend a minute or two reviewing the changes, look at the modifications we did during this module. Now let's give it a comment. Improve the look and feel, check in.
187
188Summary
189So in this module we improved the look and feel of our site in a step by step fashion. Similar to development, this is an iterative process. So there is never an end to it. You could spend hours and hours improving this design. But the focus of this module was not to produce an outstanding design that everyone would love, instead it was to teach you some front end skills. These are the skills that help you stand out from other developers who just know how to write code and nothing else. So we looked at the meaning of different colors. In general warm colors like red, orange, and yellow bring more energy and excitement to a design. Cool colors like blue, green, and purple are more relaxing. We also looked at using custom fonts. Similar to colors, each font has a different personality. Also in terms of sizing, bigger fonts are often more youthful while smaller fonts are more serious. We also learned how to override bootstrap styles. We used Chrome Developer Tools to get immediate feedback as we were modifying styles. And finally we added these modifications in our site. css. And that brings us to an end of this module. In the next module I want to talk about usability, which is extremely important, so I will see you in the next module.
190
191Usability Best Practices
192Introduction
193Building software is not just about writing code. Your applications should be easy to use and intuitive. So in this section I'm going to walk you through some key principles of usability that I believe every full stack developer must know. Just to let you know usability really requires its own course. So what I'm going to show you in this section is not comprehensive by any means. It's just an eye-opener. Now let's see these principles in action.
194
195Labels
196Let's start with labels. This is how our form currently looks like. So the labels are short and clear. Now what if we change this form to something like this? At first you might think the labels are more descriptive so it's better, but actually it's quite the opposite. This form is too noisy. Users don't have too much patience online or even offline. We're constantly bombarded with information from the moment we wake up to when we go to bed. So when we listen to noise and unnecessary words in your forms, or in your pages in general, we can increase usability and user engagement. So keep the labels to one or two words and be concise. Don't use ambiguous and mysterious words. Now in terms of alignment, we've got three choices. Top, right, and left. Let's study each of these in more detail. Left-aligned takes the most brainpower and is the slowest. Because often we associate things that are close to each other as related. When there is a gap between a label and an input field, your brain needs to think a bit harder to relate those things. Now let's see how the user's eyes move when they try to fill out a form like this. So you see there's a lot of eye movement. Down, right, down, right, down right. And that's another reason that left aligned labels slow down users. Now look at an example of right aligned labels. Labels and fields are pretty close. Ideally like a couple. There's no gap. Now look at the eye movements. There is less movement here. We still have the right and down pattern, but it's not as bad as left-aligned labels. And finally look at this image. Here again labels and fields are pretty close. Now look at the eye movement. The user's eyes only need to look down. They don't go to the right and down and right and down, but one downside of top aligned labels, is that they require more vertical space. So if vertical space is an issue, you would better use right-aligned labels. Otherwise go for top aligned. So with forms it's best to stick to top or right aligned labels.
197
198Input Fields
199Now let's talk about fields. First, and most important best practice, reduce the number of fields in a form. Let's be honest. No one likes long, complicated forms. Less is more. Capture only what is essential. Once you get rid of unnecessary fields, see if there are any optional fields that you can remove as well. It's best to capture only what is really required. After that if you still have optional fields, visually separate them from mandatory fields. So the user doesn't have to waste their time filling out every field when it's not required. With all these if you still have quite a few fields in your form, group them in a way that logically makes sense. If that's not sufficient, break the entire form into wizard. Show an indicator as the user is progressing through the wizard. Now if some of the input fields accept data in a specific format, you need to clearly highlight that to the user. Currently we have a format for our date and time fields, but nowhere that is specified. So as a minimum I'm going to add a watermark here. And finally set the focus on the first field in the form. You save the user from one extra click. That's another issue we have in our form which I'm going to fix next.
200
201Fixing the Usability Issues with Input Fields
202Alright, so here's our form. The good thing here is that it's pretty simple. It has only four fields and it's capturing what is really required, but it's not telling the user that all these fields are mandatory. Now when it comes to separating mandatory and optional fields, one practice is to put an asterisk or a label like "required" next to those required fields, but in this case because all fields are required, adding an asterisk or a label is going to add visual noise. Instead I'm going to add a label on top of the form saying all fields are required. So back to Visual Studio. We go to the create view. Alright here's our form. Now, right below I'm going to add a label. Now to take this to the next level, I can make the required word here bold. So it stands out. Now let me show you a technique. I'm going to select it with control W. This is a real sharper shortcut. Now control alt and J. It brings up "surround with" menu. So we can surround this with a tag or with a link. I can press 1 because that's the shortcut for tag here. And now I can put strong. So when you want to surround your code with something control alt J. It's much easier than creating a block and then cutting your code and pasting it inside. Alright now let's preview our changes. Save. Back to the browser. Refresh. Alright, it's there but it's kind of being mixed with the heading and the label for the first field. So I want to make it visually stand out. Bootstrap has a class for that called Alert. Let me show you how to use that. So, back here. In the P tag I'm going to add class alert. That's the primary class for all alerts. And then depending on the color you want to display, there are secondary classes. For example we've got alert info, which displays a blue alert. We've got alert danger, which displays a red alert. And so on. You can look at Bootstrap documentation for details. Save. Back to the browser. Refresh. Okay, that's better. Now I want to put the focus on the first field. That's pretty easy. So back here. So here's our venue text box. I'm going to use auto focus attribute which is part of HTML5 to set focus on this field. So here in the anonymous object. Save. Back to the browser. Refresh. There you go. And finally I'm going to add a watermark on the date and time fields to specify the format. Again that's pretty easy. So back here. Here's our date field. So in the anonymous object I'm going to use place holder attributes. Again this is part of HTML5. So here we can add some text. Just like that. And now I'm going to copy this and apply it on the time field as well. But this time I'm going to specify a 24 hour time format. Save. Back to the browser. Refresh. That's better.
203
204Actions
205Now let's talk about actions. Each form should have a primary action that should be visually distinguished from other actions. By primary action I mean links or buttons that perform to final functionality. Like save or submit. Secondary actions are like back or cancel. In general it's best to avoid secondary actions. If you really have to use them, be sure to visually separate them from the primary actions. So here's an example. Imagine we add a cancel button to our form like this. Currently both these buttons are using the same color, which is giving them the same weight. They appear to be equal which is not right. Instead we could separate them by using a different background color for cancel. Like this. Or we could turn it to a link. Either way the primary action is clearly standing out. And finally in terms of alignment, align primary actions with input fields. This is to reduce eye movement and provide a clear path to completion. Here's an example. Note that the primary action is aligned with the inputs and there is no distraction in the eye movements. As the user presses tab or scrolls down, they expect some element at the same horizontal position below. But look at this example. Here after filling out the last field, users eyes should move to the bottom right. And this is actually scientifically studied that in left to right languages like English, elements on the top left of the screen get the most attention while elements on the bottom right get the least attention. So currently our form adheres to all these best practices. So there is nothing we need to do here.
206
207Validation Messages
208And finally let's talk about validation. When a user enters bad data, provide clear and concise validation messages. For me personally it happened quite a few times when I was filling out a form as a user, and something went wrong, but the validation message was not helping. I had to guess to provide different values to get things done. So be clear and concise with your validation messages. Second best practice is to use red to indicate errors and green to indicate successful messages. A little while ago I was trying to book an appointment with my doctor online, and I noticed her confirmation message was displayed as red. So without reading the details, my immediate reaction was the booking failed. Perhaps he was fully booked. So I had to read the message to figure out what was happening. Your goal should be to reduce user's stress and guesswork as they are using your application. Now in case of Gig Hub you have a small problem. Our validation messages are pure black and they are not standing out. So I'm going to fix that shortly. And finally to reduce the user's chance for errors, provide smart defaults. If you can detect their location using their IP address or HTML5 location API, pre-fill the location textbox for them. If you can calculate the value for some fields based on the value entered in other fields, go ahead and do that. This will make the user's experience in your application smoother, and it will also reduce the chance for errors and seeing a validation message.
209
210Fixing the Usability Issues with Validation Messages
211Alright, let me show you how to fix the problem with validation messages. So I'm just going to submit the form without entering any values. Okay, look at the validation messages. They're black. We want to change them to red. So just like what you learned in the section about user interface. Right click. Inspect element. Alright, look here's the span where we have the validation message. Now look at it's parent. It's another span with a class filled validation error. So all we need to do is to define this class in our style shade, and set the color of text to red, but before doing so, let's quickly try it in Chrome to get immediate feedback. So in our styles window I'm going to click this plus icon. New style rule. So Chrome automatically gets that I'm going to create a set of styles for a span with a class "fill validation error". Now we just accept this by pressing enter. And click here. Color red. I'm also going to make the font bold. So font weight bold. Now let's take a look. That's exactly what I was looking for. So I'm just going to copy this class. Back to Visual Studio. We go to site. css Now this class is not part of Bootstrap. This is part of S down at NBC. So I'm going to define it on top of this file. So look we got body, body content, dl-horizontal, and then we get to inputs and select. So I would like to put it right here, because I like to have related styles in one place. Paste. Save. And now it's time to review our code and commit it to the repository. So team explorer. We've got a couple of changes here. We give it a comment. Improve the usability of the form. Check it. Beautiful.
212
213Summary
214So in this module we explored some of the core principles of usability and creating user friendly forms. In the real world there are people who specialize in usability, but not every team and every project involves one of these people. So you as a software engineer should develop a common sense to usability to design a clean and a smooth user experience for your applications. Plus understanding and applying usability principles, helps you stand out from other developers who know nothing but writing code. Now let's quickly recap some of the key points in this module. When designing forms keep your labels short and concise, and prefer to use top aligned levels if vertical space is not an issue. Otherwise use right aligned labels. With fields try to avoid optional fields if you can. And if not remember to clearly specify the mandatory fields. Make sure your forms have a primary action that is distinguished from secondary actions. Remove secondary actions if possible. And in regards to validation, keep your validation messages clear and use red. I hope the principles you learned in this module help you become a better developer. In the next module I'm going to show you how to extend the user class in ASP. NET identity. Thank you for watching and I'll see you in the next module.
215
216Extending ASP.NET Identity Users
217Introduction
218Every ASP. NET application we create, using the default template has built in authentication and authorization, implemented using ASP. NET Identity. We get a basic login and sign up form. Now, this sign up form is pretty basic and in most real world applications, we need to capture one or more attributes during the sign up process. So in this section, we are going to extend ASP. NET Identity and add a new field to our sign up form. This field is going to be the name of the artist, so let's get started.
219
220Building a Basic View
221All right. Here's our current homepage. We want to replace this content with the list of upcoming gigs. So, back to Visual Studio. We're going to go to Home Controller, control + shift + "n". In the index action, we need to retrieve all upcoming gigs from the database, so we need a DbContext here. And I'm going to initialize this in the constructor, so ctor, "Tab", that's it. So, back to the index action. So context. Gigs and at this point we need to eager load the gigs and their artists because we want to display the name of our artists on the homepage. So we use the Include method. The Include method you see here takes a string parameter, which we use to specify the name of the navigation property, in this case, artist. This method is very dangerous and in my opinion, it is a design smell in Entity Framework, because if you rename this navigation property as part of your refactorings, your eager loading code is going to break and you're going to get a non-reference exception. And the problem with that is you won't know until you run the application, and chances are, you may even deploy the application to the production and you still don't know. So, we're going to use a different Include method that takes a lambda expression. To use that, you need to import System. Data. Entity, so, that's it. Now, back here. A lambda expression, g goes to g. Artist. If I rename this Artist property, this lambda expression will automatically get updated. Next, you want to filter and get only gigs in the future. So g. DateTime > DateTime. Now. Now this code is getting a little bit too long and generally speaking, scrolling to the right is a bad practice when you're coding. You should never scroll to the right, so we're going to break up this code into multiple lines to make it more readable. Like this. Now, we need to put the model inside the view. That's it. And finally, we need to go to the View, so control + shift + "n", index, the first one is InViews\home, so let's go here. I'm going to delete all the contents here. All we're going to have is ViewBag. Title = "Home Page". Now, in the top, I'm going to specify the model which is going to be an IEnumerable of Gig. That's a simple interface that is implemented by all lists and it allows me to iterate over an object. So, now you're going to iterate over this model and display all gigs using a Ulnli. So, ul foreach (var gig in Model). I'm going to display the DateTime, use hyphen as a separator for now. Don't worry about user interface which is focusing on displaying all upcoming gigs. Now, gig. Artist. Name. Look, we don't have a property called Name. We have only Username, so that's something we're going to fix in this module, but for now let's just render Username and make sure what we have done so far is working and then, in the next video, I'm going to add the Name property to our list. Control + shift + "b" to build. Back to the browser. Control + R. All right, it's working, so for each gig, we get the date, time, and the artist username.
222
223Extending ApplicationUser Class
224All right, now let's add the Name property to our users, so back to Visual Studio. I'm going to clean up my workspace, alt + W + L. Let's go to Solution Explorer. So under Models, you've got ApplicationUser. You've worked with this class before. It derives from IdentityUser. Which is part of ASP. NET Identity. Now this IdentityUser class does not have the Name property, so we need to add it here to the ApplicationUser. Now, because we have extended our domain model, we need to create a migration and update the database. But before doing so, there is one more thing we need to do here. This string type in C# is nullable. So if you update the database now, our Name column is going to be nullable, and its type is going to be varchar of max. In one of the earlier modules, I explained this is because of the default conventions built into Entity Framework. So we are going to use data allocations to override these conventions. First, I'm going to make this Required, import the namespace, and then I'm going to set a Length on this column. I think 100 characters is enough for a name. Now, let's go to Package Manager Console. In case you forgot the shortcut, that's Alt with a / and. Add-migration. AddNameToApplicationUser and as a good practice, we always review our migrations before writing them on the database. So, we've got AddColumn here and AspNetUsers table, we're going to get a new column called Name, it's going to be a string. It's not going to be nullable, and it's length is going to be 100 characters so that's good. Back to Package Manager Console. Clean up, Update-Database. Now let's go to the database, so Server Explorer, under Data Connections, DefaultConnection is pointing to GigHub. You can also use SQL Management Studio if you prefer. Under Tables, AspNetUsers, right click, Show Table Data. So we have one user in our database and if we scroll to the right, we see the new Name column. Because this column is not nullable, by default Entity Framework inserts an empty string here. So, I'm going to change it to, let's say, James Morrison. It's one of my favorite trumpet players. Now, let's go to our View and display the name of the artist, instead of their Username. Control + shift + N, index, that's our homepage so I'm going to replace UserName with Name. Control + shift + B, build succeeded, back to the browser, refresh. Beautiful.
225
226Extending the Sign up Form
227Okay, now there is one problem here. When a new user signs up as an artist, there is no way to capture their name so we need to modify the sign up form. So, back to Visual Studio. Again, clean up my workspace, alt + "w" + "L". Let's find the registration form, so, Solution Explorer, under Views, Account, look, we got Register, so let's take a look here. So here we have a form and we've got multiple form groups just like before, so the first one is for Email, the second one is for Password, and so on. So I'm going to add a form group for capturing the Name. You can simply copy one of these and paste it, I would like to put it at the beginning. First, we ask them about their name, then email, then password, it has a logical order, so here's the first one. Let's change the property to Name. Okay, we don't have these properties, so what's happening here? We go to the top of this View, the model behind this View is the RegisterViewModel class. It's not ApplicationUser. So we need to add this property to our ViewModel. The slow way of doing that is to open up the ViewModel class and add the property, but now I'm going to use ReSharper, so back here, to the Name property, alt and "Enter, " "Enter. " So ReSharper brings us here. It's going to be a string. Now, I'm going to apply a data annotation to make it Required, and I would also like to add StringLength, so if the user types something that is more than 100 characters, we stop them. All right. Save. Now back to the View. So we got the Name property here. Now, we need to change the Input field from PasswordFor to TextBoxFor because I copied from the Password field. And, change Password to Name. Control + shift + "b", build succeeded. Now we're going to have a new field in our registration form. Finally, when the user clicks the Register button, we need to get that Name field and put it in the database. So we go to AccountController, control + shift + "n". Now press control + "F12". With this, you can look up members of a class. I'm going to go to the Register method. We've got two overloads, the first one is to render the View, the second one that takes a view model is called when we click the Register button. So, let's go here. So first it's checking if ModelState is valid, then it's constructing an ApplicationUser object, and setting its UserName and Email. So, we're going to initialize the Name property here as well. So, Name = model, which is the View model,. Name. Now this line is getting a little bit too long so I'm going to break it up. That's cleaner. Let's run the application and make sure everything is working. So, I log out, and then Register. Okay, registration worked. Let's inspect the database. So back to Server Explorer. Right click AspNetUsers, Show Table Data. All right, here is my second user, scroll to the right, and the Name is Bill Evans, so now when a new user signs up, we can capture their name, put it in the database, and later, when they add a gig, we can display their gig and their name on the homepage.
228
229Refactoring
230Okay, before finishing this task, I want to do a bit of cleanup. So, let me show you something here. In Solution Explorer, under Models, and open up AccountViewModels. This file is part of the default project template, and as you see, there are multiple classes in this file, and personally, I see this as a smell. In a clean codebase, we should have one class per file. So, we should take each of these classes out and put them in separate files, but there's also another problem here. These classes are defined in the Models namespace. But they're View Models, they should be in the ViewModels namespace. So let me show you a couple of ReSharper techniques to quickly clean up this file. First, I want to find RegisterViewModel here, so control and "F12", RegisterViewModel. Now, I want to move this to a separate file, so alt and "Enter", "Enter". Okay, now this View Model is in a separate file. But this file is in GigHub. Models. I want to move it to ViewModels. The poor way of doing that is to go to Solution Explorer, drag this file, RegisterViewModel and drop it into ViewModels. Why is it the poor way? Because when you do this, you will move the file but the namespace will not be updated. The namespace will continue to be GigHub. Models. A better way is to use ReSharper, so I put the cursor on the name of the class, I activate refactoring commands using control + shift + "r" and the second option is Move To Folder. I'm going to move it to ViewModels. And next, that's it. Let's take a look at the Solution Explorer. Scroll down. Under ViewModels, look, we've got RegisterViewModels, it's moved here, and look at the namespace. It's automatically updated. So when you want to move files, user ReSharper. Control + shift + "r" to activate refactoring and go from there. Now, in AccountViewModels, we've got a bunch of other ViewModels classes in this file. So I leave this to you as an exercise, to move each of these classes to the ViewModels namespace, and finally, it's time to review our code and commit it to the repository. So, Save, clean up the workspace, alt + "w" + "L", Team Explorer. These are the changes we have made to add the name to the artist, or ApplicationUser class, so we've got 11 changes. I want you to review them, and the Comment, Add name to artist, check it. Beautiful.
231
232Summary
233So in this module, you saw that the ApplicationUser class in ASP. NET Identity may not have the properties you need. And there are times that you need to extend it. You may want to add additional properties to this class, like Name, Birthdate, Location and so on. The process is very simple. We add any additional properties to the ApplicationUser class and then because we have changed our domain model, we need to create a migration and update the database. Just remember, when you add new properties to this class, you may also need to modify the sign up form, and for that, you need to modify the View to add any addition fields and also modify AccountController to process those fields, but remember what you learned in the module about usability. Keep your forms simple and only capture the essential fields. In the next module, we're going to get creative again and give a nice-looking field to our homepage. I will show you how to use CSS to render and lay out like this. I'm sure you're going to love those CSS techniques so I'll see you in the next module.
234
235Creating Beautiful and Precise Designs with CSS
236Introduction
237OK, this section is all about CSS. I'm going to show you some techniques that every front end or full stack developer must be familiar with. Now, let's get started.
238
239Markup
240So, how can we implement something like this with HTML and CSS? Let's zoom into one of these gigs. To implement this, first we need a parent container. This is the element that represents one gig. Inside this element, or container, we're going to have two containers. One for the date, and one for the details of the gig. Now, look at the container for the date. This container itself has two children. One container for the month, and one for the date. So, first we need to create this structure, or markup, using HTML. Then, we'll use CSS to adjust the colors, padding, and the final look and feel.
241
242Zencoding
243Alright, so, back in Visual Studio, let's go to our index view. So, we're using this li element, here, to render each gig. This is going to be our parent container. Inside this we're going to have two containers. One for the date, and one for the details. So, temporarily, let me delete the content of this li. Now, let me show you an awesome technique called Zencoding. Which prompts the web essentials plugin. So, let's say, I want to create a div with a class date. I type div. date. Now if I press tab here, Web Essentials plugin automatically generates this for me. Now, I can make this more sophisticated. Let me delete it. I want to create a div with a class date, and next to that, I want to create another div for the class details. Now, at the same time, I want to specify their children. So, I put them in parenthesis. Each one represents a group. So, let's put this date group, inside this date div. I want to have a div with a class month, and next to that, I want to have a div with the class date. Similarly, inside the details div, I want to have a span with the class artist. And next to that, I want to have a span with the class genre. With the cursor at the end of the line, tab. Much faster and easier to create this markup. Now, let's put the values inside these divs. So, for the month, gig. DateTime. ToString Use three upper case M's. To render three letter months. And, for the date, use a lower case d. And look at the IntelliSence. A lower case d represents a short date. But I'm only interested in the day component. So, the trick is to put a space after that. So, first we press escape, So, the IntelliSence goes away, and a space. Now, for the artist. gig. Artist. Name. In case you were wondering, why I used a span here, and not a div, my personal preference is to use a div, when I want to create a layout, but use a span when I'm just going to add style to some text. You could use a div here, that's perfectly fine. And finally, for the genre, gig. Genre. Name Now, there's one we need to add here. Currently, we are either loading gigs and the artists. But, the genres are not loaded. So, if you run the application now, you are going to get a null reference exception. So, we go to home controller in our index action, we need to include genre. That's it. Build. Now, run the application. OK, the markup and the data is there. But, it doesn't look the way we want, and that's perfectly fine. That's the purpose of the next step. So, for now, look, we've got the month, we've got the day, the artist's name, and the genre.
244
245Absolute and Relative Positioning in CSS
246OK, our structure is ready, but it doesn't look like this image. To implement something like that, first we need to understand relative, and absolute position in CSS. So, here's the trick. An element with relative position allows us to absolutely position it's children. Let's take a look at an example. Imagine you have a blue container like this. If we set the position of this container to relative, we can precisely position, any of the children. So, we can put an element inside this container at this exact position. For this to happen, we need to set the position of this child element to absolute, and then use the top and left attributes to put it exactly where we want. So, here, this child element is 10 pixels from the top, and 100 pixels from the left of it's parent. So, to render the gigs in a layout like this image, we need to use this technique, so we can put the details container, about 100 pixels from the left of it's parent.
247
248Using Absolute Positioning
249Alright, now in our homepage, look, here is our details container, where we have the artist's name and the genre. I want to use relative and absolute positioning, so, we can move this container to the right of the date container. So, back to Visual Studio, in the index view, look, here's our details container. I want to set the position of this container to absolute, and it's parent, which is this li, here, to relative. Now, before writing any CSS, we need to add something here. Let's scroll up a little bit here. So, this ul, we need to give it a class, so we can identify this element and any of it's children in our CSS. gigs. Now, save. You open up inside CSS At the end of this file, I'm going to write page specific stuff, so let's start it with some generic styles. Then we have Bootstrap Overwrite, and finally, page level stuff. Now, gigs. Li. The greater than operator here means the li immediately below the gigs element. So, I want to set the position here to relative. Also, I want to add a bit of margin below each gig so they are not too close to each other. About 30 pixels Now, for the details container, we need to set the position to absolute. Back to the browser. Refresh. OK, Look. Now the details container is about 70 pixels from the left of it's parent. Now, one more thing, I want to remove the bullet points. So, for our gigs element, the ul, with the class gigs, is set the list style to none. That removes the bullet point. Back to the browser. It's gone.
250
251Working with CSS Attributes
252Alright, now let's build the calendar icon. Before we get started, I want to show you a cool technique. First, I want to put Visual Studio, and the browser side by side. So, I hold down the Windows key and press right. That pushes the browser to the right of my screen. Now, alt + tab, to go to Visual Studio. Windows key, and the left arrow. So, now they are side by side. Now, hover your mouse over this icon, here. This is called Browser Link, which comes with Visual Studio 2013. Now, look at the tool tip again, it says 1 browser connected. Chrome. It detected that I am running the application in Chrome. In your case, if you don't see that, you need to run the application in the debug mode, using this icon, here. Now, also, make sure that under browser name, both Enable Browser Link, and Enable CSS Auto Sync are checked. With this, I can make any changes here, save my file, and when I put the focus on the browser, it will automatically refresh. So, I don't need to press Ctrl and R every time. Alright, now let's use CSS to paint the calendar icon. So, first, I'm going to add gigs, li. date I want to make this background red. And, the color of the text, white. And, use text align, center, to put the date and the month in the middle. Save. Alt and tab See, the browser link automatically refreshed the browser. Now we get this weird look, that's because we didn't set the width on our date container. So, by default, it's set to 100 percent. Now, alt and tab, back to Visual Studio, and the date container width 60 pixels. Save. Alt and tab. That's better. Now, let's work on the styles for the month container. First, I'm going to make the text upper case. So, use test-transform: uppercase. I want to make the font a little bet smaller. And make it bold. Save. Back to the browser. Look, it's uppercase, it's smaller, and it's bold. But it's too close to it's surrounding. So, I want to add a bit of padding. Back to Visual Studio. So, let's say two pixels on the top and bottom, and six pixels on the left and right. Save. Alt and tab. OK, now look. The month name, it's not too close to it's surrounding. Next, let's work on the styles for the date container. Back here, so I'm just going to copy this line. Paste. Change it to, day. I want to set it's background to grey. Let's say f7f7f7. Now because the background is light, we want the text to be black, to create contrast. And let's make the day a little bit bigger. Save. Alt and tab. OK, it's getting better. Now the only problem is that the day is too close to it's surrounding. So, again, I'm going to add a bit of padding. Back to Visual Studio. Let's say six pixels on the top and bottom. And 12 pixels on the left and right. Save. Back here. It's looking better. And finally, I want to make the corners, of the dates container a bit round. So... The dates container, border-radius: 8 pixels. And use resharper to add render specific properties. Save. Back to Chrome. Look, the edges are a bit curvy.
253
254Final Polishing
255And finally, we need a few more styles to make the entire look and feel a bit more polished and cleaner. So, I want to make this artist's name bold, so it stands out. And I want to have a line break, after. So, I don't want Jazz to be right next to it. So, back to Visual Studio. Scroll down. In the details container, for the artist element, font-weight: bold and to add a line break, set the display to block. So, the reason we don't have a line break here is we are using a span, and the default display of span is set to inline. That's why the artist's name and genre are on the same line, because they're inline. See. Back to Chrome. That's better. Next, I want to make the genre a little bit smaller. Currently, it's the same size as the artist's name. And it's kind of competing with it. So, back here. Copy this line. Change it to genre. Font-size, let's say 14 pixels. Back here. It's a little bit too small. Let's go for 15 pixels. Back to Chrome. I think that's better. And, one last thing. Frankly, our first gig is right below the navigation bar. And, that's not good. Let me show you how to fix that. Back to Visual Studio. On the very top of this file, in the body element, padding top is set to 50 pixels. I want to increase this to 90 pixels. Save. Switch to Chrome. That's better. Now, let's make it full screen. Windows key and the up arrow. OK, I think the list of Artists looks pretty decent and clean. So, it's time to finish this task, review our code, and commit it to the repository. Team Explorer. Improve the look and feel of the home page. Check in.
256
257Summary
258So, in this module, you saw how we could use CSS to create beautiful and precise designs. Again, if you want to be a successful full stack developer, you need to master also your front-end and back-end skills. In this module, you learned about Relative and Absolute Positioning, which are used to create precise layouts. So, when you set the position up, an element to relative, you can absolutely position any of it's children. You also learned about Zencoding, which is a great way to quickly generate the HTML markup. This feature, as I explained, comes with Web Essentials plugin. And finally, you saw more CSS Attributes in action. We used attributes for working with fonts, colors, padding, and so on. In the next module, we're going to implement the remaining core use cases for this application. We'll be using ASP. NET web API, Bootstrap, and some Javascript to implement these use cases, from top to bottom. So, I'll see you the next module.
259
260Implementing a Use Case from Top to Bottom
261Introduction
262In this section, we're going to implement a use case end to end. So we'll add a button in front of each gig, and when the user clicks that, we'll create an attendance for them. As part of this section, I will show you two different solutions for extending our domain model and I will explain why I prefer one solution over the other. Then we extend our domain, we use code first migrations to bring the database up-to-date. And finally, we'll create an API and call it using jQuery AJAX. Now let's get started.
263
264A Poor Design
265So we want to implement the use case add a gig to calendar. Let's do a bit of class modeling. One common mistake that a lot of non-experienced developers make is that they rely too much on the words and the requirements document. So here, we're working on add a gig calendar, an amateur developer would think, "We've got two classes here, gig and calendar. " What are going to be the attributes and behavior of this calendar class? Are we going to have classes like month and day and associate them with our calendar as well? We can because after all, that's the model of the reality. A calendar has months and days, so they should be part of our domain model. Plus, one can argue that in the future, we want to integrate with Google calendars and other calendars, so we should have this calendar class here. Perhaps we can even derive other classes like Google Calendar or iCal from Calendar. But is this really solving the problem at hand? Not really. The problem we're trying to solve is keeping track of the gigs the user might be attending. The problem is not integration with Google Calendar. It's not keeping track of the months and days in a calendar and public holidays either. It's keeping track of the gigs the user might be attending, and that's the key point I want you to pay attention here. When building software, do not attempt to model the universe. Only create enough of a model to solve the problem at hand. A while ago, I was engaged as a consultant in a project and in the introductory session, I met the data architect for that project. He walked me through tons and tons and tons of classes and UML diagrams, more than 50 pages. He attempted to model the entire universe in that software. And guess what, that company spent half a million dollars on that project and nothing was produced, not even a beta version. They engaged various developers and teams, and no one could really implement that large complex model and the project was shut down. So I emphasize one more time, do enough modeling to solve today's problems, not future problems that may never exist.
266
267A Better Design
268So let's disconnect from the specific words in the requirements document and instead look at the concept behind them. A user can add a gig to their calendar and, in a separate page, view the gigs they might be attending. So essentially, what we need here is a way to keep track of the gigs that the user might be attending. So a simple association between the user and the gig is sufficient to solve this problem. A user can attend many gigs, and a gig can have many users, which we'll call attendees in this context. As you see, we have a many-to-many relationship in our object model here, and there's no need for classes like calendar, month, day and so on. Now when we take this object-oriented model and implement it in a relational database, we'll need a structure like this. We'll need an intermediary table for our many-to-many relationship. Entity Framework can create this table for us as part of a migration. But in this case, I want to add this table to our model. So I want to have a class called Attendance in our domain model. Why? Because at some point, I would want to create that object directly. Later, when we want to delete a gig from the user's calendar, we want to directly work with that object. Or when adding a gig to the user's calendar, we want to check if that gig already exists in their calendar. So when we add this Attendance class to our model, we can easily use link to queries. You will see this later in this module when we get to building the API. Now let's go ahead and add this class to our domain model.
269
270Extending the Domain Model
271Okay, back to Visual Studio. Let's go to Solution Explorer, right-click Models, go to Add, Class. Also note the shortcut, Shift + Alt and C. So here we add a new class, Attendance. Okay. Here we're going to have a couple of navigation properties, one for the gig, one for the application user, which we'll call attendee. So prop, tab, Gig, gig. Next, ApplicationUser Attendee. Also, for optimization reasons, we want to add a couple of ForeignKey properties here. I explained the reason for this earlier in the course where we were working on adding it, so it will save us from loading an entire gig or attendee object in order to add a new attendance to the database. So prop int GigId, and prop string AttendeeId. I use string here because the ID property in the ApplicationUser class is a string. Now in terms of mapping this to a table, we need a composite primary key. So the combination of the GigId and AttendeeId uniquely represents an attendance. So with data annotations, we need to apply the key attribute on both these properties. Now there's one more thing we need to add here. When you use data annotations for composite keys, you also need to specify the order for your columns. So Column. Now I'm going to copy this line and paste it here. I set the order to two. Save the file. Next, we need to add a DbSet to our DbContext because we want to query an attendance object directly. So Control + Shift + N. Now let me show you a technique. If I want to go to ApplicationDbContext, I don't have to type application Db co... I can just type the first letter of every word. So ApplicationDbContext. This is a ReSharper feature called Camel Humps, which is great when you want to look up classes or methods that have a long name. So let's go here. Now I'm going to add a new DbSet. Prop, tab, DbSet of Attendance. Attendances. Save. So we have changed our domain, now we need to create a migration. So we need to open up Package Manager Console. Remember the shortcut? Alt slash dot. Add migration, AddAttendance. Beautiful. Let's review our migration. So it's trying to create a table called Attendances with two columns: GigId and AttendeeId. Note that the primary key is composite. It's the combination of GigId and AttendeeId, and we have two relationships as specified with the ForeignKey method here. One to ASP. NET user's table, one to Gigs table. So let's go ahead and run this migration. Back to Package Manager Console. Cls to clean up. Update database. We got an error. Introducing foreign key constraint on table Attendances may cause cycles or multiple cascade paths. Let me explain what's happening here. With this model, when we delete a user, the relative attendance records will be deleted because of cascade delete. Also, for the same reason, the gigs they have created will be deleted, which will cause another cascade delete to attendance records. So the problem is we have multiple cascade paths, two different paths trying to delete attendance records, and SQL Server doesn't like that. The workaround is to disable cascade delete in one of these relationships where we don't need it. I'm thinking we shouldn't really delete gigs from the database. In fact, we should have an attribute like cancel. This also allows the user to undo these cancellations. So if you're never going to delete a gig, it's okay to disable cascade delete between gigs and attendances. How do we do that? We need to use FluentAPI.
272
273Overriding Code-first Conventions Using Fluent API
274So back to Visual Studio, we go to ApplicationDbContext. In order to use FluentAPI, we need to override OnModelCreating method here. So override OnModelCreating. At this point, we can use the modelBuilder object pass here to supply additional conflagration to override the default conventions. So modelBuilder. Entity Attendance, each attendance has a required gig. So. HasRequired. Here we use a lambda expression. So a, as in short for attendance, goes to a. Gig. So each attendance has a required gig. Now we need to configure the reverse direction of this relationship from gig to attendance. So each gig can have many attendances, that is the people who are attending that gig. So WithMany. Here we can supply another lambda expression like g, as in short for gig, goes to g. Attendances. Now currently we don't have this property in our model. There is no navigation property between gig and attendance, so we can either add this navigation property or just remove this lambda expression. For now I prefer not to pollute our domain model by adding properties that we may not necessarily need. So we configured the relationship and finally, we can call WillCascadeOnDelete and supply false here. This is how we can turn off cascade delete with FluentAPI. Now this line is a little bit too long so I'm going to break it up and make it more readable and cleaner. That's better. Also, be sure to call base. OnModelCreating at the end of this method. The reason for that is because our ApplicationDbContext derives from IdentityDbContext. So in this class, which is part of ASP. NET Identity, Microsoft has overridden the default convention using FluentAPI. All right, our configuration is finished, so we need to regenerate our migration. Back to Package Manager, cls, cleanup, Add migration, AddAttendance, and I'm going to supply the force switch to overwrite it. Yes. And finally, update database. Beautiful.
275
276Designing the API
277All right, so we extended our domain model and also migrated the database. Now we need to work on the UI. So we want to build something like this. We're going to put a button in front of each gig, and when the user clicks that button, we'll change the label and the background color of the button and also add the gig to their calendar. To implement this, we're going to use AJAX, because we don't want to do a full page reload. So on the server, we're going to create a lightweight RESTful API that we can call using jQuery AJAX. Now in terms of the contract, I want to expose this API as an endpoint like /api/Attendances. The common RESTful convention to create a resource is to use either HTTP POST or HTTP PUT. POST is more common, so I'm going to go with that. Now with POST, we'll need to include some data in the request body. What are we going to include there? We definitely need the GigId. How about the userId? I'm not going to add this there. Why? Because it's going to open up security holes in our application. A malicious user can simply post to this API, passing the ID of every user and every gig using a loop. This will mess up with the whole system. So the userId should be calculated on the server, and that should be the ID of the currently logged in user. So we want to restrict this API to only authenticated users. Now let's go ahead and implement this API.
278
279Building the API
280All right, now to create a Web API, we go to Solution Explorer, right-click Controllers, Add, Controller. From the template, we select Web API 2 Controller. Add, I'm going to call it Attendances. Okay. First time you try to create a Web API, you will see this readme. txt file that explains the additional steps that you need to do in order to enable web APIs in your project. So it's pretty simple. Basically, we need to copy this last line and put it in global asax in the applications direct method. So global, we go to the C# file. Here's application start. At the beginning of this method, we're going to paste that line. Import a name space, that's it. Save the file. Unused name spaces are removed. We don't need this anymore, so we can close it with Shift and Escape. Same here. Now back in our controller, we're going to create an action called Attend, which takes a parameter called gigId. Again, as I explained, we're not going to get the userId here for security reasons. We're going to get the ID of the currently logged in user from the user object. Now to add an attendance object to the database, we need our DbContext. So private, ApplicationDbContext. See, I'm using Camel Humps. Adbc, short for ApplicationDbContext. Initialize it in the constructor, ctor, tab. All right, now let's scroll down. So we need to create a new attendance object, add it to the context and save changes. We set the GigId based on the parameter that is passed in, and AttendeeId to User. Identity. GetUserId. Now because we need the ID of the currently logged in user, we need to apply the Authorize attribute on this controller to make sure it's only accessible by authenticated users. So okay? Next, context. Attendances. Add, our new attendance object. context. SaveChanges. And finally, we return Ok. This is a very basic implementation. I'm not checking for duplicate, I'm not doing error handling. I just want to build something simple and make sure the API is working. All right, a couple more things we need to do here. One is to use the HTTP POST attribute on this action because we're only going to call it using HTTP POST. So that's it. And the last thing. Look at this parameter here. ASP. NET Web API, by default, does not look for scalar parameter like an integer in the request body. It expects them to be in the URL. So in this case, we need to decorate this parameter with FromBody attribute just like that. Now we need to test our API. So build the application, Control + Shift + B, and run it with Control + F5.
281
282Testing the API with Postman
283All right, now to test our API, I'm going to use a Chrome plug-in called Postman. We can use any plug-ins you would like. But in this video, let me show you how to get Postman, in case you don't already have it. So open a new tab and search for Postman rest client. You see two links here. The first one, which is more popular, unfortunately didn't work for me. I had problems with authentication. So in this video, let's try the second one. Here you see this plug-in is already added to my Chrome. On your machine, if you don't have it, you're going to click this button and add it to your Chrome. Once you do that, you'll see an icon here on the toolbar. So click that. Okay, I'm going to click this icon here to collapse the left panel. Now here on the top, we need to put the URL of our API. So I'm going to use Control + Tab. Back here, Control + L. Now we are in the address bar. Control + C, Control + Tab. Back here, Control + B. I'm just going to replace Home/Index with the address of our API. Then I'm going to change GET to POST and click the raw button here. This is our request body. So here I'm going to put a GigId. And my database in the gigs table, I've got a gig with an ID 2. So on your machine, I want you to open up the gigs table and grab a GigId from there. And finally, with click the Send button. Okay, let's scroll down. You see that we get HTML in the result, which shouldn't really happen. And here in the title of this HTML, you see the word log in. This is because of the Authorize attribute we added to our controller. So it looks like the authentication is not working and the API is redirecting me to the login page. So I go back to homepage here. That's exactly right. Look, I'm not logged in. So first, let me login. Okay, now I'm logged in as you see here. Now we go back to Postman and click the Send button one more time. Okay, we get a different error. It says the request entity's media type, text/plain is not supported for this resource. So when you see that error, that means you missed a header. So click on this button here and specify content-type application/json. Now click Send again. All right, it's working. So now the body of the response is empty, we don't get any exceptions and the status is 200, or OK. Now if I click the Send button one more time, we get an exception. Let me scroll down a bit more. So somewhere near the button, you're going to see the actual exception message, which is violation of primary key constraint. It says cannot insert duplicate key in object Attendances. So here, as you remember, we have a composite primary key, which is the combination of the userId and the GigId. So for this user, I already added an attendance and I cannot do it twice. So we need to modify our action to prevent duplicates.
284
285Preventing Duplication
286All right, so back in our controller, in the attend action, I'm going to check if they already have an attendance for the current user for the given gig. So context. Attendances. Any. Look. Earlier I told you I wanted to add the Attendance class in our model because we want to directly query that. And here's an example. I want to check if there is an Attendance object for the current user and a given gig. Now let's write a lambda expression, a, short for attendance, goes to AttendeeId is User. Identity. GetUserId. And GigId is gigId. Now there's a tiny problem here. Look at this User. Identity. GetUserId. We already have this expression below. And I think that would actually make a call to the database to get the idea of the current user. Because I think by default, ASP. NET Identity uses usernames, not user IDs. So I'm going to extract this expression and put it in a separate variable. Cut. Put it in userId and paste it here. Also, I'm going to remove this expression here and replace it with userId. Now to finish up my task, if exists, I'm going to return BadRequest. And here we can supply a friendly message, like, "The attendance already exists. " Now to make this code a bit cleaner, I think we can get rid of this exists variable here. It's just an extra noise. So with Resharper, put the cursor here, Control + Shift + R, and the first option is Inline Variable. So Resharper got rid of the variable and put the expression in the if clause. Now I think it's a little bit too close to the line before. I would prefer to separate it. The code is more readable. So first, we get the userId, then we check if the attendance exist. Otherwise, we add it to the database and return Ok. Let's test this. Control + Shift + B to build. Back to the browser. I'm going to click the Send button. Okay, scroll down. So we didn't get an exception anymore. Instead we got a BadRequest, and the message is the Attendance already exists. So the API is working well, now we need to add the button on the page and wire it up to the API.
287
288Adding a Button
289So back into Visual Studio, let's go to the index view. Let's scroll down. So in the details container, I'm going to put a button after the genre. We give it a couple of Bootstrap classes. The first one is btn, which is common for all buttons. And then I'm going to use btn default and give it a white background. And the label is going to be Going with a question mark. Save. Back to the browser. Refresh. All right, this button looks a little bit too big, so I'm going to use one of the Bootstrap classes to make it smaller. So that's btn-sm, as in short for small. Save. Back to the browser, refresh. It's not working. And the reason is because of a mistake I made in one of the earlier videos. Let me explain what happened here. So right-click, inspect element. Now in the styles window, scroll down. Here we can see the styles in Bootstrap for btn-sm. So padding is five and 10 pixels, and font size is 12 pixels. But both these attributes are struck through. And if you scroll up, we can see the actual font size is 17 pixels and padding is seven and 20 pixels. And this is the btn class that I defined in our site. css. So because this class is defined after Bootstrap, it overrides Bootstrap styles. So we have two choices here. One is not change the font size and padding and just stick with Bootstrap as they define it. Or if we're going to change it, we should already it for all button sizes. So at this point, let me temporarily disable these two attributes here. Now look at our button. This is how a small button should look like. So for now, I'm going to temporarily remove these two attributes from site. css so we don't mess up with Bootstrap styles. Later, we can come back and fix this issue. Back to Visual Studio. And go to site. css and search for. btn. Okay, here's our class. I'm going to temporarily comment out these two attributes. So select them, Control + K, Control + C. Save, back to Chrome. All right, now it's working. Now one last problem. Let me zoom in. Now look at these two buttons. Their left are not aligned, and this increases the eye movements of users, which is a bad thing as explained in the section about usability. Now here we have only two gigs and two buttons, which is not too bad. But the more gigs and more buttons we have, the more you're going to see this problem. So we want to right align them. Back to Visual Studio. Let's go to the index view. I'm going to apply another Bootstrap class to our button. pull-right, Save. Back to the browser. Refresh. Okay, look, now they are perfectly aligned. So that button is there. The final step is to wire it up to our API.
290
291Wiring up the Button to the API
292All right, we are back in Visual Studio in the index view. I'm going to go to the bottom of this page and write some JavaScript. So we start with the section scripts. So what we put here will be rendered after all JavaScript libraries, like jQuery or Bootstrap will be rendered. Now the script tag. Here I'm going to handle the ready event of jQuery's document object. So when the document is loaded, we want to subscribe to the click event of our buttons. First, we need an identifier for our buttons. So let me scroll up a little bit. Okay, here's a button. I'm going to give it a new class and prefix this class with js-. This is purely a marker so I know this class is used by JavaScript and it's not for presentation. And then I'm going to call it toggle attendance. The reason I call it toggle attendance is because in the future, we'll use the same button to remove an attendance object. Now I'm going to copy this class here and use it as a selector. So jQuery dot class. Now we subscribe to the click event. At this point, we want to make an AJAX call to our API. So I'm going to use jQuery post method. The URL is /api/attendances. The second argument is the data we want to send in the request body, which would be the GigId. Now where do we get it? In this case, we need to add it to our button as a data attribute. So here I'm going to add a data attribute, gig id, and simply render gig. Id here. With that, we can go to our JavaScript function and get an argument here, let's call it e. That represents the event. From the event, we can get the source of the event, which is the button. So I can type jQuery e. target. That gives me the source of the event. Now attribute is data-gig-id. So this will post to our API and return a promise. So we can chain the done and fail methods to handle success and error scenarios. So at the end of this method, I'm going to call. done. So if the call is successful, I want to change the label and the background of the button. Again, we need e. target as a jQuery object. Now here I'm going to remove the btn-default class and add another class to make it blue. I'm going to use btn-info. And finally, change the label to Going, without a question mark. Now in terms of optimization, look, you're repeating this e. target twice. So jQuery is going to query the document object model twice here. It's more efficient to query once and store the result in a variable. So I'm going to call this button and set it to e. target. Finally, replace it with button. And same in the done method. Now in terms of clean coding, look, this line is a little bit too long. We have to scroll to the right. So I would rather, to break it up, like this. And this is our success callback. We also need to handle the failed scenario. So. fail. For now, we can just display an alert. In the future, we can use the Toast notification to make the application a little bit more fancy. That's pretty much it.
293
294Introducing a DTO
295All right, I just noticed I made a mistake here, and that's about this second argument in the post method. With this syntax, when we make an AJAX call, our controller is not going to be able to bind this value to the GigId parameter. Let's open up the controller. AttendancesController. So look at this int gigId parameter. We decorated this with FromBody. So ASP. NET runtime expects an integer in the request body. Now in order for the runtime to bind the value in the request body, so this parameter, we need to come back here and put his value in an object literal. Like this. So the key is an empty string and the value is GigId. I know this is ugly. I know that empty string as the key is weird, but this is how Web API works. Don't blame it on me. So let me show you a cleaner way to do the same thing. Back to the controller. The reason we're having this problem is because we have a scalar parameter here, the interger. If we put this in a complex type like an object, then we won't need this FromBody anymore and in our JavaScript, we can replace this empty string with gigId as a key. This, in my opinion, is a cleaner approach. If you're sending an object to the server, it has a property or a key called GigId and has a numeric value. So back to the controller. I'm going to create a new class to wrap this GigId parameter. So I go to top of this file. I'm going to call it AttendanceDto. So Dto stands for data transfer object, And it's an architectural pattern to send data across processes. So here we have some piece of code running on the client and another piece running on the server. We want to communicate between these two processes so we can use a Dto, or data transfer object. I give it a property. GigId. Now we can put this in a separate file, so the cursor here, Alt and Enter, Enter. Beautiful. Note that it's currently in the controller's namespace. I would rather to put it in a separate folder called Dtos. So Solution Explorer. Right-click, Add, New Folder. Dtos. Now we put the cursor back here and use ReSharper to move this class to Dtos folder. Control + Shift + R. Second option, Move To Folder. Change controllers to Dtos. Next. Done. And now back in our controller, I'm going to replace this with AttendanceDto. We got two errors here because GigId no longer exist. So I put the cursor here. Alt and Enter. And the last option, change all local gigId. So Enter. Now we can type dto. GigId. Enter. So using this technique, we replaced both occurrences altogether. Now let's test the application. Control + Shift + B to build. Back to the browser. Refresh. We click the first button. Something failed. Okay, right-click, inspect element. Click this red icon here. And now you can see in the console the server responded with a status of 400, Bad Requests. And the reason is we already have an attendance for the first gig for the current user. Because in the last video, when we were testing our API using Postman, we actually created an attendance. So ideally, when we render this page, the going button for the first gig should be in a state to tell me that I'm already going to this gig. But that's a separate scenario, we're going to work on that later. So for now, let's click the second button to test what we have built. Beautiful, that's exactly what I was looking for.
296
297Summary
298So in this module, we implemented another use case from top to button. First, we started by building the model, a simple model to solve the problem at hand, nothing more. Again, I emphasize one more time, do not attempt to model the reality or the universe. Only model the aspects that matter to the problem you're trying to solve. Once we built our model, we migrated our database. Then we built an API, we tested it with Postman. And finally, we placed a button on our view and wired it up to the API. And here's the takeaway from this module: at each of these steps, I was focusing only on one aspect of the development. I didn't try to do too many things. When you work like this, not only will you be more productive because you won't switch contexts all the time, but you will also write better code. Now as an exercise, I want you to implement Follow an Artist use case on your own. You can find my solution in the downloadable materials of this module. In the next module, we'll finish up the remaining use cases for iteration one and wrap up the course. I hope you enjoyed this module, and thank you for watching.
299
300Implementing Secondary Use Cases
301Introduction
302Okay now finally in the last section, we're going to implement the remaining use cases and finish the first iteration. As part of this section, I'm going to show you more techniques like hiding certain elements for anonymous users, using partial views, and some more CSS tips and tricks. Now let's get started.
303
304A Quick Code Review
305Okay let me quickly walk you through what I have done to implement and follow an artist use case. So now in front of each artist we have a link called Follow. When I click this link, it changes to following. Now this is a temporary solution. I don't want to have this Follow links here, because we have too many actions here. For each gig we have a button to add it to calendar. And also a link to follow the artist. Later when we implement the use case to show the details of a gig, there we can display some information about the artists and put the follow button next to the artist on that page. Now let's take a look at the implementation. So I open up Team Explorer, you can see my changes here. We've got ten changes. We've got a new controller. We got a DTO. We got a migration. We've got a few changes in our domain model. And a change in our index field. Let's start with the domain. So I added a new class called following. Which could also be called relationship. This following, as you see, has a composite primary key. Which is the combination of two user ID's. One as the follower, one as the followee. We also have two navigation properties here, follower and followee. And this is very similar to that tennis class. So first I created this class and then I modified application user, so let's take a look. So here I added two properties, followers and followees. Note that they both are collections and I have initialized them in the constructor. So as a rule of thumb, when you add a property to the class and that property is a collection, you should always initialize it in the constructor. Because that's the responsibility of that class to initialize that collection. So these were the changes I made to our domain model. Then I added a db set to our db context. Application db context. So look we've got a new db set. Called followings. And then on model creating method... I've configured the relationship between application user and it's followers and followees. So in the first configuration here, you see an application user has many followers. And each follower has a required followee. And note that I have turned off cascade delete on this relationship. The reason for that is because of multiple cascade paths problem that I told you about earlier. And here's the second configuration. An application user has many followee's and each followee has a required follower. And again here, I have disabled cascade delete. So once I made these changes then I created a migration. Let's take a look at our migration. So this migration creates a new table. Called followings with two columns. Follower ID and followee ID. And here are the primary keys composite, which is the combination of these two columns. So this table is very similar to our attendance's table that we created earlier. Then I ran this migration, updated the database, and next I created an API. Let's take a look at the API. So that's called followings controller. Again, very similar so we have the authorize attribute to limit this to authenticated users. And we have an action called follow, which takes following DTO. I've decorated this action with extra tp post attribute. And the implementation is again, very similar to attendances controller. So first we get the user ID. Then we check if there is a following object, or this user, and a given artist. If yes, we return bad request. Otherwise we create a following object and add it to the database. Finally return ok. I tested my API, everything was fine. So then I moved to the index view. Here in the details container, in front of each artist I added a button. I used btn/link, which is part of bootstrap, to give your buttons the look and feel of a link. And I also used js-toggle-follow as a selector to wire this button up with the API. Also note, the use of data attribute here. Data-user-id and this is where we stored the artist ID. Now let's take a look at the jQuery code. So again very similar. You handle a click event of all buttons with the class JS toggle follow. And a click handler, first we get the button. Then we post to the API. And supply the data. If everything works, we change the label of the button to following, otherwise we display it another way. So as you see, this exercise was very easy and I hope you completed it successfully.
306
307Hiding Actions from Anonymous Users
308As I was testing the application, I noticed a problem. I'm currently logged out as you can tell from the navigation bar. But we still have these two actions here. Follow and going. I want to show them only to authenticated users. So let's go ahead and fix this problem. So back to Visual Studio. Let's go to the index field. So here's the artist's name. And here is our button. I want to show this only to authenticated users. But how do we know in a view if the user is authenticated or not, that's the job of the controller to pass this information to the view. So let's go to the controller. That is home controller. So here in our index action, currently we are returning a list of gigs, that's the model that we put in the view. We need to supply additional information to this field. So I want to change the model of this view from an innumerable gig to a view model that has two properties. Something like this. Let's call it home view model. Give it two properties. So upcoming gigs and show actions. And I'm going to set this to user. identity. isauthenticated. Now with resharper, we can easily create this class. So I put the cursor on the class name. Alt and enter, enter. Here's home view model. Now to get back to where we were, I hold down the control and press minus. There we are. Again I'm going to put the cursor on the arrow here, alt and enter, the first option is create property, enter. Resharper detected that the type of this property should be IQueryable Gig. I prefer to change this type from iqueryable to innumerable, because when I pass the model to the view I want the view to iterate over it. I don't want it to use an iqueryable to extend the query. It's not the responsibility of the view. So IEnumerable. Gig, now control minus. There we are, back in the index action. Again, alt and enter, enter. Resharper detected that we need a boot in here. So we press enter and accept it. Now you want to move this view model to view models folder. Because currently it's placed next to the controller. So control shift R, move to folder. And we change this to view models. Enter. Beautiful. Control minus. We're back in the index action. Now I'm going to send the view model to the view. Save, now let's go to the view. We need to change the model behind this view so we go to top of the file. I'm going to change IEnumerable of gig to home view model. Now we've got a bunch of errors, but that's pretty easy to fix. So for each, instead of iterating over the model, I'm going to iterate over model. upcominggigs. All errors are resolved. Now let's go to our button. So here is the button to following artists. I'm going to display these using an if block. So if model. showactions is true, I'm going to render this button. Now I'm going to do the same thing with the other button, so copy. Here's the second button. Paste, here are the braces. Put the button inside the if. Now select, tab, tab, tab, tab. That's it. Nice and clean. Control shift B alt and tab. Back to the browser. Refresh. Beautiful, they disappeared. Now let's log in. And here we got our buttons.
309
310Implementing a Supporting Use Case
311So we have implemented add a gig to calendar, but currently there is no way to verify that. So now we need to implement view gigs I'm attending as a secondary or supporting use case. So back in Visual Studio. Let's go to gigs controller. I'm going to create a new action here called attending, which would return a view that will render the list of gigs the user will be attending. So we can create an action here. We need to decorate this action with the authorize attribute. Because this should be accessible only by authenticated users. Okay, now we need the list of gigs the user is going to attend. So we start from context then attendances. Now here went into Filter. So where A goes to a. attendingID is the ID of the currently logged in user. So first we need to get the user ID and put it in a separate variable. That's user. identity. giguserid. As I explained before, we can not write this expression as part of a query because link cannot link cannot translate that to sequal. So now we put that here. So what we get here is a list of attendances. But what we want is the list of gigs. So then we need to select again A, as it's short for attendance goes to a. gig. And finally I would like to call to list to immediately execute my query. Now this line is getting a little bit too long, so I'm going to break it up. So where then select and to list. That's more readable. And finally we will put that in a view and return it. Now there was a time that I could create a view using resharper here, but I don't know, for some reason it's not working for me anymore. So we have to manually go to solution explorer. Go to Views. Right click Gigs. Add view. So I'm going to call this attending. Now what I want to display here is a list of gigs. I want this list to look like the list we have on the homepage. So let's go to the index view. Now I have two choices here. One is to copy this mark up into our new view or extract this into a partial view so we can reuse it in both places. For now, I prefer to go with the copy approach because I don't want to focus on something else. I don't want to get distracted by too much refractory and moving things around. Let's build this page, make it work, and then we'll do refactoring. So I'm going to select this entire UL using control W. Copy, back to the attending view. And paste it here. Now on the top we need to set the model for this view. The model here should actually be home view model. Because this markup is relying on that view model. So model home view model. Now this is a little bit odd because we are in the attending view, but you're referencing home view model. So it's better to rename this view model to something like gigs view model that we can reuse on both these views. So my cursor is here on home view model. I press F2, rename. To gigs view model. Now resharper automatically renames the class and the file. And both these views are also updated. Both the index view and attending view. Now the last step is to put a link to this action in our navigation bar. So we need to go to underline, log in partial. Here we've got the markup or dropdown menu on the navigation bar. So look, earlier we added this gigs I'm going, so I'm going to replace this href here. With url. action. The name of our action is attending. And the controller is gigs. That's all. Build, beautiful. Now before testing the application, I want to make sure my attendances table is empty. So when we add a gig to the calendar on the homepage, then we can go to this new page and verify that it's there in the calendar. So server explorer. Open up tables, right click attendances. Show table data. Look I've only got two attendances. I'm going to delete both of these. Back to the browser. Refresh. Alright we go to this dropdown menu, gigs I'm going. We got an error. The model item passed into the dictionary is of type, list of gig, but this dictionary requires a model item of type GigsViewModel. So we need to go back to our controller, gigs controller. Look in our attending action, you're returning a list of gigs here. But because we reused the markup from the homepage, here we need to use GigsViewModel. So var viewModel equals new GigsViewModel. The first properties, upcoming gigs. And the second is Showactions, which I want to set to user. identity is authenticated. Then put the view model here. Build, back to the browser, refresh. Okay so far so good. So we don't have any gigs in our calendar. Let's go to the homepage. I'm going to add the first gig to my calendar. Going, beautiful. Now let's go here. We've got a no reference exception. And that's happening here. In the view, gig. artist. name. So artist is no. And that's because we haven't loaded artist. So back to the controller. Here where we are selecting the gig, we should also include the artist and genre because we're going to display both these attributes. So include g goes to g. artist. And another one is include g goes to g. genre. Control shift B. Back to the browser. Refresh. Look, a gig on 20th of November is now in my calendar. Now what I'm missing here is this button should be in a state to show that I'm going to this event. So it should be blue and it shouldn't have a question mark in it's label. We're going to look at this in the second part of this course.
312
313Refactoring: Applying the DRY Principle
314And the final step, currently we have two views that look exactly the same. One is index, which is our homepage, and the other is attending, which we just created in the last video. So I'm going to apply the dry or don't repeat yourself principle here. So we go to solution explorer. Let's scroll down. Look at views, gigs. So our attending view is here. But our index view is under home folder, which is used by home controller by convention. So what we want here is a view that can be referenced by both home and gigs controllers. In order for that to work, this view needs to be in a shared folder. So I'm going to drag this index view and move it to shared folder. And then I'm going to rename it to gigs. Because it renders a list of gigs. And now look at the view model behind this view. It's gigs view model. So note the consistence in the code. I have a view called gigs and I have a view model for that called GigsViewModel. And I'm reusing this both to display the list of upcoming gigs on the homepage and the list of the gigs the user is going to attend. And the interesting thing here is we didn't come up with these names straight from the beginning. This view used to be called index. And the view model behind that was home view model. Then as we were adding new features and we were refactoring our code, we came up with the structure that is cleaner and more consistent. Alright now we need to go back to solution explorer. We don't need this attending view anymore. So delete. We just need to modify our controllers so they use this new view. Let's go to home controller. So in the index action, I'm going to supply the name of the view. Which is going to be gigs. Now I'm going to do the same thing with the gigs controller. Gigs controller. Here's our attending action. So I'm going to set the name of the view to gigs. Let's run the application and make sure both these pages are working. Control shift B, back to the browser. We are in the attending page, refresh. Okay we lost the page heading, but that's pretty easy to fix. So back to Visual Studio. Let's go to our gigs view. So this view starts with a UL. We don't have a heading here. So I'm going to add h1 here. And render model. heading. We don't have this property or view model, so we create it with resharper. Alt and enter, enter. And I'm going to set this to string, done. Now we need to set the heading in our controller as we're initializing the view model. So let's go to gigs controller. In our attending action, I'm going to initialize the heading here. And do something similar in the home controller. Build, back to the browser. Refresh. Okay the heading is there, but it's a little bit too close to our gigs. I'm going to fix that in a second. Let's just finish up this task. So let's go to the homepage. Alright so both these pages are working properly after my refactoring.
315
316Adding Vertical Space Using CSS
317And the final step, we want to add a bit of vertical space between the heading and the list of gigs. We can easily do so with css. And we have two options here. One is to define a style for our h1 heading and add margin button there. But the problem with this approach is it may not always work. Maybe on another page I want the text below the heading to be pretty close to it. Another option is to add margin top to our list of gigs. So this list is a UL and we already have a class for that. So we can add margin top to that class. But again here there is a problem. Maybe on another page I don't want to have the margin on top of this list. So in this video, I'm going to show you a third way that is cleaner, more reliable, and more reusable. So back to Visual Studio. Let's clean up our work space of wl. And go to site. css. Let's scroll down a little bit. So before we get to bootstrap overrides, I'm going to define a number of classes to add margin on top of an element. Something like this. So v as in short for vertical offset. This adds two pixels margin to top of an element. Now I duplicate this with control D. Change the class name to one. And increase the margin to let's say five pixels. Repeat, we offset to 10 pixels. Again this time I'm going to set this to three and margin to 20 pixels. Four margin to 40 pixels. And five margin to 80 pixels. That's enough for now. Now we can add one of these classes to any element without missing out with the design of the site at a global level. So let's close this. And go to gigs view. So here's my UL. I want to add vertical space between UL and the element before that. Which is the heading. So I can apply v offset three. Save, back to the browser. Refresh. It's a bit better. We can increase it, let's go back. Let's try four. Save, back to the browser, refresh. I think it looks reasonable. By the way, this is the zoomed in view. So the actual view is like this. Now it's time to review our code and commit it to the repository. So back here, Team Explorer. Implement new gigs I'm attending. Check in. Beautiful.
318
319Exercise
320So we have tackled all the core use cases in this application. The only one remaining is who I'm following. And I want you to do that as an exercise. Once you do that, you can download my solution in the downloadable materials of this module.
321
322Course Wrap Up
323Okay if you made it this far, you have proven your passion and determination for learning new things and improving your skills. But first of all, I want to congratulate you on that. Second, I want to say thank you. Thank you for letting me be your instructor and watching this course all the way through up to this point. I hope you have learned a lot of new things. But our journey is not finished. There are two more parts to this course. In the next part, we'll be looking at implementing CRUD operations, refactoring our domain model to a behavior reach, an object oriented model. I will also show you how to use various useful Bootstrap components like dialog boxes, popovers, icons, badges and so on. But also look at various useful Javascript libraries like Underscore. js and moment. js. On the CSS side, we'll look at using LESS to create cleaner and more maintainable CSS. I will also show you how to create animations with CSS. And lots of other techniques that you can use in a lot of applications. So I hope to see you in the next part.
324
325Course author
326Author: Mosh Hamedani
327Mosh Hamedani
328Mosh (Moshfegh) Hamedani is a passionate and pragmatic software engineer specializing in web application development with ASP.NET MVC, Web API, Entity Framework, Angular, Backbone, HTML5, and CSS....
329
330Course info
331Level
332Beginner
333Rating
3344.8 stars with 1132 raters(1132)
335My rating
336null stars
337
338Duration
3395h 34m
340Released
34125 May 2016
342Share course