Complete login and registration system in ASP.NET MVC application



Introduction

Before this article we have seen, how to create login page & registration page in ASP.NET MVC application but It was very simple example and most of the important features like email verification, password hashing in the registration page, remember me option in the login page has not been explained for make the example simple and easy to understand for beginners. Today in this article I will explain the followings...


  1. Registration page with email validation & password Hashing
  2. Email Verification Page for account verification, Login page with remember me option  & Logout page.

Ok, Let's start implementing complete login and registration system in ASP.NET MVC application. 

Follow the following steps in order to implement "Complete login and registration system in ASP.NET MVC application".

Here In this article, I have used Visual Studio 2015

Step - 1: Create New Project.

Go to File > New > Project > ASP.NET  Web Application (under web) > Enter enter application name > select your project location > and then click on add button > It will brings up a new dialog window for select template > here I will select Empty template > checked  MVC checkbox from Add folder and core referances for: > and then click on ok button.

Step-2: Add a Database.

Now I will create a database for our application. As this is a tutorial project, I will add a database in our applications here in the app_data folder.

Go to Solution Explorer > Right Click on App_Data folder > Add > New item > Select SQL Server Database Under Data > Enter Database name > Add.

Step-3: Create a table in our database.

In this example, I have added the table for store user data when submit for registration.



double click on the database under app_data folder  for open the database in server explorer > expand the database and Right click on Tables node > click on Add New Table >  here we will write schema of the table for the table we want to create > now click on Update button for create the table and then again click on Update Database button. 

Step-4: Add Entity Data Model.

Go to Solution Explorer > Right Click on Project name form Solution Explorer > Add > New item > Select ADO.net Entity Data Model under data > Enter model name > Add.
A popup window will come (Entity Data Model Wizard) > Select Generate from database > Next >
Chose your data connection > select your database > next > Select tables > enter Model Namespace > Finish.

Step-5: Add a partial class of user model class for apply validation.

Now I will add a partial class of that user model where We will add Data Annotation Validators for validate our model.

First, I will add a folder here inside the Models folder as we can not add same named file in the same location.

Go to solution explorer > Right Click on Models folder > Add > New Folder > Rename it "Extended".

Now I will add the partial class here in this Extended folder.

Right Click on the Extended folder > Add > Class > Enter "User.cs" in the name textbox > Ok.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
//namespace RegistrationAndLogin.Models.Extended
namespace RegistrationAndLogin.Models
{
    [MetadataType(typeof(UserMetadata))]
    public partial class User
    {
        public string ConfirmPassword { get; set; }
    }

    public class UserMetadata
    {
        [Display(Name ="First Name")]
        [Required(AllowEmptyStrings = false, ErrorMessage ="First name required")]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        [Required(AllowEmptyStrings = false, ErrorMessage = "Last name required")]
        public string LastName { get; set; }

        [Display(Name ="Email ID")]
        [Required(AllowEmptyStrings =false, ErrorMessage ="Email ID required")]
        [DataType(DataType.EmailAddress)]
        public string EmailID { get; set; }

        [Display(Name ="Date of birth")]
        [DataType(DataType.Date)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString ="{0:MM/dd/yyyy}")]
        public DateTime DateOfBirth { get; set; }

        [Required(AllowEmptyStrings =false, ErrorMessage ="Password is required")]
        [DataType(DataType.Password)]
        [MinLength(6,ErrorMessage ="Minimum 6 characters required")]
        public string Password { get; set; }

        [Display(Name = "Confirm Password")]
        [DataType(DataType.Password)]
        [Compare("Password",ErrorMessage ="Confirm password and password do not match")]
        public string ConfirmPassword { get; set; }

    }
}

N:B: You can see here in line 6 I have removed the .Extended  from namespace

Step-6: Create a Controller.

Go to Solution Explorer > Right Click on Controllers folder form Solution Explorer > Add > Controller > Enter Controller name > Select Templete "empty MVC Controller"> Add.
Here I have created a controller "UserController"

Step-7: Add a new Action (HttpGet) for getting the registration form.

I will add a HttpGet MVC action for getting the registration form.

[HttpGet]
public ActionResult Registration()
{
    return View();
}

Step-8: Add view for the registration (HttpGet) action.

Right Click on Action Method (here right click on Registration action) > Add View... > Enter View Name > Select "Create" under Template dropdown > Select User model from Model class dropdown > > Add.

HTML Code

@model RegistrationAndLogin.Models.User
@{
    ViewBag.Title = "Registration";
}
<h2>Registration</h2>
@if (ViewBag.Status != null && Convert.ToBoolean(ViewBag.Status))
{
    if (ViewBag.Message != null)
    {
        <div class="alert alert-success">
            <strong>Success!</strong>@ViewBag.Message
        </div>
    }
}
else
{
    using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.EmailID, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.EmailID, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.EmailID, "", new { @class = "text-danger" })
                    @Html.ValidationMessage("EmailExist", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.DateOfBirth, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.DateOfBirth, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.DateOfBirth, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.ConfirmPassword, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.ConfirmPassword, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
        if (ViewBag.Message != null)
        {
            <div class="alert alert-danger">
                <strong>Error!</strong>@ViewBag.Message
            </div>
        }
    }
}

<div>
    @Html.ActionLink("Login", "Login")
</div>

@section Scripts{
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
}

Step-9: Update _Layout.cshtml.

We have to update our _Layout.cshtml page. I will add a RenderSection for render js from view page after the jQuery library.

Here is the complete _Layout.cshtml page
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" type="text/css" />
    <script src="~/Scripts/modernizr-2.6.2.js"></script>
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                </ul>
            </div>
        </div>
    </div>

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>

    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
    @RenderSection("Scripts", false)
</body>
</html>

Step-10: Add a class for password hashing. 

When we will write code for registration post action in the next step we will do password hashing before saving data to our database. So here I will add a class for password hashing.

Go to solution explorer > Right Click on your project name > Add > Class > Enter name Crypto > Add.

   
using System;
using System.Text;

namespace RegistrationAndLogin
{
    public static class Crypto
    {
        public static string Hash(string value)
        {
            return Convert.ToBase64String(
                System.Security.Cryptography.SHA256.Create()
                .ComputeHash(Encoding.UTF8.GetBytes(value))
                );
        }
    }
}

Step-11: Add a new MVC Action for post registration form in UserController.

Here we will add a new MVC Action (HttpPost Action) for submit the registration form. Here we will validate the form and if we found the is valid then we will save registration data to our database and then we will send an email to the user email id for verify account.   

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Registration([Bind(Exclude = "IsEmailVerified,ActivationCode")] User user)
{
    bool Status = false;
    string message = "";
    //
    // Model Validation 
    if (ModelState.IsValid)
    {

        #region //Email is already Exist 
        var isExist = IsEmailExist(user.EmailID);
        if (isExist)
        {
            ModelState.AddModelError("EmailExist", "Email already exist");
            return View(user);
        }
        #endregion

        #region Generate Activation Code 
        user.ActivationCode = Guid.NewGuid();
        #endregion

        #region  Password Hashing 
        user.Password = Crypto.Hash(user.Password);
        user.ConfirmPassword = Crypto.Hash(user.ConfirmPassword); //
        #endregion
        user.IsEmailVerified = false;

        #region Save to Database
        using (MyDatabaseEntities dc = new MyDatabaseEntities())
        {
            dc.Users.Add(user);
            dc.SaveChanges();

            //Send Email to User
            SendVerificationLinkEmail(user.EmailID, user.ActivationCode.ToString());
            message = "Registration successfully done. Account activation link " + 
                " has been sent to your email id:" + user.EmailID;
            Status = true;
        }
        #endregion
    }
    else
    {
        message = "Invalid Request";
    }

    ViewBag.Message = message;
    ViewBag.Status = Status;
    return View(user);
}

Step-12: Add a new method in UserController for check email id availability.

Here I have added a method IsEmailExistfor check email id available or not.  

[NonAction]
public bool IsEmailExist(string emailID)
{
    using (MyDatabaseEntities dc = new MyDatabaseEntities())
    {
        var v = dc.Users.Where(a => a.EmailID == emailID).FirstOrDefault();
        return v != null;
    }
}

Step-13: Add an another method in UserController for sending a verification email.



[NonAction]
public void SendVerificationLinkEmail(string emailID, string activationCode)
{
    var verifyUrl = "/User/VerifyAccount/" + activationCode;
    var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, verifyUrl);

    var fromEmail = new MailAddress("dotnetawesome@gmail.com", "Dotnet Awesome");
    var toEmail = new MailAddress(emailID);
    var fromEmailPassword = "********"; // Replace with actual password
    string subject = "Your account is successfully created!";

    string body = "<br/><br/>We are excited to tell you that your Dotnet Awesome account is" + 
        " successfully created. Please click on the below link to verify your account" + 
        " <br/><br/><a href='"+link+"'>"+link+"</a> ";

    var smtp = new SmtpClient
    {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        DeliveryMethod = SmtpDeliveryMethod.Network,
        UseDefaultCredentials = false,
        Credentials = new NetworkCredential(fromEmail.Address, fromEmailPassword)
    };

    using (var message = new MailMessage(fromEmail, toEmail)
    {
        Subject = subject,
        Body = body,
        IsBodyHtml = true
    })
    smtp.Send(message);
}

Step-14: Run Application.

We have done all the steps. Now it's time to run the application. 

Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.