Wednesday, June 19, 2013

Custom Membership Provider in ASP.NET MVC 2-Part1


In this tutorial I will show how to implement Custom Membership Provider in ASP.NET MVC 2 Web Application using Microsoft Visual Web Developer 2010 Express.
The tutorial will consist of few parts (not sure how many at this stage) and I will try to cover custom implementations of membership, role and profile providers.
I will use custom database schema and Entity Framework with additional repository class sitting between the Membership Provider and Entity Framework model.
Let’s start by creating a new Project called CustomMembership.
Because we’re using ASP.NET MVC 2 Web Application template, we can instantly run the application and get:
This default project is already configured to use ASPNETDB database (or to create one if does not exist) located in App_Data folder and standard ASP.NET Membership Provider . We want to use custom database schema to store membership information and to do that we will have to implement Custom Membership Provider. So let’s do it!
First, create new class called MyMembershipProvider in Models folder.
Remove the namespace definition and make your class inherit MembershipProvider class fromSystem.Web.Security namespace.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;

public class MyMembershipProvider : MembershipProvider
{
}
Move MyMembershipProvider.cs file to App_Data folder by right clicking App_Data folder and adding an existing item, and remove it from Models folder by right clicking MyMembershipProvider.cs file and excluding it from the project.
Open App_Data\MyMembershipProvider.cs file for editing and right click on MembershipProvider class name and from the context menu choose Implement Abstract Class.
This will create override methods for MembershipProvider class.
You have just created Custom Membership Provider. None of the functionality is implemented yet but let’s just carry on and configure our application to use it.
Open Web.Config file in root of your project and change setting in membership node to use your new provider.
<membership defaultProvider="CustomMembershipProvider">
 <providers>
 <clear/>
 <add name="CustomMembershipProvider" type="MyMembershipProvider"
      connectionStringName="ApplicationServices"
      enablePasswordRetrieval="false"
      enablePasswordReset="true"
      requiresQuestionAndAnswer="false"
      requiresUniqueEmail="false"
      maxInvalidPasswordAttempts="5"
      minRequiredPasswordLength="6"
      minRequiredNonalphanumericCharacters="0"
      passwordAttemptWindow="10"
      applicationName="/" />
 </providers>
</membership>
If we run our project now, and try to log in using the link on the page you will see the following errors:
which is correct as we have not implemented any of the methods yet.
Let’s try to modify the ValidateUser method to return true and let us in.
public override bool ValidateUser(string username, string password)
{
 if (username == password)
 {
  return true;
 }
 else
 {
  return false;
 }
}
Now we should be able to log ourselves in as long as username and password are the same.
Let’s give it a go.

This is it for now! In the next part we will implement the database backend and UserRepository class.
Continue to:

MVC 2 Custom Membership Provider Tutorial – Part 2

Just to quickly wrap up what we’ve done so far:
We created new project using ASP.NET MVC 2 Web Application to make use of the layout (login pages, master page, login controls) and speed up our development.
We created Custom Membership Provider and we implemented custom logic into the ValidateUser method to show how we can override Membership Provider’s methods.
In this part of the tutorial we’re going to implement a database, create UserRepository class which will contain data logic (to keep the provider as simple as possible and to leave Entity Framework model untouched so we can make modifications to the database without breaking things), and implement some of the Membership Provider’s basic methods.
First of all, I would like to say that this is first time I’m doing this too. Although I’m few steps ahead of the tutorial I’m open to suggestions on how the implementation can be improved (both, coding and the way it works).
While I’m at it, I’ll just quickly (sorry for all the delay) mention where I see this tutorial going in the next few parts.
We’re going to implement all default Membership Provider methods to make it tidy. Even if it means just returning hard-coded value like password format (for example: we don’t need the option between text/hashed passwords).
We will also implement email validation system that will request clicking auto-generated link in an email to register, reset password and change email address.
After we’ve done that, we will implement Role Provider and we will create admin section of the application.
So, coming back to this part of the tutorial, first we will need a database table to store all membership information. The table I’m proposing is basically a hybrid of aspnet_membership table from ASPNETDB database and Userstable from Tank_Auth authentication library for CodeIgniter PHP framework (Check out the following link on Stack Overflow to find out more about Tank_Auth, it’s very informative – What Code Igniter authentication library is best? – Stack Overflow).
Let’s start by adding the database to our project. Right click App_Data folder, Add -> New Item…, Select SQL Server Database, call it CustomMembership.mdf and click Add.
In Database Explorer, right click on the Tables node and Add New Table. Create the following table:
Make UserId column a Primary Key and an Identity Column and save the table with the name Users.
Back in the Solution Explorer, right click Models folder Add -> New Item…, Select ADO.NET Entity Data Model, call it CustomMembership.edmx and click Add.
Select Generate from Database and click Next.
Change the connection name to CustomMembershipDB and click Next.
Select Tables, change Model Namespace to CustomMembership.Models and Finish the wizard.
Back in Solution Explorer open Web.config file and delete default ASPNETDB connection. We had to keep it there because Membership Provider needs connectionStringName parameter. Now, we have our DB connection which by the way Membership Provider is not going to use directly anyway, we can delete the ASPNETDB connection.
Change connectionStringName parameter value in Membership, Role and Profile provider nodes in Web.configfile like on the screenshot below.
We can quickly run our application to confirm that we didn’t break anything… yet.
While we have the application running see what happens if we click Register link on the login page.
We could just hard-code MinRequiredPasswordLength propery into Custom Membership Provider if we wanted to.
What happens is that when the Membership Provider is initialized, the Initialize() method is called. It readsWeb.config file and sets Membership Provider object’s properties. So, lets implement Initialize method inMyMembershipProvider class
First, lets add a reference to System.Collections.Specialized assembly:
using System.Collections.Specialized;
Next, create helper function which we will use to read config values.
 //
 // A helper function to retrieve config values from the configuration file.
 //  

 private string GetConfigValue(string configValue, string defaultValue)
 {
  if (string.IsNullOrEmpty(configValue))
  return defaultValue;  

  return configValue;
 }
Next, lets add properties from Web.config file. We’re going to hard code some of the provider’s default properties. We will want unique email and hashed password and we don’t want to let users to retrieve their passwords (not even, using QuestionAndAnswer)
 //
 // Properties from web.config, default all to False
 //
 private string _ApplicationName;
 private bool _EnablePasswordReset;
 private bool _EnablePasswordRetrieval = false;
 private bool _RequiresQuestionAndAnswer = false;
 private bool _RequiresUniqueEmail = true;
 private int _MaxInvalidPasswordAttempts;
 private int _PasswordAttemptWindow;
 private int _MinRequiredPasswordLength;
 private int _MinRequiredNonalphanumericCharacters;
 private string _PasswordStrengthRegularExpression;
 private MembershipPasswordFormat _PasswordFormat = MembershipPasswordFormat.Hashed;
And finally, lets add Initialize method.
public override void Initialize(string name, NameValueCollection config)
{
 if (config == null)
 throw new ArgumentNullException("config");

 if (name == null || name.Length == 0)
 name = "CustomMembershipProvider";

 if (String.IsNullOrEmpty(config["description"]))
 {
  config.Remove("description");
  config.Add("description", "Custom Membership Provider");
 }

 base.Initialize(name, config);

 _ApplicationName = GetConfigValue(config["applicationName"],
               System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
 _MaxInvalidPasswordAttempts = Convert.ToInt32(
               GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
 _PasswordAttemptWindow = Convert.ToInt32(
               GetConfigValue(config["passwordAttemptWindow"], "10"));
 _MinRequiredNonalphanumericCharacters = Convert.ToInt32(
               GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"));
 _MinRequiredPasswordLength = Convert.ToInt32(
               GetConfigValue(config["minRequiredPasswordLength"], "6"));
 _EnablePasswordReset = Convert.ToBoolean(
               GetConfigValue(config["enablePasswordReset"], "true"));
_PasswordStrengthRegularExpression = Convert.ToString(
               GetConfigValue(config["passwordStrengthRegularExpression"], ""));

}
I think the function is pretty much self explanatory. If you remove all unnecessary line breaks it will look much tidier.
We can edit Web.config‘s membership node and delete all the hardcoded parameters.
<membership defaultProvider="CustomMembershipProvider">
 <providers>
 <clear />
 <add name="CustomMembershipProvider"
      type="MyMembershipProvider"
      connectionStringName="CustomMembershipDB"
      enablePasswordReset="true"
      maxInvalidPasswordAttempts="5"
      minRequiredPasswordLength="6"
      minRequiredNonalphanumericCharacters="0"
      passwordAttemptWindow="10"
      applicationName="/" />
 </providers>
</membership>
Next, let’s implement the properties fully into our Custom Membership Provider.
Open MyMembershipProvider file and starting from the top edit properties and methods as below:
public override string ApplicationName
{
 get { return _ApplicationName; }
 set { _ApplicationName = value; }
}
Because we will not implement password reset using security question and answer we can change:
public override bool ChangePasswordQuestionAndAnswer(string username,
                                                     string password,
                                                     string newPasswordQuestion,
                                                     string newPasswordAnswer)
{
 return false;
}
public override bool EnablePasswordReset
{
 get { return _EnablePasswordReset; }
}

public override bool EnablePasswordRetrieval
{
 get { return _EnablePasswordRetrieval; }
}
public override int MaxInvalidPasswordAttempts
{
 get { return _MaxInvalidPasswordAttempts; }
}

public override int MinRequiredNonAlphanumericCharacters
{
 get { return _MinRequiredNonalphanumericCharacters; }
}

public override int MinRequiredPasswordLength
{
 get { return _MinRequiredPasswordLength; }
}

public override int PasswordAttemptWindow
{
 get { return _PasswordAttemptWindow; }
}

public override MembershipPasswordFormat PasswordFormat
{
 get { return _PasswordFormat; }
}

public override string PasswordStrengthRegularExpression
{
 get { return _PasswordStrengthRegularExpression; }
}

public override bool RequiresQuestionAndAnswer
{
 get { return _RequiresQuestionAndAnswer; }
}

public override bool RequiresUniqueEmail
{
 get { return _RequiresUniqueEmail; }
}
At this point, we can run the application and go to Log In -> Register page and we will see:
with minimum password length being taken from Web.config file.
In case I’ve made some typos while copy and pasting the code here you can downloadMyMembershipProvider.cs file up to this point of the tutorial:
If we try to register new account we will get an error about CreateUser method not being implemented.
Before we implement CreateUser method we need to implement 2 other methods which are used by CreateUsermethod: GetUser and GetUsernameByEmail.
We need them both to check for existing usernames and email addresses in our database.
Let’s start by creating UserRepository class.
Right click Models folder, Add -> Class…, call it UserRepository and click Add.
In UserRepository class, add reference to System.Web.Security assembly:
using System.Web.Security;
We’re going to implement 3 methods at this stage:
CreateUser:
public MembershipUser CreateUser(string username, string password, string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  User user = new User();

  user.UserName = username;
  user.Email = email;
  user.Password = password;
  user.PasswordSalt = "1234";
  user.CreatedDate = DateTime.Now;
  user.IsActivated = false;
  user.IsLockedOut = false;
  user.LastLockedOutDate = DateTime.Now;
  user.LastLoginDate = DateTime.Now;

  db.AddToUsers(user);
  db.SaveChanges();

  return GetUser(username);
 }
}
We can see that our UserRepository CreateUser method uses Entity Data Model (CustomMembershipDB) we created earlier. We will come back to hasing and salting the password in the next part of the tutorial.
It creates User object, saves it to DB and returns user object of MembershipUser type.
In case you’re wondering why we assign DateTime.Now values to LastLockedOutDate and LastLoginDate. This is because in default MembershipUser type these properties are not Nullable, which means that they can’t store NULL values. There is a way to implement DateTime? nullable type but for the simplicity we’ll just populate the fields with current time on user creation.
GetUserNameByEmail:
public string GetUserNameByEmail(string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  var result = from u in db.Users where (u.Email == email) select u;

  if (result.Count() != 0)
  {
   var dbuser = result.FirstOrDefault();

   return dbuser.UserName;
  }
  else
  {
   return "";
  }
 }
}
GetUser:
public MembershipUser GetUser(string username)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  var result = from u in db.Users where (u.UserName == username) select u;

  if (result.Count() != 0)
  {
   var dbuser = result.FirstOrDefault();

   string _username = dbuser.UserName;
   int _providerUserKey = dbuser.UserId;
   string _email = dbuser.Email;
   string _passwordQuestion = "";
   string _comment = dbuser.Comments;
   bool _isApproved = dbuser.IsActivated;
   bool _isLockedOut = dbuser.IsLockedOut;
   DateTime _creationDate = dbuser.CreatedDate;
   DateTime _lastLoginDate = dbuser.LastLoginDate;
   DateTime _lastActivityDate = DateTime.Now;
   DateTime _lastPasswordChangedDate = DateTime.Now;
   DateTime _lastLockedOutDate = dbuser.LastLockedOutDate;

   MembershipUser user = new MembershipUser("CustomMembershipProvider",
                                             _username,
                                             _providerUserKey,
                                             _email,
                                             _passwordQuestion,
                                             _comment,
                                             _isApproved,
                                             _isLockedOut,
                                             _creationDate,
                                             _lastLoginDate,
                                             _lastActivityDate,
                                             _lastPasswordChangedDate,
                                             _lastLockedOutDate);

   return user;
  }
  else
  {
   return null;
  }
 }
}
Again, we can see that some of the properties get DateTime.Now value, and again this is becauseMembershipUser constructor needs the values and can’t accept NULLs.
So basically what the method does is; It connects to database and reads the user data; It then generates newMembershipUser object with properties from database and finally it returns the object.
UserRepository class can be downloaded here:
Now, let’s go back to MyMembershipProvider.cs, add the reference to CustomMembership.Models namespace
using CustomMembership.Models;
and implement the following methods:
GetUserNameByEmail:
public override string GetUserNameByEmail(string email)
{
 UserRepository _user = new UserRepository();

 return _user.GetUserNameByEmail(email);
}
GetUser(string username, bool userIsOnline) - (not the one with userProviderKey argument):
public override MembershipUser GetUser(string username, bool userIsOnline)
{
 UserRepository _user = new UserRepository();

 return _user.GetUser(username);
}
and finally CreateUser itself:
public override MembershipUser CreateUser(string username,
                                          string password,
                                          string email,
                                          string passwordQuestion,
                                          string passwordAnswer,
                                          bool isApproved,
                                          object providerUserKey,
                                          out MembershipCreateStatus status)
{
 ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username,
                                                                password,
                                                                true);

 OnValidatingPassword(args);

 if (args.Cancel)
 {
  status = MembershipCreateStatus.InvalidPassword;
  return null;
 }

 if (RequiresUniqueEmail && GetUserNameByEmail(email) != "")
 {
  status = MembershipCreateStatus.DuplicateEmail;
  return null;
 }

 MembershipUser u = GetUser(username, false);

 if (u == null)
 {
  UserRepository _user = new UserRepository();

  _user.CreateUser(username, password, email);
  status = MembershipCreateStatus.Success;

  return GetUser(username, false);
 }
 else
 {
  status = MembershipCreateStatus.DuplicateUserName;
 }

 return null;
}
MyMembershipProvider class up to this point in the tutorial can be downloaded here:
At this point, we should be able to register using the registration form of our application (Log In -> Regsiter – or /Account/Register link) and check directly in the database if the account has been created.
It would also be easy enough to modify ValidateUser method to validate against the database but because there is still few things we need to do during user creation process (hash the passwords and generate salt for example) we will leave it for the next part of the tutorial.
Continue to:

MVC 2 Custom Membership Provider Tutorial – Part 3


In the previous part of the tutorial we implemented CreateUser method which successfully creates new user in the database.
First thing we want to do now is to generate password salt.
Open UserRepository.cs, and add a reference to System.Security.Cryptography:
using System.Security.Cryptography;
and function to generate the salt (within UserRepository class):
private static string CreateSalt()
{
  RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  byte[] buff = new byte[32];
  rng.GetBytes(buff);

  return Convert.ToBase64String(buff);
}
Finally,change the CreateUser method to generate and save the salt to database with other user data.
public MembershipUser CreateUser(string username, string password, string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  User user = new User();

  user.UserName = username;
  user.Email = email;
  user.Password = password;
  user.PasswordSalt = CreateSalt();
  user.CreatedDate = DateTime.Now;
  user.IsActivated = false;
  user.IsLockedOut = false;
  user.LastLockedOutDate = DateTime.Now;
  user.LastLoginDate = DateTime.Now;

  db.AddToUsers(user);
  db.SaveChanges();

  return GetUser(username);
 }
}
We can go ahead and try it. Run your application and register new user account. If you check the database you will see random salt generated during the registration.
Now, let’s hash the password. Add the following code to UserRepository class:
private static string CreatePasswordHash(string pwd, string salt)
{
 string saltAndPwd = String.Concat(pwd, salt);
 string hashedPwd =
         FormsAuthentication.HashPasswordForStoringInConfigFile(
         saltAndPwd, "sha1");
 return hashedPwd;
}
and modify CreateUser method again to store hashed password. Because we’re going to useuser.passwordSalt property as an argument in CreatePasswordHash method we need to reorder the properties so the salt gets generated before the password is hashed:
public MembershipUser CreateUser(string username, string password, string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
   User user = new User();

   user.UserName = username;
   user.Email = email;
   user.PasswordSalt = CreateSalt();
   user.Password = CreatePasswordHash(password, user.PasswordSalt);
   user.CreatedDate = DateTime.Now;
   user.IsActivated = false;
   user.IsLockedOut = false;
   user.LastLockedOutDate = DateTime.Now;
   user.LastLoginDate = DateTime.Now;

   db.AddToUsers(user);
   db.SaveChanges();

   return GetUser(username);
 }
}
I am aware that this is probably not the best method to hash the password and that the hashing and salt generating methods can be improved but this is not the point of this tutorial so I’ll leave it as it is.
The UserRepository.cs file up to this point in the tutorial can be downloaded here:
We now have hashed password and salt stored in the database so let’s implement ValidateUser method properly.
Create ValidateUser method in UserRepository class:
public bool ValidateUser(string username, string password)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  var result = from u in db.Users where (u.UserName == username) select u;

  if (result.Count() != 0)
  {
   var dbuser = result.First();

   if (dbuser.Password == CreatePasswordHash(password, dbuser.PasswordSalt))
    return true;
   else
    return false;
  }
  else
  {
   return false;
  }
 }
}
and modify ValidateUser method in MyMembershipProvider class:
public override bool ValidateUser(string username, string password)
{
 UserRepository _user = new UserRepository();

 return _user.ValidateUser(username, password);
}
At this point we can run the application, register new account, log off and log in with it.
By the way, let’s tweak our application so it doesn’t log newly registered users in after the registration automatically.
We will want our users to activate the account by clicking the link in an email. Until activated user will not be able to log in (we will implement that in a second too).
Let’s create a View that will be displayed to users after the registration.
Open HomeController.cs file, and add Welcome method:
public ActionResult Welcome()
{
 return View();
}
Right click on Welcome() and Add View…
In the View, add a message to newly registered users:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

 <h2>Welcome</h2>

 <p>Thank you for registering!</p>

 <p>Activation email has been sent to you. Click on the link in
 the email to activate your account!</p>

</asp:Content>
Now, open AccountController.cs file, locate Register method and change:
if (createStatus == MembershipCreateStatus.Success)
{
 FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
 return RedirectToAction("Index", "Home");
}
so it looks like this:
if (createStatus == MembershipCreateStatus.Success)
{
 return RedirectToAction("Welcome", "Home");
}
If we run our application now and register new account we will not end up being logged in and we will be redirected to the Welcome page. Great!
Let’s generate email activation key and store it with the user data in the database.
Add the following method to UserRepository class:
private static string GenerateKey()
{
 Guid emailKey = Guid.NewGuid();

 return emailKey.ToString();
}
and modify the CreateUser method so the key is saved to the database (In the NewEmailKey column):
public MembershipUser CreateUser(string username, string password, string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  User user = new User();

  user.UserName = username;
  user.Email = email;
  user.PasswordSalt = CreateSalt();
  user.Password = CreatePasswordHash(password, user.PasswordSalt);
  user.CreatedDate = DateTime.Now;
  user.IsActivated = false;
  user.IsLockedOut = false;
  user.LastLockedOutDate = DateTime.Now;
  user.LastLoginDate = DateTime.Now;
  user.NewEmailKey = GenerateKey();

  db.AddToUsers(user);
  db.SaveChanges();

  return GetUser(username);
 }
}
Now, the activation key is generated we will email the activation link to the user.
For the purpose of this tutorial I will implement the email code directly into UserRepository class. In real world scenario you would ideally want to keep the email class separate. You would also want to add some sort of error handling for the email class.
You will also need an SMTP server that allows relaying messages. When you run the application on the Web Server from an ISP, usually it has SMTP role installed and you can use localhost as a server. This isn’t the case with Web Server installed with Visual Web Developer so you will need to find a server which will allow the application to send emails.
First, add a reference to System.Net.Mail namespace (UserRepository.cs):
using System.Net.Mail;
In CreateUser method, add the following code:
public MembershipUser CreateUser(string username, string password, string email)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  User user = new User();

  user.UserName = username;
  user.Email = email;
  user.PasswordSalt = CreateSalt();
  user.Password = CreatePasswordHash(password, user.PasswordSalt);
  user.CreatedDate = DateTime.Now;
  user.IsActivated = false;
  user.IsLockedOut = false;
  user.LastLockedOutDate = DateTime.Now;
  user.LastLoginDate = DateTime.Now;
  user.NewEmailKey = GenerateKey();

  db.AddToUsers(user);
  db.SaveChanges(); 

  string ActivationLink = "http://localhost:PORT/Account/Activate/" +
                                      user.UserName + "/" + user.NewEmailKey;

  var message = new MailMessage("EMAIL_FROM", user.Email)
  {
   Subject = "Activate your account",
   Body = ActivationLink
  };

  var client = new SmtpClient("SERVER");
  client.Credentials = new System.Net.NetworkCredential("USERNAME", "PASSWORD");
  client.UseDefaultCredentials = false;

  client.Send(message);

  return GetUser(username);
 }
}
You will need to replace PORT (with your local application port name or remove if on live server), EMAIL_FROM, SERVER, USERNAME and PASSWORD values.
If during registration process the application throws an exception like this:
That means that the server doesn’t allow relaying and you need to find another server (not easy I know).
Once you’ll get past this step (manually removing all created up to this point accounts from the database), you will receive an email with the link.
So let’s add the activation functionality to the AccountController.
Open AccountController.cs and add the following code:
// **************************************
// URL: /Account/Activate/username/key
// **************************************

public ActionResult Activate(string username, string key)
{
 UserRepository _user = new UserRepository();
 if (_user.ActivateUser(username, key) == false)
  return RedirectToAction("Index", "Home");
 else
  return RedirectToAction("LogOn");
}
For the activation Url to work we will need to edit Global.asax.cs file and add the following route:
routes.MapRoute(
 "Activate",
 "Account/Activate/{username}/{key}",
 new { controller = "Account", action = "Activate",
 username = UrlParameter.Optional, key = UrlParameter.Optional } );
And finally, ActivateUser method in UserRepository class:
public bool ActivateUser(string username, string key)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  var result = from u in db.Users where (u.UserName == username) select u;

  if (result.Count() != 0)
  {
   var dbuser = result.First();

   if (dbuser.NewEmailKey == key)
   {
    dbuser.IsActivated = true;
    dbuser.LastModifiedDate = DateTime.Now;
    dbuser.NewEmailKey = null;

    db.SaveChanges();

    return true;
   }
   else
   {
    return false;
   }

  }
  else
  {
   return false;
  }
 }
}
Now, let’s modify ValidateUser method so it will only authenticate activated users:
public bool ValidateUser(string username, string password)
{
 using (CustomMembershipDB db = new CustomMembershipDB())
 {
  var result = from u in db.Users where (u.UserName == username) select u;

  if (result.Count() != 0)
  {
   var dbuser = result.First();

   if (dbuser.Password == CreatePasswordHash(password, dbuser.PasswordSalt) &&
                                                       dbuser.IsActivated == true)
    return true;
   else
    return false;
  }
  else
  {
   return false;
  }
 }
}
Run the application and register 2 user accounts. Validate one of them using the link from the email. You will be able to log in only using the activated account.
In the next part of the tutorial we will add some error handling as well as some Views to support implemented processes.
Sorry folks! Due to new role I have taken, I won’t be able to continue this tutorial any time soon.
Files at the end of this part of the tutorial:

Tuesday, June 18, 2013

Print GridView Data

Print DataGridView data or particular control's data from web page

Introduction

This tip explains how to print a particular web control's data from a web page.

Background

I have tried to open a new page and use JavaScript to print the web page, but all the web page controls are printed using document.windows.print().

Using the code

<script>
function PrintCasedata() {
// var prtGrid1 = document.getElementById("<%= GridView1.ClientID %>");
var prtGrid1 = document.getElementById("<%= Panel1.ClientID %>");

// document.getElementById("GridView1");
//prtGrid1.border = 1;
var prtwin = window.open('', 'PrintCasedata', 
  'left=100,top=100,width=1000,height=1000,tollbar=0,scrollbars=1,status=0,resizable=1');
prtwin.document.write(prtGrid1.outerHTML);
prtwin.document.close();
prtwin.focus();
prtwin.print();
prtwin.close();
}
</script>
On this button I have added code tp print the DataGridView.
<asp:Button ID="btnPrint" runat="server" 
  OnClick="btnPrint_Click" Text="Print" 
  Height="26px" Width="42px" />
Use the following code at codebehind:
protected void btnPrint_Click(object sender, EventArgs e)
{
  //ScriptManager.RegisterStartupScript(this,
  //      this.GetType(), "mymessage", "Myprint(" + ");", true);
  ScriptManager.RegisterStartupScript(this, this.GetType(),
          "mymessage", "PrintCasedata(" + ");", true);
}
Using this code we can print the formatted web page,  i.e. we want the logo on the print, the date, and user name. So we need to collect all controls which need to print on one panel or group box. And then replace the id inGroupControlID.
var prtGrid1 = document.getElementById("<%= GroupControlID.ClientID %>");

GridView Export to PDF file

jQGrid PDF Export


The aim of this article is to address the PDF export from client side grid frameworks. The solution is done using theiTextSharp in ASP.NET MVC 4 and Visual Studio 2012. jQGrid is one of the client grid framework built on top of the jQuery framework. It helps in building a beautiful grid with paging, sorting and exiting options. There are also other features available as extension plugins and developers can write their own if needed. Please do a nuget update before running the demo code.

Background

The article assumes the developer to have a fair amount of knowledge on ASP.NET MVC and C#.
Tools used:
  • Visual Studio 2012
  • ASP.Net MVC 4
  • Nuget Package Manager
Developers can learn about the jQuery and jQueryUI at http://jquery.com/
jQgrid related wiki can be found at below links:
iTextSharp tutorials can be found at the following link

Using the code

You can download the JQgrid from the jQGrid homepage or as NUget package. I have given below the command to download the jQGrid through the package manager console. From the tools menu select “Library Package Manager” and then select “Package Manager Console”. I have given the screenshot below.


This command will pull down the latest JQGrid package and adds them in the script folder.

Once the script is downloaded and referenced in the project update the bundleconfig file to add the script reference in the pages. Bundleconfig can be found in the App_Start folder in the project structure. .
bundles.Add(new StyleBundle("~/Content/jqgrid").Include("~/Content/ui.jqgrid.css")); 
bundles.Add(new ScriptBundle("~/bundles/jquerygrid").Include(
  "~/Scripts/jqGrid/jquery.jqGrid*"));
Once added the config’s refer the bundles to the Views/Shared/LayoutPage.cshtml. Add the following lines to the head section of the page.
@Styles.Render("~/Content/jqgrid</a />")
Add the following lines to the end of the page before html close tags.
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/bundles/jquerygrid") 
That’s all to be done from the view perspective. Once these steps are done the developer can start coding for the JQGrid. In this example we will modify the HomeController for the demo. The index action will be the default action. We will add an argument for this index action. Let it be nullable bool. It’s just to mark the pdf request. In the Index.cshtml we will add a table tag with an id “gridTable”. We will use this table for making the grid. Since jQGrid is an extension for the JQUery we will initialize the grid setting at the script section of the page. This script section is marked at the end of the page to improve performance. The script section is placed just below the bundle reference for JQuery and JQueryUI. This is the one of improvement factors from “why slow” provided by yahoo.
<table id="gridTable" class="scroll"></table>
<input type="button" value="Export PDF" onclick="exportPDF();" />
@section scripts
{
<script type="text/javascript">
$(document).ready(
function ()
{
$("#gridTable").jqGrid(
{
datatype: "json",
url: <a href="mailto:'@Url.Action(%22GetCustomerDetails%22)'">
  '@Url.Action("GetCustomerDetails")'</a />,
mtype: 'GET',
colNames: ["CustomerID", "CustomerName", 
   "Location", "PrimaryBusiness"],
colModel: [
{name:"CustomerID",width:40,index:"CustomerID",align:"center"},
{ name: "CustomerName", width: 40, index: "CustomerName", align: "center" },
{ name: "Location", width: 40, index: "Location", align: "center" },
{ name: "PrimaryBusiness", width: 40, index: "PrimaryBusiness", align: "center" },
],
height: 250,
autowidth: true,
sortorder: "asc",
rowNum: 10,
rowList: [5, 10, 15, 20],
sortname: "CustomerID",
sortorder: "desc",
viewrecords:true 
}
);
}
);function exportPDF() {
<a href="mailto:document.location='@Url.Action(%22Index%22)?pdf=true'">
  document.location='@Url.Action("Index")?pdf=true'</a />;
}
</script>}
The exportPDF methos just sets the document location to the Index action method with PDF Boolean as true just to mark for download PDF. An inmemory list collection is used for demo purpose. The GetCustomerDetails method is the server side action method that will provide the data as JSON list. We will see the method explanation below.
[HttpGet]
public JsonResult GetCustomerDetails()
{
    Var result = new
    {
        total = 1,
        page = 1,
        records = customerList.Count(),
        rows =(
        customerList.Select(e=>
        new {id=e.CustomerID,cell=new string[]{
          e.CustomerID.ToString(),e.CustomerName,e.Location,e.PrimaryBusiness}})
        ).ToArray()
    };
    return Json(result, JsonRequestBehavior.AllowGet);
}
jQGrid can understand the response data from server in certain format. The server method shown above is taking care of formatting the response so that JQGrid understand the data properly. The response data should contain total pages, current page, full record count, rows of data with ID and remaining columns as string array. The response is built using an anonymous object and will be sent as a MVC JsonResult. Since we are using HttpGet it’s better to mark the attribute as HttpGet and also the JSON requestbehavious as AllowGet. The in-memory list is initialized in the homecontroller constructor for reference.
public class HomeController : Controller
{
    private readonly IList<CustomerViewModel> customerList;
    public HomeController()
    {
        customerList =new List<CustomerViewModel>() {
        new CustomerViewModel{CustomerID=100,
          CustomerName="Sundar",Location="Chennai",PrimaryBusiness="Teacing"},
        new CustomerViewModel{CustomerID=101,
          CustomerName="Sudhagar",Location="Chennai",PrimaryBusiness="Software"},
        new CustomerViewModel{CustomerID=102,
          CustomerName="Thivagar",Location="China",PrimaryBusiness="SAP"},
    };
    }
    public ActionResult Index(bool? pdf)
    {
        if (!pdf.HasValue)
        {
            return View(customerList);
        }
        else
        {
            string filePath = Server.MapPath("Content") + "Sample.pdf";
            ExportPDF(customerList, new string[] { "CustomerID", 
              "CustomerName", "Location", "PrimaryBusiness" }, filePath);
            return File(filePath, "application/pdf","list.pdf"); 
        }
    }
} 
The index actionmethod has a Boolean argument named “pdf”. It’s used to indicate for PDF download. When the application starts this method is first hit for initial page request. For PDF operation a filename is generated and then sent to the ExportPDF method which will take care of generating the PDF from the datasource. The ExportPDF method is listed below. This is a generic method which can handle any data source. since column names are passed as argument there is no need to worry about the property names.
private static void ExportPDF<TSource>(IList<TSource> customerList,string[] columns, string filePath)
{
    Font headerFont = FontFactory.GetFont("Verdana", 10, Color.WHITE);
    Font rowfont = FontFactory.GetFont("Verdana", 10, Color.BLUE);
    Document document = new Document(PageSize.A4);
    PdfWriter writer = PdfWriter.GetInstance(document, 
               new FileStream(filePath, FileMode.OpenOrCreate));
    document.Open();
    PdfPTable table = new PdfPTable(columns.Length);
    foreach (var column in columns)
    {
        PdfPCell cell = new PdfPCell(new Phrase(column, headerFont));
        cell.BackgroundColor = Color.BLACK;
        table.AddCell(cell);
    }
    
    foreach (var item in customerList)
    {
        foreach (var column in columns)
        {
            string value = item.GetType().GetProperty(column).GetValue(item).ToString();
            PdfPCell cell5 = new PdfPCell(new Phrase(value, rowfont));
            table.AddCell(cell5);
        } 
    }
    document.Add(table);
    document.Close();
}
iTextSharp is one of the pioneer in PDF export. It’s an opensource library readily available as NUget library.

This command will pulldown latest available library. I am using the version 4.1.2.0. The latest version may have changed. There are three main things in this library.
  • Document: This is the document class which takes care of creating the document sheet with particular size. We have used A4 size. There is also an option to define the rectangle size. This document instance will be further used in next methods for reference.
  • PdfWriter: PdfWriter takes the filename and the document as the reference. This class enables the document class to generate the PDF content and save them in a file.
  • Font: Using the FONT class the developer can control the font features. Since I need a nice looking font I am giving the Verdana font.
Following this PdfPTable and PdfPCell are used for generating the normal table layout. We have created two set of fonts for header and footer.
Font headerFont = FontFactory.GetFont("Verdana", 10, Color.WHITE);
Font rowfont = FontFactory.GetFont("Verdana", 10, Color.BLUE);
We are getting the header columns as string array. Columns argument array is looped and header is generated. We are using the headerfont for this purpose.
PdfWriter writer = 
   PdfWriter.GetInstance(document, new FileStream(filePath, FileMode.OpenOrCreate));
document.Open();
PdfPTable table = new PdfPTable(columns.Length);
foreach (var column in columns)
{
    PdfPCell cell = new PdfPCell(new Phrase(column, headerFont));
    cell.BackgroundColor = Color.BLACK;
    table.AddCell(cell);
}
Then reflection is used to generate the row wise details and form the grid.
foreach (var item in customerList)
{
    foreach (var column in columns)
    {
        string value = item.GetType().GetProperty(column).GetValue(item).ToString();
        PdfPCell cell5 = new PdfPCell(new Phrase(value, rowfont));
        table.AddCell(cell5);
    } 
}
document.Add(table);
document.Close();
Once the process id done the pdf table is added to the document and document is closed to write all the changes to the filepath given. Then the control moves to the controller which will take care of sending the response as a JSON result with a filename. If the file name is not given then the PDF will open in the same page otherwise a popup will open up asking whether to save the file or open file.
return File(filePath, "application/pdf","list.pdf");
The final result screen is shown below.

PDF file opened below to show the output.

Conclusion

This is how the export pdf is done for JQGrid. The problem area that is addressed here is the clientside grid frameworks won’t support PDF’s export. In that time it’s better to have a fine grained control over the data and generated PDF.iTextSharp has helped us to achieve our goal.