Introduction
With the new ASP.NET Identity, our applications are increasingly linked to the integration with social networks.
In the face of these additions, the new membership by default with ASP.NET MVC 4/5, is (intentionally) very "lean" and free of many features that are used to manage custom accounts provided on his application.
One of the features "missing" is the ability to send an Email confirmation in respect of the registration of a user, to verify that the email address exists. Figure 1 represents the login form with Email Field.
Using the Code
Below, I will explain in a step by step manner how to create a simple registration "custom" I have to send a confirmation email to the registration site.
Model User
Creating an application like ASP.NET MVC by default in the Models folder, we find the ApplicationUser
class, this class contains the definition of the model of our User.
The first step is to add the following properties to our class:
Email
: E-mail address of our user
ConfirmedEmail
: A Boolean value that indicates the Email address after user's confirmation.
public class ApplicationUser : IdentityUser
{
public string Email{ get; set; }
public bool ConfirmedEmail { get; set; }
}
Registration ViewModel
Once you add the Email property to our model, we should modify the view model used in the user registration adding the Email
field:
public class RegisterViewModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[EmailAddress]
[Display(Name = "E-mail")]
public string Email { get; set; }
}
Our field during the registration process will be mandatory ([Required]
) and Type Email ([EmailAddress]
), so that the front end will be activated client side scripts to check the presence of the data and the validity of the form (Email Address).
Registration Form
After changing the Register ViewModel
, we can update the View User's registration:
@{
ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Register", "Account",
FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
@Html.ValidationSummary()
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Action ConfirmEmail and Register
After changing the interface (View
), we can finally add a new Action ConfirmEmail
and change the Action Register of our controller (AccountController
) used for registration, adding sending an e-mail address provided during registration:
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string Token, string Email)
{
ApplicationUser user = this.UserManager.FindById(Token);
if (user != null)
{
if (user.Email == Email)
{
user.ConfirmedEmail = true;
await UserManager.UpdateAsync(user);
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home", new { ConfirmedEmail = user.Email }); }
else
{
return RedirectToAction("Confirm", "Account", new { Email = user.Email });
}
}
else
{
return RedirectToAction("Confirm", "Account", new { Email = "" });
}
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
user.Email = model.Email;
user.ConfirmedEmail = false;
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage(
new System.Net.Mail.MailAddress("sender@mydomain.com", "Web Registration"),
new System.Net.Mail.MailAddress(user.Email));
m.Subject = "Email confirmation";
m.Body = string.Format("Dear {0}
<BR/>Thank you for your registration, please click on the
below link to complete your registration: <a href=\"{1}\"
title=\"User Email Confirm\">{1}</a>",
user.UserName, Url.Action("ConfirmEmail", "Account",
new { Token = user.Id, Email = user.Email }, Request.Url.Scheme));
m.IsBodyHtml = true;
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.mydomain.com");
smtp.Credentials = new System.Net.NetworkCredential("sender@mydomain.com", "password");
smtp.ServerCertificateValidationCallback = () => true;
smtp.EnableSsl = true;
smtp.Send(m);
return RedirectToAction("Confirm", "Account", new { Email = user.Email });
}
else
{
AddErrors(result);
}
}
return View(model);
}
Since sample code I leave to you the change for the management of localized strings for the parameters and sending the mail (the example uses a mydomain.com account, but you can use your email address).
Action / Confirm View
As you can see from the code, once you register a new user, a mail is sent and, unlike the default recording, is called the action "Confirm
" that is used to display video in the notification of sending mail registration confirmation the address indicated on the registration form:
[AllowAnonymous]
public ActionResult Confirm(string Email)
{
ViewBag.Email = Email;return View();
}
Finally add the Confirm View:
@{
ViewBag.Title = "Confirm Email Address Sent";
}
<h2>@ViewBag.Title.</h2>
<div class="row">
<div class="col-md-8">
Please check your Email Inbox, a confirm Email is Sent to @ViewBag.Email
</div>
</div>
Once you have applied the changes described in the previous steps, you can compile the web application and try a new user's registration. If everything is correct, there will come an Email to the address given in filling in the registration form, which contains a useful link for the confirmation of the email, for simplicity inside the link will be passed to the user's unique identifier and the 'e-mailreference. By clicking on the link contained within Mail, will be called the Action "ConfirmEmail
" which, once checked the input data, will mark as confirmed the email address of the user.
User Login
We can also change the flow of the application login to prevent access of a not yet "confirmed" user, always changing our controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
if (user.ConfirmedEmail == true)
{
await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Confirm Email Address.");
}
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
return View(model);
}
It simply checks the value of the property User's ConfirmedEmail
before logging on.
I hope the guide has been useful to you.
P.S. Remember to change the parameters for sending mail!
History
- March 2014: First release