Creating your ASP.NET MVC 5 Application from SCRATCH for Beginners: Using Entity Framework 6 and Identity with CRUD Functionalities


Interested in creating your own website? Want to learn a new Ever wondered how cool is it to have a website that has a log-in/log-out functionality? Want to learn how to Create, Read, Update, or Delete(CRUD) records in a database? Are you lost track of your tutorials? Well, I'm going to teach you how to create one from scratch wherein you will know every single detail on how the code works. If you are new to back-end web development, this tutorial is for you. I'll explain everything in detail so that you won't have to research some particular methods being used. Also, I won't be focusing on the website design since we're after the functionalities. What will be doing is a simple item list when the users are logged in.


If ever you are an experienced programmer with a little background on C# and stumbled upon online tutorials, most likely you are referred to just creating the built-in internet application template of Visual Studio which is very complicating to understand. Be it the MVC, Web API, Single Page, etc, Visual Studio has it made as a template. Not really beginner-friendly if you ask me. So I made this article for beginners, explained everything, and built from scratch. Hopefully, after this, you could try to build your own site using ASP.NET MVC.


Pre-requisites


In this tutorial, we'll be using the following software together with some programming languages. If you have zero knowledge of the following especially on Object-Oriented Programming (OOP), you will definitely have a hard time understanding this as this article uses a lot of OOP concepts. If you want to have a little refresher, this article is a good start. Moving on to the pre-requisites:



  1. Object-Oriented Programming Knowledge - Just reiterating what I said earlier and just to clarify a little further, its preferred that you know this. Although I'm not saying this is totally mandatory, it's better to have a little background in order to easily grasp the topic. Know at least the basics. Don't worry, you don't have to master everything as long as you know how an object works.

  2. C# Programming Language - This will be our back-end code and pretty much the majority of what we're writing.

  3. HTML/CSS - Pretty much the bread and butter of web applications but still worth mentioning for starters.

  4. Internet connection - I know it may sound a little obvious but it's still worth mentioning. This is very minimal and you don't need this the entire tutorial. Placed it to give you an idea to prepare for a few seconds of a stable connection. The reason is we'll be getting libraries on NuGet which requires an internet connection.

  5. SQL - A little bit about databases will do. If you have knowledge of object-relational databases then you can easily grasp the topic.


For the software, you'll be needing the following:


1.) Visual Studio Ultimate 2013 OR Visual Studio 2013 Community OR Visual Studio 2012- Our Software and IDE for developing our app. For ultimate, better if you can download together with update 4.You may start with a 90-day free trial. If you still have VS2012 you can still use it however by default, it might not provide you with MVC 5 so you'll need to adjust and update it to have it support MVC 5. If your school is subscribed to a Dreamspark premium or your company owns a Bizpark license, you may get it there provided with a corresponding serial key. VS2013 Community is free in any case your license has expired on Ultimate or if you didn't avail one.


Warning: The file is approximately 5GB so make sure to have a good internet connection regardless if you got the ISO or the small EXE installer. Installation might take more or less 3 hours depending on your PC specs and even in some cases an ENTIRE DAY (which happened to me) so make sure you do this in advance before starting.


2.) Internet browser - IE, Chrome, Safari, Opera, whatever suits you. This will be used to view your web page.


Make sure to have Visual Studio 2013 installed. If ever you have Visual Studio 2012, it has a different file structure so you might get confused nor get lost along with the tutorials so it is recommended that you use VS2013.


Table of Contents


I'm not going to subdivide this into separate articles as it can seem confusing. I'll place the processes here so that in case you want to resume, you can simply press control + f OR command + f then look for the number where you last stopped.



  1. Creating your Empty Project

  2. Creating the Authentication Middleware using Identity

    1. Installing the Owin packages

    2. Coding the Middleware

    3. Connecting the Middleware to the Solution



  3. Creating the Basic Home Pages

    1. Adding the Home Controller

    2. Adding the Home View

    3. Explaining Views and Master Page



  4. Adding Authentication Security and Unauthorized Page Placeholder

  5. Creating the Login Model and Login Form

  6. Adding the Login logic With Hard-coded Values

    1. Adding the HttpGet Login Method

    2. Adding the HttpPost Login Method

    3. Adding Credential Validations

    4. Displaying the Error Message and Adding URL Validation



  7. Displaying Persisted Values and Adding the Logout Logic

    1. Displaying Your Name

    2. Creating the Logout Button and Logic



  8. Creating the Database using LocalDb

    1. Connecting the Database to the App through Connection Strings

    2. Creating the Database Tables



  9. Linking the Database Through Entity Framework

    1. Creating the Context and Renaming the LoginModel

    2. Cleaning our AuthController Redirection



  10. Creating the Registration Page

    1. Creating the Registration Action and View Page

    2. Creating Data Encryption and Decryption

    3. Creating the Query Logic

    4. Editing the Login Logic



  11. Creating our List Table

    1. Creating the UI for the tables

    2. Creating the List Model and Linking it to the Database

    3. Adding Input Fields

    4. Explaining Relationships Between Tables: Another Logged-in User = Different Item List



  12. Adding Items to our List

  13. Displaying the Items to the List

  14. Editing the Items

    1. Adding the Edit View

    2. Creating the Edit Logic



  15. Deleting Items from the List

  16. Displaying Public Data

  17. Cleaning the Code

  18. Debriefing and Summary


Note before starting: In case the picture is too small or unreadable, you can click the picture for the enlarged version. In case you get lost, I have the complete copy of the code which you can use for a reference at the end of the tutorial (In chapter 18).


1.) Creating your Empty Project


Let's first create a new project. Open your Visual Studio (In my case, I'm using Visual Studio 2013) and go to New Project (located on the left side) then a pop-up window will appear. From there go to Installed > Templates > Visual C# > ASP.NET Web Application. From the name textbox (located below), name the project MyFirstWebsite then click OK.


1


Next on the next window, select Empty on the template window and click on the MVC checkbox below on the Add folders and core references for then click OK.


2-2



Now you might ask what's with the MVC reference? It means when we create the project, we're adding the following folders:



  • App_Data

  • App_Start

  • Controllers

  • Models

  • Views


And that's it. It only creates 5 folders. Don't worry, they are pretty much empty folders (except for App_Start and Views. I'll explain the one file residing inside them later) and we're still building the app from scratch. The only difference from this on not checking the MVC checkbox is that in a literally empty project, those folders are not created. Your workspace should look like this:


3


Enclosed in the box are the folders created from the MVC reference as I mentioned earlier. Then again if not checked, just imagine those folders are gone (which means the solution file, Properties, References, Global.asax, packages.config, and Web.config is only present in a literally empty project)



Now you might notice that inside the App_Start folder, there's a RouteConfig.cs and inside the Views folder is a web.config file. These are initially created on the MVC reference. RouteConfig.cs is the file that deals with how URL routings of your app work. We're not going to do anything with it as we are not customizing our own routes yet. Now you might notice we have a web.config inside the Views folder and one outside. Don't get the two confused!


The one inside the Views folder is used to tell the project that within the Views folder, we can use Razor syntax within our cshtml file (our views or rather, our HTML file designed to accept OOP razor codes).


The one outside is used to configure the entire project's references and connections.


10


2.) Creating the Authentication Middleware using Identity


Next, we'll create our middleware using ASP.NET's identity. You might ask what middleware is. In a nutshell, middleware is the pipeline between the communication of the server and the application. For short, its a bridge between the two. You can read more about this great article. On the Solution Explorer located on the right, right-click on App_Start. Go to Add > Class...


4


From the class, we'll name it Startup.cs then click OK


5


Startup.cs in the standard internet application template is the default name and middleware where we place settings from cookies. In our case, we'll build it from scratch.



2.1 - Installing the Owin Packages


From the Solution Explorer, right-click on MyFirstWebsite then click on Manage NuGet Packages...


6


On the search bar on the upper-right, type in Microsoft.Owin.Host.SystemWeb then click on Install beside it then just agree on the terms and continue. Wait for the installation to finish. We are installing Owin, .NET's middleware specification.


Note: You'll need an internet connection to get the library


7



After, you should see a green check-mark beside it indicating that it's successfully installed. This time, type on the search bar Microsoft.Owin.Security.Cookies then install.


8


A green check-mark should appear beside it. Now we're set to code our middleware. On Startup.cs, add the owin libraries by placing this on top. This is the libraries we downloaded earlier and now we're placing it as a reference.


[code language="csharp"]
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
[/code]


Then the following function inside the Startup class:


[code language="csharp"]
public void Configuration (IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login")
});
}
[/code]


2.2) Coding the middleware


9


Here's the explanation to the code:



  • IAppBuilder - Parameter object that serves as the entry point to the pipeline. This serves as the linking of the pipeline branches

  • app.UseCookieAuthentication - From the method itself, we're going to use cookie-based authentication. Have no idea what cookie-based authentication means? This Stackoverflow answer pretty much explains it. In a nutshell, it means you provide a word and set its value in which this word will be used to bridge the communication of the app and server.

  • CookieAuthenticationOptions - This class contains the options that will be used for cookie-based authentication. Note that this is a parameter inside the UseCookieAuthentication method.

  • AuthenticationType - This is a property defined within the CookieAuthenticationOptions class. We say that we're using an "ApplicationCookie" which is a string that defines the cookie.

  • LoginPath - It's assigned from PathString Object in which the URL it contains is where the user will be redirected if he/she is not authorized.


2.3) Connecting the Middleware to the Solution


Now that we have our middleware created, let's tell our project that we created one and have it executed at the start of the app. Open the Web.config file from the solution and inside the <appSettings> tag on top, add the following line:


[code language="csharp"]
&amp;lt;add key="owin:AppStartup" value="MyFirstWebsite.App_Start.Startup"/&amp;gt;
[/code]


11


Let me explain the tag format. the key indicates that you have owin to start on the execution of the app. value indicates the namespace of your Startup.cs file in our case, its MyFirstWebsite.App_Start and lastly the class name which is Startup. Connecting the dots, we have the value MyFirstWebsite.App_Start.Startup.


If you don't know where the namespace comes, its the directory from your solution. This will show you how to locate the namespace of the class:


12


HOLD YOUR HORSES! DO NOT RUN THE APP YET!


If you do, it will throw you an error saying you have no default page. Now that's the next thing we're going to do.



3.) Creating the Basic Home Pages


Now let's create our basic placeholder page. With that, we'll create an MVC controller named "Home".


3.1) Adding the Home Controller


From the Solution Explorer, right-click the Controller folder then Add > Controller...


13


From the controller window, select MVC 5 Controller - Empty then click on Add


14


Another window will appear. Name it as HomeController and click on Add. It should now scaffold and after, you should have something like this:


15



If you are wondering what's this Controller term, it's the C from the acronym MVC. MVC stands for Model-View-Controller. We'll not dig deep into it but in a nutshell, what the controller does is we process all the logic here. The model is basically the data. Just imagine it as database tables. The view is the look and feel of your app.



3.2) Adding the Home View


Next, we'll create a view for our home controller. This is the so-called HTML of the controller. Right-click on the Index() method then click on Add View...


16


A window for the view settings appear. Leave the View name as Index and leave everything as is then click Add.


17



It will then create Index.cshtml inside the Views > Home. Now let's try running the app by clicking the given browser on top with an arrow beside it (Below the DEBUG, TEAM, and TOOLS navigation and currently above the Startup.cs tab. Refer to the squared area above). In my case, I'm using Google Chrome.


18



It should have a layout like this:


19


WHOAAAAH WAIT! I know you might be expecting a plain HTML page but all of a sudden, why was there a black navbar and a footer? That's the next portion I'll discuss. By the way, you might notice the URL route is Home/Index. By default, the Home controller is the default controller and Index is the default action method that the site finds whenever running. You can check the RouteConfig.cs file located on the App_Start folder (Refer to the second image below).



By the way, you can stop the program from this point. To stop the program, there should be a square button on the right.


34



RouteConfig.cs:


22



Next, you might ask "How do I run the web app without the Home/Index appearing? How do I set it as locahost:<portnumber> without the URL as my default page?". Simple. Make your URL property as an empty string or in other words, url:"". Your default view is still from the Home controller and Index action method but the URL should now appear only as localhost.


I'm not going to do that as I'll just go with the flow for now. I just gave you an idea just in case you want to modify the app for future use.


3.3) Explaining Views and Master page


Have you recalled the part where you created your Home view index? There was a portion there that says "Leave empty if it is set in a Razor _viewstart file". _ViewStart file is located at the Views folder and I'll be explaining it in a bit while. Let me show to you that window again and look at the lowest text box (This was also the picture from part 3.2):


17



You have the "Use a layout page:" checked by default so it will reference a master page. The master page by default is named as _Layout.cshtml and located at Views > Shared. How was that configured by default you ask? It's at the _ViewStart.cshtml file. It tells where's the default master page should be located whenever you check and leave the directory empty. If you'll open it, it should have the code like this:


[code language="csharp"]
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
[/code]


telling that the default master page is always located on that directory and will always be the default, not unless changed.


A master page is a page to be used all throughout so that you don't need to re-code again similar HTML tags such as navigational bars and footers. This makes structuring cleaner to read. Let's open our _Layout.cshtml and see what it looks like:


20




Get it now? You notice that there's a @RenderBody() method. It renders the view from your action method. In every master/partial page, @RenderBody is always required. Regarding the CSS classes, they are predefined on the Bootstrap framework. The bootstrap file was also generated when the project was created. Its a framework created for mobile-friendly websites. we'll not dig deep into it but if you like to learn on how to code bootstrap, this is a great start.


Note that this framework is not created by Microsoft so don't get confused about it. It was generated during project creation but doesn't mean they own it. It's open-source so it's free for modification.



Moving on, you might question how did Startup.cs get in the picture? The thing is it's not yet there and that's our next job.



4.) Adding Authentication Security and Unauthorized Page Placeholder


On the Solution Explorer, right-click on the App_Start folder then add another class named "FilterConfig.cs". From there, add the using System.Web.Mvc as your reference and the following code:


[code language="csharp"]
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
[/code]


21



We created a function named RegisterGlobalFilters with a parameter called GlobalFilterCollection. What does that mean? GlobalFilterCollection is a class that deals with filtering. They define action methods that usually have a one-to-one relationship with possible user interactions, such as clicking a link or submitting a form. Filters are custom classes that provide both a declarative and programmatic means to add pre-action and post-action behavior to controller action methods. For example, when the user clicks a link, a request is routed to the designated controller, and the corresponding action method is called. You can read this for more info.


Inside the method, we've added 2 classes named HandleErrorAttribute and AuthorizeAttribute. HandleErrorAttribute is the class that will handle all exceptions thrown by the action method. AuthorizeAttribute on the other hand is the main reason why we created the filter. What that class does is to specify access to a controller or action method that is restricted to users who meet the authorization requirement.



Lastly, we'll let the app know that FilterConfig.cs exists and it should always start during run-time of the app. On your solution explorer, go to Globax.asax.cs and add its reference (the namespace of the file) using MyFirstWebsite.App_Start on the top. Next, add FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters) below RouteConfig.


23


Now that we have our filters, let's try and run the app. It should appear like this:


24



WOAAAAAHH CALM DOWN! I know an error occurred but its fine and it means you're on the right track!


It will definitely produce an error due to the following reasons:



  1. We are not authorized even on our default route, which is Home/Index - You are always directed to that page. TRUE! Then again it's your default page. You might ask how was that route secured? Have you recalled the filters you placed earlier? AuthorizeAttribute in particular? Yup, that's right! That's the reason why. Every controller you have is considered to be part of an authorized page. That's the purpose of the AuthorizeAttribute. The app is trying to look for cookies for authentication but it doesn't exist. Its linked with Startup.cs as it tells our application uses Cookie authentication. Try removing filters.Add(new AuthorizeAttribute()); and run the app. It should work so you can see but make sure to bring the code back.

  2. We don't have a placeholder page yet for the route auth/login - If you recall error 404, it means the page is not found. If you also recall our RouteConfig, the format goes as {controller}/{action} in our case, we have not created the AuthController and an action method called login. The ?ReturnUrl=%2F is just a query string that appears whenever you are redirected. %2F means a forward slash (/) wherein 2F is the hexadecimal value for a forward slash and the percent sign (%) tells that its an ASCII character. You might ask why auth/login is our default redirected page(route) for unauthorized users. Have you recalled your Startup.cs? Your LoginPath string? Putting this picture again might do the trick:


9


Having those said let's resolve the error by creating a controller (empty MVC 5) named AuthController and replace the Index() action method to Login().


Note that you will see a red line once you rename it. Put your cursor there and a drop-down will appear. Rename it to Login. The reason for that is to rename everything referenced from that action to the newly edited action name.


25



Now let's create our Login view by right-clicking the Login() then Add View... Leave everything as is then Add. You should have an Auth folder within the Views folder then the view should look like this:


26



Let's run the program once again and see what happens...


27



WOAAAH RELAAAX! Then again, it's fine and if this happens, you are on the right track!



You might scratch your head on this. You already created a controller, an action method, and a placeholder page that represents auth/login but yet an error still occurs. If you recall the two reasons I've said earlier, we only solved problem number 2 BUT not yet problem number 1. Let me just say it again, because of AuthorizeAttribute, Every controller your have is considered to be part of an authorized page. Meaning, your auth/login is considered to be a secured authorized page which is also one of the reasons why you have looping redirects, and those looping causes you to stack up the query string on the URL (which is auth/login?ReturnUrl=%2).


Let's solve that problem, shall we? On your AuthController, place in the Data Annotation on top of the class [AllowAnonymous]


28


It simply says that everything under your AuthController can be accessed by anyone. This also by-passes the AuthorizeAttribute filter telling it that it shouldn't be always a page for authorized users.


Now let's run again the app and see what happens...


29



Phew! We finally have it working!


We have finally finished securing the Home Page. The next stop, creating our Model and form for logging-in.


5.) Creating the Login Model and Login Form


If you don't know what Model is, just so you know its the representation of your database entities. In other words, its what you ask or let the user input for information (such as textboxes and checkboxes).


We'll create one by making a class. On your Models folder, create a class and name it LoginModel.cs


30


Then in your class, add using System.Web.Mvc and using System.ComponentModel.DataAnnotations as your references and the following code inside the class:


[code language="csharp"]


[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }


[Required]
[DataType(DataType.Password)]
public string Password { get; set; }


[HiddenInput(DisplayValue=false)]]
public string ReturnUrl { get; set; }


[/code]


31



Those are the representations of our login form later. Annotations such as [Required] tell those model entities are associated with it where areas:



  • [Required] - required input field. If stated and if this portion is left null, then the form will not submit.

  • [DataType(DataType.Password)] - Tell that this field is a password. So the text field should be masked with dots just as a typical password field.

  • [HiddenInput(DisplayValue = false)] - A hidden input text field. This can be considered as a temporary storage of data.


Next, let's create our login form. On our Login view, let's place the following code:


[code language="csharp"]


@model MyFirstWebsite.Models.LoginModel
@{
ViewBag.Title = "Login";
}


&amp;lt;h2&amp;gt;Log In&amp;lt;/h2&amp;gt;


@Html.ValidationSummary(true)


@using (Html.BeginForm())
{
@Html.EditorForModel()
&amp;lt;p&amp;gt;
&amp;lt;button type="submit"&amp;gt;Log In&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;
}


[/code]


32


Here's the explanation to the code:



  • @model MyFirstWebsite.Models.LoginModel - Loads the reference for the Login model to let the view know we're using a model

  • @Html.ValidationSummary(true) - This reveals the output message if ever a validation error occurs. For instance, if you submitted texts in a numbered-only text box or did not place any values on a required field would result in this area displaying the errors. The true argument states that it should only display mode-related errors, otherwise if false, it will display every error. We place true because we'd only care about model-related errors for now.

  • @using (Html.BeginForm()) {}- This is equivalent to a <form> tag.

  • @Html.EditorForModel() - Displays your model based on the attributes. Pretty much lays all the cards in the table regarding your model.

  • I guess I don't need to explain the following HTML tags below...


Run the app and it should look like this:


33



As you can see, the form was automatically created based on your model. Next, we'll create our logic for Login and Logout using hard-coded values.



6.) Adding the Login with hard-coded values


We'll put into action one of the main features of our app which is having a Login and Logout feature.


6.1) Adding the HttpGet Login Method


We'll update your AuthController and type in the following code:


[code language="csharp"]


[HttpGet]
public ActionResult Login(string returnUrl)
{
var model = new LoginModel
{
ReturnUrl = returnUrl
};
}
[/code]



35


Note: If you are having an error on instantiating the LoginModel, just right-click it (As in the LoginModel word itself) > Resolve > using MyFirstWebsite.Models. That should do the trick and unfortunately, I didn't place it in the reference on the screenshot :(



We've added a data annotation named [HttpGet] and added a parameter named string Url. HttpGet basically gets the value of your URL query string. If you recall it, our query string is ReturnUrl and its value is %2F. The string parameter returnUrl gets the first value of the query string (which is %2F). The value being passed is now a forward slash (/) since it's not anymore encoded in the URL.


Next, we declared the Login model object passing it to model variable and inside, we assigned the model's ReturnUrl from the returnUrl parameter. We'll let our model know this value. Then lastly we return the value of the model object to our view. If you recall our view, we declared a namespace @model MyFirstWebsite.Models.LoginModel. This lets us know we have a model and in our case, we only passed in ReturnUrl and the rest of the values (email and password) are null. So in our view, if we did something like @Model.ReturnUrl, it will display the backslash (It shouldn't since its a hidden input).


Try typing in @Model.ReturnUrl in your Login view and remove the annotation [HiddenInput(DisplayValue = false)]. It should display the backslash but it should appear in a textbox as, by default, EditorForModel() converts strings as a textbox editor.


Make sure to bring the code back once you're done testing it.



6.2) Adding the HttpPost Login Method


Next, we'll create another method that's the same as Login but the difference is for the purpose of a HttpPost. Write this below your first Login method:


[code language="csharp"]


[HttpPost]
public ActionResult Login(LoginModel model)
{
&amp;nbsp; &amp;nbsp; return View(model);
}


[/code]


36


This doesn't do any logic yet but the purpose is just to create a placeholder method to have it prepared. This returns the model value coming from the input fields. Then again, they are represented by LoginModel so values are passed to that object. The thing that triggers the HttpPost is through clicking the submit button. The app already knows that a POST request will be submitted whet you have a submit button. Now let's put it into action and test whether clicking the submit button will get the value. In your Auth view, type in Model.Email and Model.Password having a <H1> tag.


37



Run the app and type in the email address "admin@admin.com" and password "123456" then click on submit. It should look like this, displaying your input:


38


Now that we know how to pass and display values, lets move on to adding credential validations but first, remove <h1>@Model.Email</h1> and <h1>@Model.Password</h1> as you don't need it anymore. We only demonstrated how it works.


6.3) Adding the Credential Validation


As a developer, the first thing that comes into your mind when you hear the word "validation" is an if-else statement. Of course, we need to compare whether the inputs are right or wrong. We'll create one inside our HttpPost Login Method. Add in the library using System.Security.Claims as we'll be using claims as our security.


39


In your Post Login Method, type in the following:


[code language="csharp"]
public ActionResult LogIn(LogInModel model)
{
if (!ModelState.IsValid) //Checks if input fields have the correct format
{
return View(model); //Returns the view with the input values so that the user doesn't have to retype again
}


//Checks whether the input is the same as those literals. Note: Never ever do this! This is just to demo the validation while we're not yet doing any database interaction
if (model.Email == "admin@admin.com" &amp;amp;&amp;amp; model.Password == "123456")
{
&amp;nbsp; &amp;nbsp; var identity = new ClaimsIdentity(&amp;nbsp;new[] {
&amp;nbsp; &amp;nbsp; new Claim(ClaimTypes.Name, "Xtian"),
&amp;nbsp; &amp;nbsp; new Claim(ClaimTypes.Email, "xtian@email.com"),
&amp;nbsp; &amp;nbsp; new Claim(ClaimTypes.Country, "Philippines")
}, "ApplicationCookie");


var ctx = Request.GetOwinContext();
var authManager = ctx.Authentication;
authManager.SignIn(identity);


return Redirect(GetRedirectUrl(model.ReturnUrl));
}


return View(model); //Should always be declared at the end of an action method
}


[/code]


40-1


Yup, there is an error stating that we have no GetRedirectUrl. We have not created that method yet so relax. We'll do that later so don't run the app yet. Now you might get agitated on the code. I know what's inside the if statement can be very confusing but I'll be explaining them one by one:



  • var identity = new ClaimsIdentity( List of new Claims(), string Authentication Type) - This part seems too long but to explain, we assigned the ClaimsIdentity object into a variable called identity. The first parameter is new Claims(). As mentioned there, you can place a list of claims. It is declared as an array object as defined from new [] { }. The last parameter should be what type of authentication. in our case its ApplicationCookie.

  • new Claim(Claim type, string claim value) - This is the specific type of claim inside the list. In claims, you declare one the first parameter what type of claims you want to have. This will be used as our cookies throughout our app. In our case, we used name, email, and country. Click here for the complete list of claim types you can use.


The following is now outside the if-statement of the validation:



  • var ctx = Request.GetOwinContext() - Here, we are passing the value to a variable called ctx. the Request object is a keyword that reads HTTP request values sent by the client. GetOwinContext() is a method that tells that we have to get the OWIN context in which links our middle ware to the request. This return null if a middleware doesn't exist.

  • var authManager = ctx.Authentication - Next, we declare a variable named authManager and assign it a value. ctx came from the variable we declared earlier. Authentication is an object property coming from GetOwinContext() that links our middleware to authentication to the app. For short, the 2 variables can be combined as Request.GetOwinContext().Authentication but distributing it makes it cleaner to read.

  • authManager.SignIn(identity) - authManager was that variable we declared earlier. SignIn is a method that gets the list of claims and uses to authenticate those values to be persisted throughout the app. The list of claims is the first parameter that was assigned to the variable identity which we declared earlier inside the if-statement.

  • return Redirect(string URL where you will be redirected) - Simply redirects you to the URL placed inside the method.


6.4) Displaying the Error Message and Adding URL Validation


Lastly, let's place our error message right before returning the view in case we don't get redirected by adding in ModelState.AddModelError("", "Invalid email or password");


41


Now that we've explained them, let's create our GetRedirectUrl method to finish the job. We'll be using this to validate our URL in case we placed the credentials correctly. Type the following code below the Login method:


[code language="csharp"]


private string GetRedirectUrl(string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
{
return Url.Action("index", "home");
}
return returnUrl;
}


[/code]


42



What we're doing is we are validating if the string is empty or not, if not then it will direct us to Home/Index route (rather our Home controller and Index Action). Run the app and with an email "admin@admin.com" and with the password "123456". You should now be redirected to this page:



43


You've noticed that the browser asks if you want to save your password. That's because it received a post request and cookies we're saved to the browser.



We're now on an authenticated page, let's display the persisted values together with the logout. Stop the application from this point.


7.) Displaying Persisted Values and Adding the Logout Logic


Let's modify our page and display a name and a logout tab.


7.1) Displaying Your Name


On our _Layout.cshtml master page, let's edit the Application Name into your name by replacing the "Application Name" into @User.Identity.Name and a simple if-statement to display something when not logged-in. Type in the following in that portion:


[code language="csharp"]


@if(@User.Identity.IsAuthenticated)
{
@Html.ActionLink("Hello " + @User.Identity.Name + "!", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
}
else
{
@Html.ActionLink("Login", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
}


[/code]



44


Run the app again and see how it looks like:


45



Even though we stopped the app and run it again, the session still exists. It's because the cookies still exist within the browser. The name was based on the Claims value we assigned earlier. Next, let's create our Logout button.


7.1) Displaying the Logout Button and Logic


From the _Layout.cshtml, add the following code within the navbar tag:


[code language="html"]


&amp;lt;div class="navbar-collapse collapse"&amp;gt;
&amp;lt;ul class="nav navbar-nav navbar-right"&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;a href="@Url.Action("Logout", "Auth")"&amp;gt;Logout&amp;lt;/a&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;


[/code]


46



The Action parameters are (action method, controller) wherein if we click it, we'll go to Logout action method and Auth controller. From our AuthController, let's add our Logout method:


[code language="csharp"]


public ActionResult Logout()
{
var ctx = Request.GetOwinContext();
var authManager = ctx.Authentication;


authManager.SignOut("ApplicationCookie");
return RedirectToAction("Login", "Auth");
}


[/code]


47



It is set to be redirected to Auth/Login page when logged out. Let's run the app again. Login and as you can see, you have the logout on the upper-right portion on the navbar.



48



Click on Logout and it should redirect you back to the Login form.


Tadaaaa! We're done with our Authentication and security. Next topic, we'll be dealing with data dynamically wherein we will use a database to store and display data. We will modify the code we did. what we'll be doing is a list app when the user is logged in.



8.) Creating the Database using LocalDb


We'll be using the lightweight LocalDb to keep things simple. Although in .NET apps, it's common to connect through MS SQL Server and manipulate the databases from there. In this case, we will be using the built-in LocalDb to keep things simple and straightforward.


From your Solution Explorer, right-click the App_Data folder then Add > SQL Server Database...


49



A window will appear, name your database as MyDatabase and it should appear like this:


50


*Issuance Checkpoint*


In case you've been going through errors in creating the database, we'll debug it here and I'll state some possible solutions. However, if you were able to create the database flawlessly, you can skip this part.


1.) If you cannot create a SQL Server Local Database, download the 2012 (ver. 11) here or 2014(ver. 12) here (pick LocalDB 32BIT\SqlLocalDB.msi for 32bit or LocalDB 32BIT\SqlLocalDB.msi for 64bit).


2.) If you encountered this error after you're done entering the Database name:


"A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 50 – Local Database Runtime error occurred. Cannot create an automatic instance. See the Windows Application event log for error details"


It means you need to manually create and start your LocalDb instance. To do that, you'll first need to have LocalDb for SQL Server installed (It's all stated above and get both to make sure we won't be encountering issues). Once your done installing, open your cmd and type the following:



  1. sqllocaldb create "v12.0" - Create the instance for Local Db on SQL Server 2014

  2. sqllocaldb start "v12.0" - Start the instance for Local Db on SQL Server 2014

  3. sqllocaldb.exe create v11.0 - Create the instance for Local Db on SQL Server 2012

  4. sqllocaldb.exe start v11.0 - Start the instance for Local Db on SQL Server 2012


The version number stands for the Local Db instance.


51


After this, I hope this solves your issue. Try creating your database again and it should work now.


*Issuance Checkpoint Ends Here*



8.1) Connecting the Database to the App through Connection Strings


Now that we have the database, we should let the app know we created it. Open up your Web.config and insert the following tag below the <appSettings>:


[code language="csharp"]


&amp;lt;connectionStrings&amp;gt;
&amp;lt;add name="DefaultConnection" connectionString="Data Source=(LocalDB)\v11.0;&amp;nbsp;AttachDbFilename=|DataDirectory|\MyDatabase.mdf;Integrated Security=True"&amp;nbsp;providerName="System.Data.SqlClient" /&amp;gt;
&amp;lt;/connectionStrings&amp;gt;


[/code]


90-3



Let me explain the tag and its attributes:



  • connectingStrings - This is where you establish connections from your database to the app. It contains a name under the <add> tag.

  • name - The name of the database context. In our case it's DefaultConnection and we'll use this name later in our app.

  • connectionString - the property that tells where the database source is located. don't get this confused from the upper tag as this is an attribute from the name. Inside it has 3 more attributes:

    • Data Source - This is the server name. In our case since we're using a LocalDb which is only saved within Visual Studio, its (LocalDb)\\v11.0 and v11.0 means were using SQL Server 2012 LocalDb.

    • AttachDbFileName - This is where you'll indicate the directory if your database file(.mdf). |DataDirectory| stands for the solution's directory and beside it is the database name (in our case MyDatabase.mdf).

    • Integrated Security - If set to true, we'll be using Windows Authentication mode(which is you'll be using your windows account). If false, you'll be required to place in 2 attributes which are UserId and Password. We set ours to true so as to not complicate the process.



  • provideName - We'll place here the Data Provider for SQL Server which we'll use for data storage. By default, it's System.Data.SqlClient to which is a .NET library for SQL Server.


Now that we have our database linked into the app. Let's now create our database tables.



8.2) Creating the Database Tables


We'll create 2 tables. One for the users and one for the list. Double-click on MyDatabase.mdf (located on App_Data folder) and it should open the Server Explorer on the left. From there, drop down the menu on the database until you see the Tables folder. Right-click it and Add New Table.


53


*Issuance Checkpoint*


If you cannot see the tables option from the dropdown, it means you don't have SQL Server Database Toolings for 2013 installed. Click here to get it. After installing, restart your Visual Studio, and Add New Table option should appear.


*Issuance Checkpoint Ends Here*


A designer view should appear and on the T-SQL portion, type this following code:


[code language="sql"]


CREATE TABLE [dbo].[Users]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (0,1),
[Email] NVARCHAR(50) NOT NULL,
[Password] NVARCHAR(100) NOT NULL,
[Name] nvarchar(100) NOT NULL,
[Country] nvarchar (50) NOT NULL
)


[/code]


54-2



Note that the table name is based on the schema name on the right inside the brackets []. We created 5 columns with their corresponding data types. IDENTITY (0,1) beside the primary key on ID means that its set to auto-increment. For each value created, the ID will chronologically increment by one. Note that it is possible to configure your columns through the designer portion but I placed the T-SQL code to ensure that you can follow. Click on the Update button located on the upper-left portion.


Then a Preview Database Updates windows will appear. Click on Update Database button below (the middle button) then your tables have been created.



You can double-check if the tables have been created by refreshing the database on the Server Explorer. Right-click the database and click on refresh. You can see the table in the Tables folder.


55


Next, we'll create another table named List. Repeat the process on how you created the Users table and refer to the T-SQL code below:


[code language="sql"]


CREATE TABLE [dbo].[List]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (0,1),
[Details] NVARCHAR(100) NOT NULL,
[Date_Posted] NVARCHAR(30) NOT NULL,
[Time_Posted] nvarchar(50) NOT NULL,
[Date_Edited] NVARCHAR(30) NOT NULL,
[Time_Edited] nvarchar(50) NOT NULL,
[public] NVARCHAR(5) NOT NULL


)


[/code]


56



By now, you should have 2 tables. Refresh again your database from the Server Explorer then make sure to have those 2 tables within the folder:



57


Next step, We'll use the Entity Framework to use queries and use for data manipulation from the database to UI.



9.) Linking the Database Through Entity Framework



Let's install Entity Framework in our App. Right-click on your solution (MyFirstWebsite) on the Solution Explorer then click on Manage NuGet Packages... This is pretty similar to what you did when you got the Owin Libraries. On the search bar, type in EntityFramework and install.



58



9.1) Creating the Context and Renaming the LoginModel


Once done, let's create a class within the solution named MainDbContext



59


The next thing is we'll rename our LoginModel into Users. The reason is that the class name should have the same name as the table name to let the app know its representation. When you rename, there will be a Red underline indicating that its name has changed:


rev1



Put your cursor there and select Rename 'LoginModel' to 'Users' on the dropdown (First option).



This will rename all everything linked to that into the same name although there is one limitation. It didn't rename the reference from Login.cshtml. If you recall, we've referenced our model there. Note that we only renamed that class, NOT the file name itself. Make sure to rename the file as well so you wouldn't get confused. Right-click on it and choose Rename. Rename it as Users.cs


rev2



Let's go there and change its reference to @model MyFirstWebsite.Models.Users together with the code. We'll replace EditorForModel() with the following:


[code language="html"]


@model MyFirstWebsite.Models.Users
@{
ViewBag.Title = "Login";
}


&amp;lt;h2&amp;gt;Log In&amp;lt;/h2&amp;gt;


@Html.ValidationSummary(true)


@using (Html.BeginForm())
{
@Html.LabelFor(u =&amp;gt; u.Email)&amp;lt;br/&amp;gt;
@Html.TextBoxFor(u =&amp;gt; u.Email)&amp;lt;br/&amp;gt;
@Html.LabelFor(u =&amp;gt; u.Password)&amp;lt;br/&amp;gt;
@Html.PasswordFor(u =&amp;gt; u.Password)&amp;lt;br/&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;button type="submit"&amp;gt;Log In&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;


}


[/code]


70-3



We made the type that specific because we are going to add more fields in the model. On this page, we only needed 2 fields which are Email and Password. We will be using the same model for user registration later on. We'll also add in fields that are necessary for the database. Don't worry, this doesn't change the UI. Let's modify again our Users and add Name and Country with our fields with the following code:


[code language="csharp"]


public class Users
{
[Key]
public int Id { get; set; }


[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }


[Required]
[DataType(DataType.Password)]
public string Password { get; set; }


public string Name { get; set; }


public string Country { get; set; }


}


[/code]


rev4



As you'll notice, we've followed the database columns within our class. We deleted our ReturnUrl since it's not needed anymore. We'll be using it for our Entity Framework Later.


Going back to our MainDbContext.cs, let's add the libraries System.Data.Entity for our DbContext and MyFirstWebsite.Models to load up our model. Type the following on the class:


[code language="csharp"]


public class MainDbContext : DbContext
{
public MainDbContext()
: base("name=DefaultConnection")
{
}


public DbSet&amp;lt;Users&amp;gt; Users { get; set; }
}


[/code]


rev5


To explain the code:



  • base(<name of connection string here>) - This is where we link our database. The string inside is the name of the connection string. In our case its DefaultConnection. This might enlighten you:


65




  • DbContext - A class we inherited for MainDbContext to load the framework.

  • DbSet<Model> - This tells that this is a table representation and it the model name should be the same as the Table name in the database.


9.2) Cleaning our AuthController Redirection


Next, let's clean out AuthController by removing the GetDirectUrl method and replace it with the following:


return RedirectToAction("Index","Home");



66


Oh and don't forget to remove this too as it's not needed anymore:


70-2



This is simpler and easier. The method was only to show you how we pass values and use the URL we have to redirect.



10.) Creating the Registration Page


Next up is an interesting part. We'll create the registration page where we can register more users for the page. First off, create a new action method named Registration inside your AuthController then together create a view for it. The same thing as others leaving the view settings as is then adding it. You should have the following:


67


AuthController.cs



68


Registration.cshtml



10.1) Creating the Registration Action and View Page


Inside Registration.cshtml, type the following:


[code language="html"]


@model MyFirstWebsite.Models.Users
@{
ViewBag.Title = "Registration";
}


&amp;lt;h2&amp;gt;Registration&amp;lt;/h2&amp;gt;


@using (Html.BeginForm())
{
@Html.LabelFor(u =&amp;gt; u.Email)&amp;lt;br /&amp;gt;
@Html.TextBoxFor(u =&amp;gt; u.Email)&amp;lt;br /&amp;gt;
@Html.LabelFor(u =&amp;gt; u.Password)&amp;lt;br /&amp;gt;
@Html.PasswordFor(u =&amp;gt; u.Password)&amp;lt;br /&amp;gt;
@Html.LabelFor(u =&amp;gt; u.Name)&amp;lt;br /&amp;gt;
@Html.TextBoxFor(u =&amp;gt; u.Name)&amp;lt;br /&amp;gt;
@Html.LabelFor(u =&amp;gt; u.Country)&amp;lt;br /&amp;gt;
@Html.TextBoxFor(u =&amp;gt; u.Country)&amp;lt;br /&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;button type="submit"&amp;gt;Register&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;
}


[/code]


70-6


It's just basically the same as Login.cshtml. It would be easier if you'll just copy-paste it although there are some slight changes if you'll notice. It's just the same information but added the name and the country.



10.2) Adding Data Encryption and Decryption


We'll place in the code wherein we can add data based on users' inputs. We'll add another Registration Action but this time for and HttpPost. Type the following code:


[code language="csharp"]
[HttpPost]
public ActionResult Registration(Users model)
{
if(ModelState.IsValid)
{
using(var db = new MainDbContext())
{


}
}
return View();
}
[/code]


71


We've loaded up our MainDbContext inside the using so that we can dispose of them at the end of the block. We need to dispose of them so that our database is ensured to be safe. It's inside an if-statement wherein all models should have the correct format before it proceeds.


Next, we'll create our own encryption library. From your solution, create a new folder (right-click MyFirstWebsite Add > New Folder) named CustomLibraries then inside it, create 2 new classes named CustomEncrypt and CustomDecrypt.


72


On CustomEncrypt.cs, add the following code:


[code language="csharp"]


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;


namespace MyFirstWebsite.CustomLibraries
{
public class CustomEnrypt
{
public static string Encrypt(string clearText)
{
string EncryptionKey = "MAKV2SPBNI99212";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
}
}


[/code]


73



What we've done is we created our Encryption class. I don't need to explain it to bits as its function is to encrypt the string. This will be used for our password. Next, let's do the decryption by typing in the following on our CustomDecrypt.cs:


[code language="csharp"]


using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;


namespace MyFirstWebsite.CustomLibraries
{
public class CustomDecrypt
{
public static string Decrypt(string cipherText)
{
string EncryptionKey = "MAKV2SPBNI99212";
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}
}


[/code]


99-1
Now that we have the encrypt and decrypt functions ready, let's make our registration active and ready. Let's go back to AuthController and modify our Registration action for HttpPost.


10.3) Creating the Query Logic


Add the reference using MyFirstWebsite.CustomLibraries so that the file knows we have a reference to our Custom libraries:


76


After, add the following code:


[code language="csharp"]


[HttpPost]
public ActionResult Registration(Users model)
{
if (ModelState.IsValid)
{
using (var db = new MainDbContext())
{
var encryptedPassword = CustomEnrypt.Encrypt(model.Password);
var user = db.Users.Create();
user.Email = model.Email;
user.Password = encryptedPassword;
user.Country = model.Country;
user.Name = model.Name;
db.Users.Add(user);
db.SaveChanges();
}
}
else
{
ModelState.AddModelError("", "One or more fields have been");
}
return View();
}


[/code]


75


Here's the explanation to the code:



  • var encryptedPassword = CustomEnrypt.Encrypt(model.Password); - We're encrypting our password using our library we created earlier assigning it to the variable encryptedPassword.

  • var user = db.Users.Create() - We're creating the Users table within the codebase so we can modify it.

  • db.Users.Add(user) - Adds the users' object wherein its values were based on what we assigned from the model.

  • db.SaveChanges() - Saves the changes.


We'll modify our navigation bar so we can navigate it through the page. On our _Layout.cshtml page, add the following code:


[code language="html"]
&amp;lt;li&amp;gt;
&amp;lt;a href="@Url.Action("Registration", "Auth")"&amp;gt;Register&amp;lt;/a&amp;gt;
&amp;lt;/li&amp;gt;
[/code]


77-1



We just basically added a hyperlink for the registration page. Now run the app, go to Auth/Registration then input some data. In my case, I'm adding the following data:


Email - admin@admin.com


Password - adminadmin


Name - Xtian


Country - Philippines



78


Click on register and it should now register. To check for the data, to your server explorer, right-click on your database (the one named DefaultConnection) and on your tables, right-click Users table and show table data:


79



It should look like this:


80



10.4) Editing the Login Logic


Now that we have our code work dynamically with the database, we'll modify our Login logic so that we'll be using the database data instead of the hard-coded data earlier. On your Login action on AuthController.cs, Add on top of the if-statement using(var db = new MainDbContext()) encapsulating up to the redirect method.


99


Next we'll add in the query logic together replacing the claims value. Make sure to have the library using MyFirstWebsite.CustomLibraries; on top for our decryption code and add with the following code:


[code language="csharp"]


var emailCheck = db.Users.FirstOrDefault(u =&amp;gt; u.Email == model.Email);
var getPassword = db.Users.Where(u =&amp;gt; u.Email == model.Email).Select(u =&amp;gt; u.Password);
var materializePassword = getPassword.ToList();
var password = materializePassword[0];
var decryptedPassword = CustomDecrypt.Decrypt(password);


if (model.Email != null &amp;amp;&amp;amp; model.Password == decryptedPassword)


[/code]


99-4
Here's the explanation to the code:



  • var emailCheck = db.Users.FirstOrDefault(u => u.Email == model.Email); - This checks if the user has the same email as from the one in the database. This returns null as FirstOrDefault returns null if the following condition isn't met.

  • var getPassword = db.Users.Where(u => u.Email == model.Email).Select(u => u.Password); - Gets the password through LINQ query. If your familiar with SQL, its the same as "SELECT Password from Users WHERE Email == model.Email".

  • var materializePassword = getPassword.ToList(); - Materializes the query into a readable list of array objects

  • var password = materializePassword[0]; - Since the query will only result to one result, we only have one array of result.

  • var decryptedPassword = CustomDecrypt.Decrypt(password); - Decrypts the password using our custom library.


This portion now verifies your email and password. Next, we'll then modify your claim type values by placing in another query and replacing them with the following code:


[code language="csharp"]


var getName = db.Users.Where(u =&amp;gt; u.Email == model.Email).Select(u =&amp;gt; u.Name);
var materializeName = getName.ToList();
var name = materializeName[0];


var getCountry = db.Users.Where(u =&amp;gt; u.Email == model.Email).Select(u =&amp;gt; u.Country);
var materializeCountry = getCountry.ToList();
var country = materializeCountry[0];


var getEmail = db.Users.Where(u =&amp;gt; u.Email == model.Email).Select(u =&amp;gt; u.Email);
var materializeEmail = getEmail.ToList();
var email = materializeEmail[0];


var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.Email, email),
new Claim(ClaimTypes.Country, country)


[/code]


99-3


Login with the data you used when you registered then type we'll create our List inside the authenticated page.


11.) Create the List Table


We'll modify the UI of our Home Page on Home/Index.


11.1) Creating the UI for Tables


On your Index.cshtml, copy-paste the following code


[code language="html"]


@{
ViewBag.Title = "Index";
var username = User.Identity.Name;
}


&amp;lt;h2&amp;gt;@username's List&amp;lt;/h2&amp;gt;


&amp;lt;table class="table table-bordered table-condensed"&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Id&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Details&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Posted&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Edited&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Edit&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Delete&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Public Post&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;a href="@Url.Action("Edit","Home")"&amp;gt;Edit&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;a href="@Url.Action("Delete","Home")"&amp;gt;Delete&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;


[/code]


113-1
I guess there's no need for me to print screen everything as this will give you an idea.


What we've done is we placed our tables on the client-side and two hyperlinks, one for edit and one for delete.


Next, we'll create our model for the List so we can add items to the database.



11.2) Creating the List Model and Linking it to the Database


On your Models folder, create a new class and name it List.cs then after, add the following code inside it:


[code language="csharp"]


using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;


namespace MyFirstWebsite.Models
{
public class List
{
[Key]
public int Id { get; set; }
[Required]
public string Details { get; set; }


public string Date_Posted { get; set; }
public string Time_Posted { get; set; }
public string Date_Edited { get; set; }
public string Time_Edited { get; set; }
public string Public { get; set; }
}
}


[/code]


82-1


Same as above. The screenshot of the code is not complete but this should give you an idea.


Those properties are from the same as the List tables from the database. Next, let's link this model so that we can use it for our Entity Framework.


On your MainDbContext.cs, add public DbSet<List> List { get; set; } below the Users DbSet.


83


Now we can use the List object for queries. Since we have that capability, let's add an input field above the table so we can add our inputs to the database.


Back to our Home.cshtml, add the reference @model MyFirstWebsite.Models.List on top of the code and the following code above the <table> tag:


[code language="html"]


@using (Html.BeginForm())
{
&amp;lt;span&amp;gt;Enter new item: &amp;lt;/span&amp;gt;
@Html.TextBoxFor(u =&amp;gt; u.Details)&amp;lt;br /&amp;gt;
&amp;lt;span&amp;gt;Public post? &amp;lt;/span&amp;gt;&amp;lt;input type="checkbox" name="check_public" /&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;input type="submit" value="Add Item"/&amp;gt;
}
&amp;lt;br /&amp;gt;


[/code]


84-1
Your page should now look like this:



85-1


You might get surprised why aren't we using our strongly-typed models for the public post? The reason is CheckboxFor needs to have a bool type. In our case, Our public field is a string so its not compatible. Instead, we are using the name in the input box wherein check_public is assigned to it. Later I'll show how to get data using from that implementation.


*Checkpoint*


Have you been asking yourself that if you are logged in, you would see your own personal list but when you log-out and another person logs in, a different list would show up? Apparently this is the case of each user having their own personal list.


The relationship between the user and the list is one-to-one as a user can only have one list. From here, we need to compare something on the tables to know which row is his/her. The thing that we should compare is the ID as its unique and should never produce duplicate results.


In order to do this type of implementation, we'll be needing to modify our List Table together with our List model. Let's go to our Server Explorer and under MyDatabase.mdf, right-click the Tables folder then Open Table Definition.


It should open up the designer's view of the table. on the T-SQL portion, add the following code to add the column User_Id and we'll also make our Date_Posted, Time_Posted, Date_Edited, and Time_Edited into a nullable field since we're not requiring it:


[code language="sql"]
[Date_Posted] NVARCHAR (30) NULL,
[Time_Posted] NVARCHAR (50) NULL,
[Date_Edited] NVARCHAR (30) NULL,
[Time_Edited] NVARCHAR (50) NULL,
[User_Id] &amp;nbsp; &amp;nbsp; INT &amp;nbsp; NOT NULL,
[/code]


Make sure to add it below public and add a comma at the end of the line.


96

After, click Update (located on the top-left) then Update Database. Note that if there was a warning stating that you need a default value, just ignore it and continue to update the database.



On your List model (List.cs), add up the User_Id too with public int User_Id { get; set; }


88



Now that we're done, we are set to do the logic for adding.



12.) Adding Items to our List


On our Home Controller, add up the reference using MyFirstWebsite.Models so we can use our model object then create a new Index action for HttpPost with the following code:


[code language="csharp"]


[HttpPost]
public ActionResult Index(List list)
{
if (ModelState.IsValid)
{
using (var db = new MainDbContext())
{
}
}
else
{
ModelState.AddModelError("", "Incorrect format has been placed");
}
return View();
}


[/code]


89


Basically we placed a placeholder for model validation and loaded up the database object inside it together with the error message in case the user had the wrong format. Now on top of the database context, add the following code:


[code language="csharp"]


string timeToday = DateTime.Now.ToString("h:mm:ss tt");
string dateToday = DateTime.Now.ToString("M/dd/yyyy");


[/code]


This will be used for our date and time posted. Add the library using System.Security.Claims since we will be using claims again and following code inside the database context:


[code language="csharp"]


using (var db = new MainDbContext())
{
Claim sessionEmail = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
string userEmail = sessionEmail.Value;
var userIdQuery = db.Users.Where(u =&amp;gt; u.Email == userEmail).Select(u =&amp;gt; u.Id);
var userId = userIdQuery.ToList();


var dbList = db.List.Create();
dbList.Details = list.Details;
dbList.Date_Posted = dateToday;
dbList.Time_Posted = timeToday;
dbList.User_Id = userId[0];
if (check_public != null) { dbList.Public = "YES"; }
else { dbList.Public = "NO"; }
db.List.Add(dbList);
db.SaveChanges();
}


[/code]




Here's the explanation to the code:



  • Claim sessionEmail = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email); - Gets the Email ClaimType and assigned it to the variable sessionEmail. This is in a URL format os its not yet the value that we're looking for. This was taken from AuthController, the part where we did our login module. Still recall that?

  • string userEmail = sessionEmail.Value; - Gets the real value of the claim, which now is the email address assigned to our variable userEmail.

  • var userIdQuery = db.Users.Where(u => u.Email == userEmail).Select(u => u.Id); - This is our LINQ query. LINQ is the query language for .NET frameworks. The value we're getting here is not yet the real value as this always returns as a list. If you're familiar with SQL, this query is equivalent to "SELECT Id FROM Users Where Email = userEmail".

  • var userId = userIdQuery.ToList(); - Materializes the query and converts it into an array of strings.

  • userId[0]; - We should only have one result here as email addresses shouldn't have duplicate data. Since userId is an array of strings, we then have a hard-coded value with an index of 0 which denotes the first value of the query.

  • The if statement checks whether we checked the checkbox or not the assigns the value YES or NO. The name came from the textbox name which we defined as check_public if you still recall.


Now let's run the app and let's try adding some data.



*ISSUANCE CHECKPOINT*


Most likely you will encounter the error:


Model backing a MainDbContext has changed; Consider Code First Migrations


That's because it relates to the other database you've seen earlier. Since everything is connected to the model, we added a new model called List and the other database (the migrated one) doesn't have it. In order to solve this problem, we need to reinitialize the database.


Now for the technical part, go to your Global.asax and add the library using System.Data.Entity and the following line of code:


[code language="csharp"]


Database.SetInitializer&amp;lt;MainDbContext&amp;gt;(null);


[/code]


91


Try running the app again and ONLY ONCE! It should reinitialize the DB again though take note that your information from the Users table will be gone! I suggest go to the registration page and register again your credentials (Refer again to section 10.4). Don't worry, we will only be doing this once as the List could be the last table (or model change rather) for this tutorial.


*ISSUANCE CHECKPOINT ENDS HERE*


I'll try input the following on the details:


Item: Salmon


Public post: Yes



92-1


*ISSUANCE CHECKPOINT*


Most likely you'll encounter an error on db.SaveChanges() saying that dbo.Lists don't exist. If that happens, we'll simply rename the List into Lists (Yes we added letter s) in every part we have them so that we don't confuse the compiler. It got confused because List is a reserved word for giving out a list of objects. Rename the following files:


List.cs model:


93



Your MainDbContext.cs




94



Index.cshtml on HomeController:


95



And lastly the database table itself (from the Server Explorer)


98


Try running the app again and add the Salmon with public data. It should now work.


*ISSUANCE CHECKPOINT ENDS HERE*


I'll add the data twice so that we can have 2 items. We can check our database data and it should now appear on the tables:


100



13.) Displaying the Items to the List


Now that we successfully had our data in the database, we'll display them in our UI. Let's go back to our HomeController and edit our first Index action. Add the following code:


[code language="csharp"]


var db = new MainDbContext();
return View(db.Lists.ToList());


[/code]


101


What this does is we're returning all data from the Lists table. In SQL, its similar to "SELECT * FROM Lists". Next, we'll modify our Index.cshtml. Let's replace 2 lines. One is our model reference we'll make it to @model IEnumerable<MyFirstWebsite.Models.Lists> instead of @model MyFirstWebsite.Models.Lists so that it can receive the object returning from the controller. Another is we'll replace the strongly typed input box into a regular HTML tag which is <input type="text" name="new_item"/> since our page can't be strongly typed due to converting our reference into an IEnumerable (a specific list for short).


102


Now that we've modified our text box for the details, we'll also modify our home controller add the following code on the given portion:


[code language="csharp"]


string new_item = Request.Form["new_item"];


dbList.Details = new_item;


[/code]


103


Going back to Index.cshtml, add the following code inside the <tbody> tag:


[code language="html"]


@foreach(var item in Model)
{
&amp;lt;tr&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Id)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Details)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Time_Posted)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Time_Edited)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;a href="@Url.Action("Edit","Home")/@Html.DisplayFor(modelItem =&amp;gt; item.Id)"&amp;gt;Edit&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;a href="@Url.Action("Delete","Home")/@Html.DisplayFor(modelItem =&amp;gt; item.Id)"&amp;gt;Delete&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Public)&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
}


[/code]


101-1
We've added a foreach to loop each row on the database. the Model in it is the object coming from the IEnumerable returned as a list then the item is the variable assigned to it. Below it embeds the columns. Next, we'll edit our Lists model (List.cs) and remove the [Required] annotation from Details to avoid having a wrong valid ModelState:


106


Lastly, let's modify our return View in the HttpPost of the Index action and do the following:


[code language="csharp"]


var listTable = new MainDbContext();
return View(listTable.Lists.ToList());


[/code]


107


This will prevent us from returning null in our Index.cshtml during the loop


Now run the app and it should display the item. I'll add Tuna and Fish as a non-public post to have another more items.



Now that we can add and display items, next is Editing them.



14.) Editing the Items


Try hovering the Edit link on the right and you'll see an ID:


108


It means we're passing data through URL strings. It's a sign that we should use an HttpGet. Let's modify our HomeController and add an action result named Edit for both HttpGet and HttpPost:


[code language="csharp"]


[HttpGet]
public ActionResult Edit(int id)
{
return View();
}
[HttpPost]
public ActionResult Edit(Lists list)
{
return View();
}


[/code]


109


The id parameter gets the number from the URL you've seen earlier in the pic.


14.) Adding the Edit View


Next, create a view for the HttpGet, leave the settings as-is. Here's the entire code:


[code language="html"]


@model MyFirstWebsite.Models.Lists
@{
ViewBag.Title = "Edit";
var username = User.Identity.Name;
}


&amp;lt;h2&amp;gt;Edit Details&amp;lt;/h2&amp;gt;
&amp;lt;a href="@Url.Action("Index","Home")"&amp;gt;Click here to go back&amp;lt;/a&amp;gt;
@using (Html.BeginForm())
{
&amp;lt;span&amp;gt;Enter new item: &amp;lt;/span&amp;gt;
&amp;lt;input type="text" name="new_item" /&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;span&amp;gt;Public post? &amp;lt;/span&amp;gt;&amp;lt;input type="checkbox" name="check_public" /&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;input type="submit" value="Add Item" /&amp;gt;
}
&amp;lt;br /&amp;gt;


&amp;lt;table class="table table-bordered table-condensed"&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Id&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Details&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Posted&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Edited&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Public Post&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Model.Id&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Model.Details&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Model.Time_Posted&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Model.Date_Posted&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Model.Public&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;


[/code]


113-2
Only part of it at least to give you an idea


If you'll notice, we did not use any IEnumerable as our reference as we're not returning a lot of items and we're not using the foreach for the same reason. Let's add the following codes on top:


[code language="csharp"]


public static string date_posted = "";
public static string time_posted = "";


[/code]


We'll be needing this later when we persist our time and date posted.


Let's modify our HttpGet action for Edit and add the following code:


[code language="csharp"]


var db = new MainDbContext();
var model = new Lists();
model = db.Lists.Find(id);
date_posted = model.Date_Posted;
time_posted = model.Time_Posted;
return View(model);


[/code]



115-2


The code is pretty simple. We opened our db, declared the list object, and passed values based on what was found. The Find() method accepts an integer which serves as the primary key of the table to search for the result.


Now run the app and you should have this page:


113-3



We have a hyperlink below to redirect us back to our home page if we changed our mind. Now for the fun part, lets go to our Edit action method for HttpPost and add the reference using System.Data.Entity. On the code, add the following:


[code language="csharp"]


var db = new MainDbContext();
string timeToday = DateTime.Now.ToString("h:mm:ss tt");
string dateToday = DateTime.Now.ToString("M/dd/yyyy");
string new_item = Request.Form["new_item"];
string check_public = Request.Form["check_public"];


if (ModelState.IsValid)
{
list.Time_Edited = timeToday;
list.Date_Edited = dateToday;
list.Details = new_item;
list.Time_Posted = time_posted;
list.Date_Posted = date_posted;
if (check_public != null) { list.Public = "YES"; }
else { list.Public = "NO"; }


db.Entry(list).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(list);


[/code]


115-4



I'll input Cowfish as a non-public post then add. It should now display on your home together with the time and date edited:


114


Congratulations! We can now edit our list! Now off to the deleting feature.


14.) Deleting Items from the List



Next, we'll delete the row from our list. We'll create a new action named Delete. We'll only need one as we'll don't need another page for confirmation but instead, we'll make a confirmation box to make things faster and cleaner. On your HomeController, add one the following code:


[code language="csharp"]
[HttpGet]
public ActionResult Delete(int id)
{
return RedirectToAction("Index");
}
[/code]


116
We'll put that as a placeholder for now. It accepts a query string for ID and returns back to our Index action.


Next we'll add a confirmation prompt if the user wants to confirm the delete action. To do this, we need to edit our delete link. Go to your Home Index.cshtml, Replace it with the following:


[code language="html"]


&amp;lt;td style="text-align: center;"&amp;gt;&amp;lt;a class="pointer-arrow" onclick="deleteRow(@Html.DisplayFor(modelItem =&amp;gt; item.Id))"&amp;gt;Delete&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;


[/code]


We removed the Url.Action as we'll need to pass on the date to the deleteRow() function from the javascript wherein if the users clicks the row, we'll pass the Id specifically on the given row.


Next, add the following code below the file table:


[code language="html"]


&amp;lt;script&amp;gt;
function deleteRow(id)
{
var r = confirm("Are you sure you want to delete this record?");
if(r == true)
{
window.location.assign("/Home/Delete/" + id);
}
}
&amp;lt;/script&amp;gt;
&amp;lt;style type="text/css"&amp;gt;
.pointer-arrow:hover {
cursor: pointer;
}
&amp;lt;/style&amp;gt;


[/code]



117-2


Note: I didn't create a separate JS/CSS file for those as I'm only demonstrating how it works. No need to make it complicated for now.


For the code, we created a confirm box wherein if its true, it will go to Home/Delete/{id} otherwise cancels the delete operation. The purpose is the style is when the user places the cursor on the Delete link, the cursor will change into a pointing finger. We need that because that property was lost as the attribute href was gone so we need to set it manually.



Now run the program then click delete on any row. It should display the alert box with 2 choices:


In this case, I've clicked the second row


118


Next we'll add in the delete logic. Let's go back to our Delete Action and add the following code:


[code language="csharp"]


[HttpGet]
public ActionResult Delete(int id)
{
var db = new MainDbContext();
var model = db.Lists.Find(id);


if (model == null)
{
return HttpNotFound();
}


db.Lists.Remove(model);
db.SaveChanges();
return RedirectToAction("Index");
}


[/code]


119


Pretty much the same as Edit's but the only difference is using the Remove() method wherein we remove the data based on the Key Id. Another is an if-statement wherein it returns an error message if the row has been deleted. Now let's try deleting the second row then it should get deleted.


In this case, I'll delete 2 data's which are Salmon with the Id of 2 and Tuna with the Id of 3. It should now delete. It shouldn't display now.


120


Congratulations! We're now done on the delete feature! Next, we're off to our last feature, displaying public posts when the user is logged out.


14.) Displaying Public Data


Let's add some more data. I'll add the following:



  • Tuna - Public

  • Shark - Public

  • Whale - Non-Public

  • Goldfish - Public



121


Logout from the system. From our AuthController, we'll create a new action named Index for HttpGet and place it on top with the following code:


[code language="csharp"]


[HttpGet]
public ActionResult Index()
{
var db = new MainDbContext();
return View(db.Lists.Where(x =&amp;gt; x.Public == "YES").ToList());
}


[/code]


122
Create a view for it then add the following code (Index.cshtml for Auth):


[code language="html"]


@model List&amp;lt;MyFirstWebsite.Models.Lists&amp;gt;
@{
ViewBag.Title = "Index";
}


&amp;lt;h2&amp;gt;Public List&amp;lt;/h2&amp;gt;


&amp;lt;p&amp;gt;@Html.ActionLink("Click here to Login","Login")&amp;lt;/p&amp;gt;


&amp;lt;table class="table table-bordered table-condensed"&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Id&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Details&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Posted&amp;lt;/th&amp;gt;
&amp;lt;th style="text-align: center;"&amp;gt;Time - Date Edited&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
@foreach (var item in Model)
{
&amp;lt;tr&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Id)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Details)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Time_Posted) - @Html.DisplayFor(modelItem =&amp;gt; item.Date_Posted)&amp;lt;/td&amp;gt;
&amp;lt;td style="text-align: center;"&amp;gt;@Html.DisplayFor(modelItem =&amp;gt; item.Time_Edited) - @Html.DisplayFor(modelItem =&amp;gt; item.Date_Edited)&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
}
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;


[/code]


123-2



This displays the list of public rows. For the finishing touches, add <p>@Html.ActionLink("Click here to view the public list", "Index")</p> on to your Login view so that you can navigate through the public list.


124


Now run the app and go to Auth/Index. It should now display the public data we've set earlier.


125


Congratulations! We are now done with the tutorials! Now we can use the app but we still need to clean up some messy parts. I'll show you some loopholes that we got and we'll clean them.



17.) Cleaning the Code


We have two loopholes to clean. One is we still have the Logout displaying on our header even though we've logged-out and two, we have to make some validations whenever registering our user so that only one unique user can exist in the table.


126


Go to your _Layout.cshtml and modify replace the logout portion with the following code:


[code language="html"]


@if(User.Identity.IsAuthenticated)
{
&amp;lt;li&amp;gt;
&amp;lt;a href="@Url.Action("Logout", "Auth")"&amp;gt;Logout&amp;lt;/a&amp;gt;
&amp;lt;/li&amp;gt;
}


[/code]


127


Lastly, go to your AuthController. Go to your Registration action for HttpPost and replace with the following:


[code language="csharp"]


var queryUser = db.Users.FirstOrDefault(u =&amp;gt; u.Email == model.Email);
if(queryUser == null)
{
var encryptedPassword = CustomEnrypt.Encrypt(model.Password);
var user = db.Users.Create();
user.Email = model.Email;
user.Password = encryptedPassword;
user.Country = model.Country;
user.Name = model.Name;
db.Users.Add(user);
db.SaveChanges();
}
else
{
return RedirectToAction("Registration");
}


[/code]


128


FirstOrDefault() returns a null if the conditions are not met. We did this so we can check if the user already exists in the database. Otherwise, it will continue with the registration.


Now run the app and the Logout on top should be gone and when we register an existing user, it should redirect you back to the registration page.



18.) Debriefing and Summary


In the end, you should have this file structure.


129


I guess I don't need to picture out every file. As promised, I'll be giving you the complete files in case you get lost or if you need references during/after development. Click here as its uploaded at my GitHub (Follow me too!). Check out my PHP Tutorial too! Follow me as well on Instagram and on Twitter and tweet me your feedbacks and experiences :D


Credits to Ben Fosters blog for giving enlightenment on Identity, MSDN blogs for specific explanations and Stack overflow for explaining things in a nutshell.


Thanks and hope this helps you with your projects. Happy Programming!

Suggested Posts
Microsoft Exam 70-480 Certification Tips
Microsoft Exam 70-480 Certification Tips

Sharing my tips from my experience when taking Microsoft Exam 70-480.

PHP Tutorials for Beginners - Creating your first PHP program FROM SCRATCH: Basic Authentication, Membership and CRUD functionalities
PHP Tutorials for Beginners - Creating your first PHP program FROM SCRATCH: Basic Authentication, Membership and CRUD functionalities

PHP Tutorials for Beginners - Creating your first PHP program FROM SCRATCH: Basic Authentication, Membership and CRUD functionalities

COBOL Programming Tutorials - Using Routines (Loop) and a Little of User Intervention
COBOL Programming Tutorials - Using Routines (Loop) and a Little of User Intervention

Quick COBOL tutorials with routines (loop) and user input

130 Comments
  • anonymousReply
    April 17, 2015 5:33 PM

    you forgot to tell that the [allowanonymous] has been placed before the public class AuthController:Controller. when overlooked, this will cause problem on the login part

    • Kristian
      April 20, 2015 7:01 AM

      Pretty much the term explains it and the hierarchy on where its placed defines that functions within the class are anonymous by default. Thanks for your feedback!

    • george
      June 6, 2015 3:37 PM

      Hi Kristianguevara I see that the "[AllowAnonymous]" added produces error "unauthorized" and does not allow me to get to the login page. when I remove it no error shows. Don't know followed your instructions carefully. Some help

    • george
      June 6, 2015 3:56 AM

      Let me update my information. When I remove the filterconfig class in the global.asax.cs file the error goes away. what am I doing wrong.

    • Kristian
      Jan 1, 1970 12:00 AM

      Hi George! May I know which part of the tutorial are you currently working on? Also, what version of Visual Studio are you using?

    • Prasanth
      Aug 23, 2017 11:19 AM

      hiii Sir , Its a great way to teach a beginner like me … I am following how you have done ..but after 6.4) Displaying the Error Message and Adding URL Validation ….i am not able to redirect to Index Page … Its Stays on the Same Page ..ie:- http://localhost:60923/auth/Login?ReturnUrl=%2F Please help me sir

  • EddieReply
    July 3, 2015 6:18 PM

    Is this for Identity V1.0 or V2.0? Many thanks for all your hard work!

    • Kristian
      July 7, 2015 11:35 PM

      Hi Eddie! This is for V1.0. Thanks for your feedback!

  • pawanReply
    Dec 2, 2015 6:42 AM

    i am getting error (“LoginModal is inaccessible due to its protection level”). can u explain why i m getting this please..

    • Kristian
      Dec 26, 2015 6:42 PM

      You misspelled LoginModel to LoginModal (not you carried over it). Another is make sure its set to public. Protection level means its access level (public, private, protected, etc). Maybe yours had an assumption of public. Making it public could solve that issue.

  • HughReply
    Jan 18, 2016 8:02 PM

    Hi Christian, Thanks so much for the tutorial! It is great. I’m a beginner and as I’m following the tutorial, am encounter an error at 6.1) Adding the HttpGet Login Method to the AuthController. ReturnUrl = returnUrl It said LoginModel does not contain a definition for ReturnUrl I look at the LoginModel.cs and it has a public string ReturnURL but not ReturnUrl ? How can I resolve this error? Thanks very much.

    • Kristian
      March 17, 2015 12:30 AM

      Hello! That’s likely from your query string as it doesn’t contain a URL value. Check your browser’s URL and see if it contains any values. If none, you may have to double-check the code 🙂

  • HughReply
    Jan 18, 2015 10:21 PM

    Hi Christian, Sorry, never mind. I had a typo in the LoginModel class.

    • Kristian
      Jan 20, 2015 6:57 PM

      Hi Hugh! No worries just feel free to comment out if you get into confusions.

  • Niraj KaushalReply
    Jan 22, 2015 3:36 AM

    Helpful article Thanks ☺

    • John VicencioReply
      Jan 22, 2015 4:01 PM

      The [AllowAnonymous] doesn’t work. You still see the same error on login view. Please advise. (note: this one doesn’t work http://kristianguevara.net/wp-content/uploads/2015/04/28.jpg).

      • Kristian
        Jan 22, 2015 10:03 PM

        Hmm I see. Try double-checking the Startup.cs as it could be the potential file that can produce the error. If it still doesn’t work, try to download the entire project and if it’s flawless, from there you can retrace the steps.

      • John Vicencio
        Jan 27, 2015 3:57 AM

        Ah. I’ll try download and retrace. Should have thought of that. Thank you!

    • HughReply
      Jan 26, 2015 1:51 AM

      Hi Christian, I follow through and got the app to work. I have created three users but they all view the same list. The Users table each have an Id (1, 2, 3). The Lists table have 8 items but all the User_Id are the same which is 1. Seems like the Lists – Users relationship is not set? How can I resolve this issue? Thanks

      • Hugh
        March 27, 2016 12:32 AM

        Hello! Try rechecking again your id values. That’s the most probable case I see as they might not be mapped properly.

    • DanielReply
      Jan 30, 2015 1:45 PM

      This is a really well thought out tutorial. Thanks for taking the time to compile this together. You really cover the gambit of programming one fell swoop.

      • Kristian
        Jan 30, 2015 5:04 AM

        Thanks! 🙂

    • abdullahReply
      Jan 30, 2020 3:45 AM

      Thanks man this is awesome ..

      • Kristian
        Jan 30, 2015 5:04 AM

        You’re welcome man!

    • EnriqueReply
      March 12, 2015 1:24 AM

      Hello, how are you? firstly, thanks for this amazing post! I was coding what you wrote, but I receive an error in the decrypt method : System.Security.Cryptography.CryptographicException: The input data is not a complete block. just in this part of code: using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(cipherBytes, 0, cipherBytes.Length); cs.Close(); //here } what can it be the cause?

      • Kristian
        March 17, 2015 12:35 AM

        Hello! Thanks for leaving out your feedback and I really appreciate it! Regards to your issue, it says you have a missing block. In other words, you still have a missing input from your value. This Stack Overflow post might help http://stackoverflow.com/questions/3253325/cryptographic-exception-input-is-not-a-complete-block

    • Nishant H. LohakareReply
      March 16, 2015 5:26 AM

      Thanks Kristianguevara for this Awesome post. I was waiting for this. You have explained things just like bread and butter no one ever had. I followed the entire tutorial and it works great. Thanks a lot !

      • ahmet kocadoğanReply
        March 21, 2015 1:19 PM

        i was lost between msdn,asp.net web site,stackoverflow and codeproject. you saved my time with your very simple and powerful explanation about asp.net login, claims and identity. Thank you all.

        • Kristian
          March 23, 2015 8:18 AM

          Thank you very much and hope you enjoyed the article!

      • AndrewReply
        March 24, 2015 9:39 AM

        Hello, thank you for awesome tutorial, everythink works just fine! I want to ask, how set, that only user can edit/delete items which he actually created? I guess it should be easy while there is a reliationship between item and user. Thanks!

        • Kristian
          March 25, 2015 9:43 PM

          Thanks too! Yes you can add use the user privileges for admin accesses for edit/delete. What you can do is you can add to your query something like db.Users.Where(u => u.userAccessLevel == model.userAccessLevel) and check if it matches their conformity. You can rate them into something like 1 = admin, 2 = user.

        • Andrew
          March 27, 2015 7:39 AM

          Thank you for your quick response! I’ve got the idea, but I’m still in the beginning of learning ASP.net. Can you provide more complex step-by-step solution or maybe some links which will help me better understanding and solving problem? (I tried google a little bit, but always ended up with role system and so on, which I found bigger than my needs). Anyway, thank you. I’ll keep trying 🙂

      • LauraReply
        April 5, 2015 12:07 PM

        Hi! Thanks so much for this tutorial – it’s so helpful 😀 Just a quick question – When I try and navigate App_Data > Add> SQL Server Database I can’t see SQL Server database? I have installed the Microsoft SQL Server Compact Edition and applied it to the solution but I still cannot see anything. I would be grateful if you could point me in the right direction! Thank you!

        • Kristian
          June 25, 2015 2:46 AM

          Hello Laura! Thanks for leaving out your comment and I apologize for my late reply. To be honest I’m not sure about that by my gut tells me this has something to do with the SQL Server installation and version. Sorry if I can’t give you the exact solution but since you already have the server installed, maybe you can try playing around with it by connecting SQL Server and use it as the source of the database itself instead of the in-house DB within the project. Maybe this article can help (https://msdn.microsoft.com/en-us/library/z6sa01t4.aspx). Hope I helped! 🙂

        • alf
          Aug 2, 2015 11:58 PM

          Laura, just in case you couldn’t figure it out, Right-click on the App_Data and choose Add –> New Item and then select SQL Server Database from the list of options

      • RefinedReply
        April 22, 2015 6:21 AM

        Great Job, Please after login in using the hard coded userinfo, i’m not redirected to the login and I have typed exactly what’s there. Please help.

        • Kristian
          June 25, 2015 2:51 AM

          Hello Refined! I’m not sure what you meant on “i’m not redirected to the login” but I’m just assuming you typed a wrong username/password and you want it to be redirected back the login page yet it didn’t happened. Thats likely on your middleware on the Startup.cs. Try to double-check your Web.config and make sure that its referenced properly. Retrace your steps from the middleware part and see which part you weren’t able to follow. If the problem still persists, you can download the entire project and try to compare from there. Hope that helps!

      • wilReply
        April 26, 2015 3:04 PM

        Thanks man this is awesome … very well explained !!!

        • Kristian
          June 25, 2015 2:54 AM

          Thanks wil and hope you enjoyed it!

      • ch sandeep kumarReply
        June 24, 2015 8:44 AM

        simply i loved you explanation and thanks for all details. just i spend 1 hour entire article and i created my first asp.net mvc application.Thank you very much.

        • Kristian
          June 25, 2015 2:55 AM

          Hello ch sandeep kumar! Thanks for your feedback and hope you enjoyed it 🙂

      • DraganReply
        July 24, 2015 3:38 AM

        I have NullReferenceException for – string userEmail = sessionEmail.Value; Can you help me?

        • Kristian
          July 26, 2015 11:14 PM

          It means your emails wasn’t saved on the claim. Try to double check your authentication layer. If problem persists, try to download my Github project and compare the changes. Maybe something you did something wrong during the process.

      • dave ernestpReply
        Aug 8, 2015 11:54 AM

        hey, at very early stage i get this error, and i cant get over it A claim of type ‘http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier’ or ‘http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider’ was not present on the provided ClaimsIdentity. To enable anti-forgery token support with claims-based authentication, please verify that the configured claims provider is providing both of these claims on the ClaimsIdentity instances it generates. If the configured claims provider instead uses a different claim type as a unique identifier, it can be configured by setting the static property AntiForgeryConfig.UniqueClaimTypeIdentifier. Line 6: @Html.AntiForgeryToken() pls help 🙂

        • Kristian
          Aug 14, 2015 8:46 PM

          Hello Dave apologies for the late reply. Regarding your error you can check this link out http://stackoverflow.com/questions/19977833/anti-forgery-token-issue-mvc-5 In other words just place in your global.cs the code below and hopefully it should work 🙂 AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

      • SiyuanReply
        Aug 12, 2015 2:54 AM

        This is one of the greatest tutorial I have read about building asp.net mvc website from scratch so far! Thank you so much!

        • Kristian
          Aug 14, 2015 8:42 PM

          I’m glad I helped. Thank you too for reading out the tutorials!

      • ManthanReply
        Aug 14, 2015 6:45 PM

        Just awesome.. Thanks

        • Kristian
          Aug 14, 2015 8:43 PM

          Thanks too my friend!

      • PatrickReply
        Aug 15, 2015 10:49 PM

        good day sir…i have a problem on the part of Auth/Registration where you click to register it says TypeInitializationException was unhandled by user code in the MainDbContext.cs pointing to base(“name = DefaultConnection”)

        • Kristian
          Aug 27, 2015 5:49 AM

          Hello Patrick! About your problem, that likely occurs on the connections string. Kindly double check if you typed it correctly. Make sure you follow the steps thoroughly and you didn’t missed out a single character. If it seems unresolvable, you can refer to the finished product, compare it and see which part you went wrong. Hope that helps!

        • Patrick
          Aug 18, 2015 5:08 PM

          thanks for the reply i just change my connection string…another problem i encounter again sir in on the Index.cshtml on the db.SaveChanges(); it says An exception of type ‘System.Data.Entity.Infrastructure.DbUpdateException’ occurred in EntityFramework.dll but was not handled in user code.

        • Patrick
          Aug 18, 2015 4:00 PM

          i mean HomeControllers.cs

      • ChineduReply
        Sep 20, 2015 8:38 AM

        Thanks a lot for this wonderful tutorial. I learn’t a lot. As a beginner it’s difficult finding good materials with focus on beginners and coding from scratch. Thanks again i really appreciate.

        • Kristian
          Nov 16, 2016 1:14 PM

          Thanks Chinedu and I’m glad to hear that! 🙂

      • Manish PanditReply
        Sep 16, 2015 10:46 AM

        WONDERFUL

        • Kristian
          Nov 16, 2015 1:14 PM

          Thanks my friend!

      • Manish PanditReply
        Sep 19, 2015 4:55 AM

        How to Redirect user on Succesful registration to Main Index Page (auto login) Please let me know ?

        • Kristian
          Nov 16, 2015 1:36 PM

          Hello Manish! You may use the Url.Action() for that. You can pretty much checkout a working example on part 6.4. Cheers!

      • JRReply
        Jan 23, 2015 10:09 PM

        You from the Philippines too? 🙂 I was having a hard time finding tutorials from scratch that also include CRUD capabilities. Until I found this. I’m new to ASP MVC so this is very helpful. Although I’m having a little difficulty understanding some of the syntax but overall thank you for this wonderful tutorial!

        • Kristian
          Nov 16, 2015 1:54 PM

          Yup hi there mate! 🙂 Wow great to hear that and hope you’re now comfortable with ASP.NET MVC!

      • AMHReply
        Oct 29, 2015 4:06 AM

        Hi Sir, At the beginning I got Server Error in ‘/’ Application. I solved that by adding “” to Web.config and it worked. But after adding [HttpPost] it keeps giving me “No owin.environment item was found in the context ” at request.getOwinContext () method. How should I solve that?

        • AMH
          Oct 29, 2015 4:11 AM

          *** by adding “”

      • cyber_daemonReply
        Nov 8, 2015 1:53 AM

        Good day, I have a query regarding MVC, suppose i have 2 tables on my dbase, 2 tables has related to each other 1 to many relation. I already use join in my LINQ but how could i put the result of that join table in my view? saying(var x =(from y in _db.mytble join z in _db.myothertbl on y.id = z.yid select new mytblcombi{ yfield = y.id,yotherfiled=y.field,yotherfield1=y.otherield1, z.field = field,z.otherfield=otherfield})) do i have to create a class for mytblcombi? how could i call this on view? to output the result on the user thanks

        • Kristian
          Nov 16, 2016 2:09 PM

          Hello cyber_daemon! In order to display the results of your join data to the view you need to return it as a list. In your example you already have a variable “x” which serves as the result of your query. Only thing missing is you need to materialize that into a list object by calling out .ToList(). In other words, you should do something like this return View(x.ToList());

      • adamReply
        Nov 7, 2015 10:43 PM

        Thanks, nice tutorial, it is important to understand basics so building an application from scratch makes perfect sense for learning purposes!

        • Kristian
          Nov 16, 2016 4:00 PM

          Thanks adam and I’m glad I helped!

      • JMartinezReply
        Nov 11, 2016 4:00 PM

        Hi, why am I getting this error during registration that no one may seem to have an answer for as I google it. An exception of type ‘System.Data.Entity.Infrastructure.DbUpdateException’ occurred in EntityFramework.dll but was not handled in user code Additional information: An error occurred while updating the entries. See the inner exception for details. ON: db.SaveChanges(); I am using: Visual Studio 2013 EntityFramework.6.1.3 Microsoft.AspNet.Mvc.5.2.3 Microsoft.Owin.3.0.1 Owin.1.0 I am a ASP.NET – VB guy but I’m making a transition to ASP.NET MVC – C# Please any help would be gracefully appreciated.

        • Kristian
          Nov 17, 2016 8:17 AM

          Hello JMartinez! It seems like the error is more on your entity framework library or if not, you need to update your db. Maybe this could help: http://stackoverflow.com/questions/20286283/why-do-i-get-an-error-if-i-have-1-dbcontext-with-multiple-dbsets-when-calling-sa

      • JonathanReply
        Dec 1, 2016 5:11 AM

        Hello Kristian, Good tutorial, i really wanted to learn MVC asp.net from scratch. I have a question, it’s pretty basic but maybe you can help me. When you give us a code to paste in the project, it appears like: &lt;table class=”table table-bordered table-condensed”&gt; &lt;thead&gt; &lt;tr&gt; Ofc it won’t work if i paste it into VS2013, so.. How can I convert the code you put to normal code instead of seeing the uncoded code?

        • Kristian
          Dec 11, 2016 8:55 PM

          Hello Jonathan! That snippet of code are actually HTML entities. Unfortunately for some weird reason my website did not recognize these HTML entities as a result it displayed as raw data. In any case you can view the picture for the real (translated) code or worse case you can check out the finished project then compare your work from there (link is on the last part of this article). The code in your comment is simply translated as: Hope this helps!

        • Kristian
          Dec 11, 2016 8:57 PM

          Looks like my previous comment didn’t displayed it. it should be: Oh and for your additional reference, you can know more about HTML entities here http://htmlhelp.com/reference/html40/entities/special.html

      • AnonymReply
        Dec 21, 2016 5:29 AM

        Hi! Our connection isn’t working in this project, it seems like the connection string is for the sql server 2012, how do we change it to the latest version? In the connectionsStrings in webconfig page. Thanks in advance!

        • Kristian
          Dec 22, 2016 1:37 AM

          Hello Anonym(ous)! There’s actually a cool site that provides a boilerplate on sql server connections strings. You can check them out here: https://www.connectionstrings.com/sql-server/

      • NourReply
        Feb 20, 2017 4:15 AM

        hiiii , i’m a beginner and i’m using VS 2015 Express i have stopped at the login check with mail and pass as when i put the action =(” index”,”home”) i got the url empty and it throws an exception : “An exception of type ‘System.ArgumentException’ occurred in System.Web.Mvc.dll but was not handled in user code Additional information: Value cannot be null or empty.” at this line : return Redirect(GetRedirectUrl(model.ReturnUrl)); any help??

        • Kristian
          March 25, 2017 5:27 AM

          Hello! It seems that you’re having troubles with your URL value. Double-check again the return URL value and see where it went wrong. If things really don’t go well you might want to check the complete source code and double-check your work from there. Make sure you have the packages installed properly!

      • aliReply
        Feb 21, 2017 4:00 PM

        Thank you for this tutorial, it helped me a lot thanks again

        • Kristian
          March 25, 2017 5:41 AM

          Thanks too Ali hope you enjoyed it!

      • iliReply
        Feb 28, 2017 12:23 AM

        hello sir , thanks for ur tutorial , it helped me a lot , i have just one problem , in the delete part its not deleting the records

        • Kristian
          March 25, 2017 5:43 AM

          Hello ili thanks for your feedback! If your delete is not working kindly double-check your code from top. Its likely just occurring on either the data you’ve passed on or the line of code that does the deletion. If things really don’t work I suggest to look into the complete source code (link on the last part) then double-check your work there.

      • JeppeReply
        March 20, 2017 11:33 PM

        Great tutorial Kristian. I can recommend that people who follow this tutorial find a better way to hash the password, since this method is very easy to break. I provide you guys with some links here: https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs https://crackstation.net/hashing-security.htm <– detailed explanation

        • Kristian
          March 25, 2017 5:44 AM

          Hello Jeppe. Thanks for those recommendations! It would be a great help to people trying to figure out a better way of doing so!

      • Alam KhanReply
        March 7, 2017 11:14 PM

        Hi Nice Article ! I am learned a lot of thing in this article thank you so much. I have a question i am using role management. 1) Admin 2) Manager 3) Salesman. How am i provide specific difference dashboard to each one. Please explain .Thank you

        • Kristian
          March 25, 2017 5:47 AM

          Hello Alam thanks for your feedback! For role management, you can simply add in an additional row wherein a certain number represents the level of their privilege. Say 1 for admin, 2 for user, etc. If you don’t want to create from scratch, there’s a library you can use: https://code.msdn.microsoft.com/ASPNET-MVC-5-Security-And-44cbdb97

      • PavanReply
        March 8, 2017 10:27 AM

        Wow! Followed this article and most of my concepts regarding MVC framework are clear. Thank you so much. I was able to build a personal note web application based off your explanation.

        • Kristian
          March 27, 2017 5:48 AM

          Hello Pavan thanks for your feedback! Glad your learned and hope you enjoyed it!

      • JimReply
        Jan 28, 2017 4:00 PM

        Hi, Thank you for this post it did work fine. Is there any chance to add register only for admin (removing register from home screen and adding admin roles so ony he can register people?

        • Kristian
          March 25, 2017 5:37 AM

          Hello Jim thanks for your feedback! Yes you may! you’ll simply add an additional table like a privilege level in order to determine their capabilities. Say 1 is for admin, 2 is for user, etc.

      • DimReply
        March 25, 2017 11:57 AM

        HI I’m new in MVC Asp.Net before I work webforms. My Question is how is good creating the connection with database in MVC. I want creating one ClassLibrary where creating EntityFramework the content from EF and model from EF I want using in MVC Web Project. When creating the Controller the connection with EF from ClassLibrary are creating EntityDB db=new EntityDB(); .

        • LouReply
          April 3, 2017 2:22 AM

          Hey !! Thank you, Great article !!! I have one question. On the Index we get the list, using the following: public ActionResult Index() { var db = new MainDbContext(); return View(db.Lists.ToList()); } How would I order this by date poster ?

          • Kristian
            April 12, 2017 6:22 AM

            Hello Lou thanks for your feedback! What you can do is you can add an additional method called OrderByDescending(). Example using date_posted field – db.Lists.OrderByDescending(a => a.Date_Posted).ToList()

        • Yakup BiberReply
          April 11, 2017 12:16 AM

          this is the best mvc tutorial I have ever read. there are lots of tutorial on net but all of them start to explain from template. and templates has lots of dummy files like views, controllers, js files and so forth. thanks for this lovely tutorial.

          • Kristian
            April 12, 2017 6:10 AM

            Thanks for your feedback Yakup! Glad it helped!

        • MichelReply
          April 19, 2017 1:55 PM

          Hello kristianguevara, AWESOME !!! As one of the replies said : I was lost between codeproject, msdn, asp website, and stackoverflow then I found this tutorial…. I have one question (on problem) and one suggestion : – Suggestion : Those using a SQL SERVER instance (not the one built into VS ) should add the following protected override void OnModelCreating(DbModelBuilder modelBuilder) {modelBuilder.Conventions.Remove();} – Question : I’m stuck at Login (step 10). Identity does get Authenticated. I can register a user. I can get its data backfrom the database. Password is encrypted and decrypted successfully… but identiy never gets authenticated therefore, return RedirectToAction(“Index”, “Home”); always redirects me to the login page… Looking in the debugger (breakpoint right on the above RedirectToAction), I saw that identity property IsAuthenticated remains set to false… So I guess authManager.SignIn(identity); never succeeds (in my case)… Any idea what the issue is and how we could resolve this ?

          • MichelReply
            April 18, 2017 4:00 PM

            http://i66.tinypic.com/2r5gw21.jpg -> this is an image of debugger in _Layout… You’ll see @user.authenticated is not true…. You’ll also see that Claims are empty though they where properly set in AuthController (did not add an image for that)… In both Login action and _Layout, debugger show IsAuthenticated property to be false… — Also, for my suggestion above, it is actually protected override void OnModelCreating(DbModelBuilder modelBuilder) {modelBuilder.Conventions.Remove();}

            • ferreteriaReply
              June 15, 2017 5:17 AM

              Hello I am so excited I found your weblog, I really found you by error, while I was browsing on Aol for something else, Regardless I am here now and would just like to say kudos for a tremendous post and a all round interesting blog (I also love the theme/design), I don’t have time to go through it all at the minute but I have saved it and also added your RSS feeds, so when I have time I will be back to read a lot more, Please do keep up the awesome job.

              • DenizReply
                July 4, 2017 5:05 AM

                Hi Kristian Guevara, Thanks for the tutorial! I have 1 question how can I display current user data and NOT from all users. I think that i need to change something in HomeController.cs example return View(listTable.Lists.ToList()); // return data but only for user who has logged in. And when he or she signs out show nothing. Thanks!

                • RhetzelleReply
                  July 9, 2017 4:00 PM

                  Hi there! How can I declare a database schema other than dbo.tablename?

                  • Sachin KarcheReply
                    July 17, 2017 11:53 AM

                    Many thanks for all your hard work! Very nice stuff to learn step by step. Thanks.

                    • FrankReply
                      Aug 30, 2017 10:09 AM

                      Hi Kristian, In the Home Controller HttpPost ActionResult Index method, the variable ‘check_public’ is not defined. It’s defined in the View module. Any help would be highly appreciated. Thanks, Great article!

                      • FrankReply
                        Aug 30, 2017 8:32 AM

                        Just notice that the variable ‘check_public’ is defined further pages down. Great tutorial, Thanks.

                        • unknownReply
                          Sep 13, 2017 3:15 PM

                          Great tutorial, thanks!

                          • MagnetiqueReply
                            Sep 16, 2017 3:24 PM

                            Only wanna say that this is very beneficial, Thanks for taking your time to write this.

                            • SuavpeleReply
                              Sep 18, 2017 3:33 PM

                              Hey there, You have performed an incredible job. I will certainly digg it and in my view recommend to my friends. I’m sure they will be benefited from this website.

                              • Liquid Tree CBDReply
                                Oct 6, 2017 7:30 PM

                                It’s wonderful that you are getting ideas from this piece of writing as well as from our discussion made here.

                                • ShemaleGifReply
                                  Nov 9, 2017 10:23 AM

                                  Nice piece, Carry on the great work!. deffo will be visitng again to read any new posts!

                                  • KristianReply
                                    Nov 16, 2017 6:06 PM

                                    Thanks guys for your support! Hope you enjoyed it!

                                    • epibatiga ploiaReply
                                      Dec 10, 2017 2:46 AM

                                      Way cool! Some extremely valid points! I appreciate you penning thiks write-up plus the rest of the website is very good.

                                      • Star CReply
                                        Dec 14, 2017 9:01 AM

                                        I was reading through some of your blog posts on this site and I conceive this website is very instructive! Keep posting.

                                      • Isolate Direct Reply
                                        Dec 16, 2017 12:22 PM

                                        Thankfulness to my father who informed me on the topic of this blog, this blog is genuinely remarkable.

                                        • Tim FlReply
                                          Dec 16, 2017 11:17 PM

                                          You have mentioned very interesting details! ps decent website.

                                          • Clinton MansellReply
                                            Dec 17, 2017 9:30 AM

                                            Good post over again! I am looking forward for more updates:)

                                            • Kory WasingerReply
                                              Dec 18, 2017 12:08 PM

                                              I the efforts you have put in this, thanks for all the great blog posts.

                                              • GeniaReply
                                                Feb 7, 2018 11:30 PM

                                                Thanks for sharing superb informations. Your site is so cool. I’m impressed by the details that you’ve on this site. It reveals how nicely you perceive this subject. Bookmarked this web page, will come back for extra articles. You, my pal, ROCK! I found just the info I already searched everywhere and just could not come across. What a great web-site.

                                                • TryVixReply
                                                  Feb 12, 2017 4:09 AM

                                                  Some genuinely nice stuff on this web site, I enjoy it.

                                                  • CorvoNeroReply
                                                    Feb 27, 2018 8:09 AM

                                                    Thank you so much for this tutorial. The Visual Studio templates and tutorials are fine, but I really wanted to learn how to do this myself, because I want to understand what I’m doing and why 🙂 Your explanations are just right, not too long, and the links you provide for more details are also good. This is really great, thanks for the effort you put into this!

                                                    • JJLReply
                                                      March 21, 2018 3:03 AM

                                                      Thanks so much for this tutorial. I have two tables “Users” (UserID, UserName, RoleID, Pwd) and “Role” (RoleID, RoleName). How do I show Role as a Dropdown list or box on the Registration view. (it should display the RoleName and not the RoleID value). The two tables are related (RoleID field). I would appreciated your help.

                                                      • Swayam DashReply
                                                        March 21, 2018 11:39 PM

                                                        Hey Kristian, Could you explain the GetRedirectUrl method once again? It is not redirecting me to /home/index on login and I am unable to figure out why. It never enters into the if block that you have specified, and even if it does, url.action returns only a forward slash instead of home/index route.

                                                        • James EdwardsReply
                                                          May 4, 2018 7:16 PM

                                                          Should include the following in Global.asax.cs to avoid the home page showing up when logging out. // Required section so that when you hit the back button after logging off you do not get the home page //https://stackoverflow.com/questions/19315742/after-logout-if-browser-back-button-press-then-it-go-back-last-screen protected void Application_BeginRequest() { Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1)); Response.Cache.SetNoStore(); }

                                                          • James Edwards
                                                            May 4, 2018 7:18 PM

                                                            I should have said this before my comment. Very nice tutorial. Thank you for taking the time to post this.

                                                        • NitishReply
                                                          May 8, 2018 9:43 AM

                                                          Excellent blog. I was looking for this for a long time. Please share me a link if you have token based authentication using Identity.

                                                          • KameronReply
                                                            July 2, 2018 4:31 PM

                                                            Great article, helped me a lot. I do have one odd issue. When debugging mode, I log in and I get the list showing on the index page. But when I deploy the website and log in, I get an index page but no list or button or anything but the word Index shows. Anyone have an idea? Thank you

                                                            • Abhida ozaReply
                                                              Sep 26, 2018 11:19 AM

                                                              I am getting an error in login.cshtml It says ‘Loginmodel’ is a type which is not valid in the given context. Please help @MyFirstWebsite.Models.LoginModel; @{ ViewBag.Title = “Login”; } Login @Html.ValidationSummary(true) @using (Html.BeginForm()) { @Html.EditorForModel() Log in } My loginmodel.cs code is using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.ComponentModel.DataAnnotations; namespace MyFirstWebsite.Models { public class LoginModel { [Required] [DataType(DataType.EmailAddress)] public string Email { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } [HiddenInput(DisplayValue = false)] public string ReturnUrl { get; set; } } }

                                                              • SenReply
                                                                July 3, 2019 1:21 AM

                                                                Hello, I have a problem with login form always return to login page when I clicked Register Link, web address display “/auth/login?ReturnUrl=%2FAuth%2FRegister”. I really need your help please, Thanks.

                                                                • KC FrankReply
                                                                  Nov 28, 2019 3:05 PM

                                                                  This is great. I have finished a project months ago, all I need was how to redirect when the user isn’t authenticated and I got my answer here. Thanks

                                                                  • Rosendo PruterReply
                                                                    Sep 18, 2020 4:55 PM

                                                                    TY for this piece, it is very useful to me! Way better written than other bloggers out there.

                                                                    • Kristian
                                                                      Sep 30, 2020 11:00 AM

                                                                      Glad it helped!

                                                                  Write a comment
                                                                  Notify me for replies