Home Interviews Developers Our View Feeds The List

LiveSide - Developer Blog

July 2007 - Posts

  • Windows Live Quick Apps and New Live Partner Initiative

    At the World Partner Conference in Denver today, they took a look at Windows Live and the opportunities that are there for companies to take advantage of the services that are offered by Windows Live. They showed off two applications that had been built by two UK Microsoft Partners, AWS and Conchango. The apps themselves have been built using technologies like Silverlight (in particular the streaming service) and Virtual Earth (Live Local's engine), and they basically show off how Windows Live services can be used for things like clubs and organisations, and even in the education sector.

    "Contoso Bicycle Club"

    "Contoso University"

    bikeclub

    uni

    What's even better about both of these demos, is not only how cool they are to use, but the entire source code for them is publicly available on Codeplex. If you would like to read more from the teams who have made these apps, James has a few quotes from them on his blog.

    Now, I also mention the Windows Live Partner Initiative, as Microsoft tries to reach to some of their partners and showing them the benefits that can be had from using Windows Live. With it comes two new sites, http://partner.live.com/ and http://www.innovateonwindowslive.com/, and all this comes hot on the heels of the Partner Bot that the UK Partner team made, which Steve Clayton talks about, and can be added to your Messenger list by adding partnerbot@hotmail.com to your contact list.

    And just to finish off with, for those that want even further Windows Live development information at their fingertips, Wrox have a book dedicated to Windows Live programming which covers all major aspects of taking on projects that use the Windows Live services.

    Useful Links

    http://dev.live.com/QuickApps - Home page for the new Quick Apps demos;
    http://www.codeplex.com/WLQuickApps - Quick Apps home page on Codeplex;
    http://www.innovateonwindowslive.com/ - Information about the opportunity of developing using Live Services;
    http://partner.live.com/ - Partner resources for developing on Windows Live;
    http://blogs.msdn.com/stevecla01/archive/2007/06/20/finally-partnerbot-is-live.aspx - Information on the Partner Bot.

    SL

  • Windows Live ID - Part 2 - Membership Provider

    In the first part of this article I explained how to integrate Windows Live ID into your own web site, how to call it and what information it returned and how to access that information.

    Now that is all fine and well but if you're using ASP.Net 2.0 (and above) and you want to take advantage of the inbuilt memberships, roles etc. the information returned from Live ID doesn't make this easy on you. So how do you do this? Well there are a number of different ways to do this but possibly the easiest is to create your own MemberShip provider and use to store and access the information.

    In this article we will be building a Membership provider that you can call with the very basic information that Live ID returns to you (basically the only useful thing it returns is a static ID string that will always be consistent for your registered web site.

    Extending or building your own MemberShip provider isn't that hard, you simply create a new class that inherits from MembershipProvider and override the methods with your own code. Unfortunately there is a fair amount of code to this but most of it is fairly intuitive.

    A couple of Notes before we proceed :-

    1. In my membership provider I take advantage of the Microsoft Patterns and Practices Enterprise objects for data access. This is a very good and useful code block that saves you from manually having to open and close database connections etc. It's also completely free and can be downloaded from here. Remember you will need to copy the appropriate dll files into the bin folder of your web application and set references to them.
    2. There are a few things that you will have to do on your own depending on the information that you wish to collect from the user. I explained in a basic outline how to do this is in the previous article. Basically once a user signs in using Live ID, you should redirect to a Registration page on your site. The first thing you want to do is to check to see if the user already exists (ValidateUser method). If they do then great you can redirect the user back to where ever it was they wanted to go in your site, if not then you will want to display a form to collect the information you wish. At the minimum you will need an Email address then you create the user in your database using the CreateUser method.
    3. As a lot of the methods in the Membership provider are fairly self explanatory, I won't take time to explain them all, they all follow the same or similar concepts as the ones I will explain.

    So lets start. Create a new Class library file in your App_Code directory and name it LiveIDMembershipProvider.cs.
    Now we import some base libraries.

    using System;

    using System.Data;

    using System.Data.SqlClient;

    using System.Configuration;

    using System.Web;

    using System.Web.Security;

    using Microsoft.Practices.EnterpriseLibrary.Data;

    using System.Collections.Generic;

    using System.Collections.Specialized;

    using System.Configuration.Provider;

    using System.Web.Hosting;

    using System.Web.Management;

    using System.Security.Permissions;

    Note the reference to Microsoft.Practices.EnterpriseLibrary.Data which was explained above. Next create your class :-

    namespace Hackersoft.UserRepository

    {

      public class LiveIDMembershipProvider : MembershipProvider

      {

    You can give your class any namespace you wish and in the class declaration we are stating that we want to inherit from MembershipProvider.

    Create some class member variables :-

        static string m_ProviderName = "LiveIDMembershipProvider";

        static int m_InvalidPasswordAttempts = 1;

        static int m_NonAlphaCharacters = 0;

        static int m_PasswordLength = 3;

        static int m_PasswordAttemptWindow = 5;

        private string m_ApplicationName = string.Empty;

     

    The m_ProviderName variable you can set to whatever you like. The other variables are fairly self explanatory, the number of password attempts you will allow doesn't really count as we will be using Live ID for authentication, same with PasswordLength which states the minimum length of the password. We will be using a hashed version of the user ID returned by Live ID as the password.

     

    Next we add some public properties to set or read (mostly read) the member variables above. The only one which is read/write is the Application Name. The way that the .Net database is setup is that you can have multiple sites running off a single database and authentication against a specific site is done by passing through the name of the application that you wish to authenticate against.

      public override string ApplicationName

        {

          get

          {

            return m_ApplicationName;

          }

          set

          {

            m_ApplicationName = value;

          }

        }

     

        public override bool EnablePasswordRetrieval

        {

          get { return false; }

        }

     

        public override bool EnablePasswordReset

        {

          get { return false; }

        }

     

        public override int MaxInvalidPasswordAttempts

        {

          get { return m_InvalidPasswordAttempts; }

        }

     

        public override int MinRequiredNonAlphanumericCharacters

        {

          get { return m_NonAlphaCharacters; }

        }

     

        public override int MinRequiredPasswordLength

        {

          get { return m_PasswordLength; }

        }

     

        public override int PasswordAttemptWindow

        {

          get { return m_PasswordAttemptWindow; }

        }

     

        public override MembershipPasswordFormat PasswordFormat

        {

          get { return MembershipPasswordFormat.Clear; }

        }

     

        public override string PasswordStrengthRegularExpression

        {

          get { throw new NotSupportedException(); }

        }

     

        public override bool RequiresQuestionAndAnswer

        {

          get { return false; }

        }

     

        public override bool RequiresUniqueEmail

        {

          get { return true; }

        }

    The first method in your custom membership provider that you will want to override is the CreateUser method :-

        public MembershipUser CreateUser(string username, string password, string applicationname,

          string email, string passwordquestion, string passwordanswer, out int status)

        {

          //This calls the Membership_CreateUser SPROC.

          //The CreateUser SPROC will automatically create an application if one doesn't exist

          //Create the User account and also create the Membership account.

          //The output to this is the newly created UserID.

          string UserID = string.Empty;

          string PasswordSalt = CreateSalt(5);

          string PasswordHash = CreatePasswordHash(password, PasswordSalt);

          status = 0;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_CreateUser");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@UserName", username);

          cmdSQL.Parameters.AddWithValue("@Password", PasswordHash);

          cmdSQL.Parameters.AddWithValue("@PassWordSalt", PasswordSalt);

          cmdSQL.Parameters.AddWithValue("@Email", email);

          cmdSQL.Parameters.AddWithValue("@PasswordQuestion", passwordquestion);

          cmdSQL.Parameters.AddWithValue("@PasswordAnswer", passwordanswer);

          cmdSQL.Parameters.AddWithValue("@IsApproved", 1);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@CreateDate", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UniqueEmail", 1);

          cmdSQL.Parameters.AddWithValue("@PasswordFormat", MembershipPasswordFormat.Clear);

          SqlParameter output = new SqlParameter("@UserID", SqlDbType.UniqueIdentifier);

          output.Direction = ParameterDirection.Output;

          cmdSQL.Parameters.Add(output);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          try

          {

     

            status = Convert.ToInt32(db.ExecuteNonQuery(cmdSQL));

            UserID = cmdSQL.Parameters["@UserID"].Value.ToString();

     

          }

          catch (Exception ex)

          {

            //put your exception handling here

          }

          MembershipUser user = GetUser(new Guid(UserID), true);

          //status = Error;

          return user;

        }

    This method returns a Membership user object (which is ultimately what you want). We call the standard SQL stored procedure provided for us and are simply poking our own custom values into this. The four main parameters that you will need to provide are username, password, application name and email. Both username and password will be the user ID returned from the Live ID service, Application Name will be the name of your application (see above for short explanation) and email is the minimum data that you must collect from the user on your registration page. Password question and password answer you can simply set to string.Empty.
    So the first thing that we do is call a helper methods to create a password hash and salt so that the password is essentially encrypted (remember that the password we use will the same as the username, the user ID returned from Live ID). Next we call our Enterprise library to create a connection to the database then create a SqlCommand object stating that we wish to call the "aspnet_Membership_CreateUser" stored procedure and simply plug our data into the parameters that it expects.
    After the stored procedure has been called it will return a unique user ID for this user. With this User ID we can call the GetUser method to create an actual MembershipUser object and then simply return this MembershipUser object.  That's it, fairly simple stuff.
    The CreatePasswordHash and CreateSalt methods aren't very interesting so I'll just include them in the full code listing at the end of this article.

    There are two overrides of the GetUser method, the one that we called in the CreateUser method above takes the UserID (as a GUID) and a flag indicating whether the user is online or not and returns a MembershipUser object.

        public override MembershipUser GetUser(object provideruserkey, bool userisonline)

        {

          MembershipUser user = null;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetUserByUserId");

          cmdSQL.Parameters.AddWithValue("@UserID", provideruserkey);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UpdateLastActivity", userisonline);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          DataSet ds = db.ExecuteDataSet(cmdSQL);

          if(ds.Tables[0].Rows.Count > 0)

          {

            DataRow dr = ds.Tables[0].Rows[0];

            user = new MembershipUser(m_ProviderName, dr["UserName"].ToString(),

            provideruserkey, dr["Email"].ToString(), dr["PasswordQuestion"].ToString(),

            dr["Comment"].ToString(), Convert.ToBoolean(dr["IsApproved"]),

            Convert.ToBoolean(dr["IsLockedOut"]), Convert.ToDateTime(dr["CreateDate"]),

            Convert.ToDateTime(dr["LastLoginDate"]), Convert.ToDateTime(dr["LastActivityDate"]),

            Convert.ToDateTime(dr["LastPasswordChangedDate"]), Convert.ToDateTime(dr["LastLockoutDate"]));

          }

          return user;

        }

     

    As you can see, this is fairly much the same story as the CreateUser method described above. We call the Enterprise to create a connection to the database, create a SqlCommand object and tell it that we wish to call the "aspnet_Membership_GetUserByUserId" stored procedure, fill in the parameters that it expects then call the stored procedure. The real change from the CreateUser method described above is that once the database call has returned, we need to actually instantiate a MembershipUser object. The MembershipUser object expects a lot of parameters however all the information required is returned to us in the dataset from the database call. We simply plug these values in and have a now have a valid MembershipUser object.

     

    The second override of the GetUser method is very much the same but instead of passing in a User ID we pass in the username, name of the application and again whether the user is online or not.

     

    public MembershipUser GetUser(string username, string applicationname, bool userisonline)

        {

          MembershipUser user = null;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetUserByName");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@Username", username);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UpdateLastActivity", userisonline);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          DataSet ds = db.ExecuteDataSet(cmdSQL);

          if (ds.Tables[0].Rows.Count > 0)

          {

            DataRow dr = ds.Tables[0].Rows[0];

            user = new MembershipUser(m_ProviderName, username,

            new Guid(dr["UserID"].ToString()), dr["Email"].ToString(), dr["PasswordQuestion"].ToString(),

            dr["Comment"].ToString(), Convert.ToBoolean(dr["IsApproved"]),

            Convert.ToBoolean(dr["IsLockedOut"]), Convert.ToDateTime(dr["CreateDate"]),

            Convert.ToDateTime(dr["LastLoginDate"]), Convert.ToDateTime(dr["LastActivityDate"]),

            Convert.ToDateTime(dr["LastPasswordChangeDate"]), Convert.ToDateTime(dr["LastLockoutDate"]));

          }

          return user;

        }

    The final method that I will describe is the ValidateUser method. Again it's not too difficult to follow :-

        public bool ValidateUser(string username, string password, string applicationname)

        {

          try

          {

              //First thing you need to do is validate the application name and get the

              //application ID from the database.

              string PasswordHash = string.Empty;

              string PasswordSalt = string.Empty;

              string HashedPassword = string.Empty;

              string ApplicationID = GetApplicationID(applicationname);

              if (ApplicationID == null || ApplicationID == string.Empty)

              {

                //Cannot find the application name therefore the user cannot

                //Exist for this application

                return false;

              }

              //Next you need to retrieve the salt and hash from the database in order to

              //verify the password.

              Database db = DatabaseFactory.CreateDatabase();

              SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetPasswordWithFormat");

              cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

              cmdSQL.Parameters.AddWithValue("@Username", username);

              cmdSQL.Parameters.AddWithValue("@UpdateLastLoginActivityDate", 0);

              cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", System.DateTime.Now);

              DataSet ds = null;

              cmdSQL.CommandType = CommandType.StoredProcedure;

              ds = db.ExecuteDataSet(cmdSQL);

              if (ds.Tables[0].Rows.Count > 0)

              {

                DataRow dr = ds.Tables[0].Rows[0];

                //The database does not name it's returned rows.

                //The Salt is stored in the first field returned (Password field)

                //The Hash is stored in the 3rd field returned (PasswordSalt)

                PasswordHash = dr[0].ToString();

                PasswordSalt = dr[2].ToString();

              }

              else

              {

                //No rows were returned from the database therefore

                //User does not exist.

                return false;

              }

              //Now we hash the password supplied.

              HashedPassword = CreatePasswordHash(password, PasswordSalt);

              //Now simply compare the hashed password just generated with that stored

              //in the database.  If they match then username and password are correct

              //otherwise they are not.

              if (HashedPassword == PasswordHash)

              {

                return true;

              }

              else

              {

                return false;

              }

            }

          catch (Exception ex)

          {

            // TODO: Exception Handling routine

            return false;

          }

        }

    As you can see the ValidateUser method takes in the user name, password and the application name as parameters. We make a call to the GetApplicationID method which returns the internal application GUID. The reason we do this is to make sure that the application is actually registered in the database before we make the call to validate the user. This is basically a safety check. Again we call the Enterprise Library to create a connection to our Sql Database, create a SqlCommand object and tell it we wish to call the "aspnet_Membership_GetPasswordWithFormat" stored procedure, fill out the expected parameters and make the call. What we get in return is the password hash and salt we originally stored in the CreateUser method. Next we call the CreatePasswordHash algorithm again and pass through the password entered along with the Password Salt returned from the database call. If the returned password hash is the same as the password hash returned by the database call then the password is correct (which it really should be as the password and username are the same user ID returned by Live ID).

    All the rest of the methods in the code below follow the same principles as those explained above. Here is the full membership provider along with the helper methods mentioned above and any others referenced in the code :-

    using System;

    using System.Data;

    using System.Data.SqlClient;

    using System.Configuration;

    using System.Web;

    using System.Web.Security;

    using Microsoft.Practices.EnterpriseLibrary.Data;

    using System.Collections.Generic;

    using System.Collections.Specialized;

    using System.Configuration.Provider;

    using System.Web.Hosting;

    using System.Web.Management;

    using System.Security.Permissions;

     

    /// <summary>

    /// Custom Membership provider that authenticates against a

    /// central user repository

    /// </summary>

    namespace Hackersoft.UserRepository

    {

      public class LiveIDMembershipProvider : MembershipProvider

      {

        #region Properties

        public override string ApplicationName

        {

          get

          {

            return m_ApplicationName;

          }

          set

          {

            m_ApplicationName = value;

          }

        }

     

        public override bool EnablePasswordRetrieval

        {

          get { return false; }

        }

     

        public override bool EnablePasswordReset

        {

          get { return false; }

        }

     

        public override int MaxInvalidPasswordAttempts

        {

          get { return m_InvalidPasswordAttempts; }

        }

     

        public override int MinRequiredNonAlphanumericCharacters

        {

          get { return m_NonAlphaCharacters; }

        }

     

        public override int MinRequiredPasswordLength

        {

          get { return m_PasswordLength; }

        }

     

        public override int PasswordAttemptWindow

        {

          get { return m_PasswordAttemptWindow; }

        }

     

        public override MembershipPasswordFormat PasswordFormat

        {

          get { return MembershipPasswordFormat.Clear; }

        }

     

        public override string PasswordStrengthRegularExpression

        {

          get { throw new NotSupportedException(); }

        }

     

        public override bool RequiresQuestionAndAnswer

        {

          get { return false; }

        }

     

        public override bool RequiresUniqueEmail

        {

          get { return true; }

        }

        #endregion

     

        #region Member Variables

        static string m_ProviderName = "LiveIDMembershipProvider";

        static int m_InvalidPasswordAttempts = 5;

        static int m_NonAlphaCharacters = 0;

        static int m_PasswordLength = 3;

        static int m_PasswordAttemptWindow = 5;

        private string m_ApplicationName = string.Empty;

        #endregion

     

        public LiveIDMembershipProvider()

        {

          //

          // TODO: Add constructor logic here

          //

        }

     

        public MembershipUser CreateUser(string username, string password, string applicationname,

          string email, string passwordquestion, string passwordanswer, out int status)

        {

          //This calls the Membership_CreateUser SPROC.

          //The CreateUser SPROC will automatically create an application if one doesn't exist

          //Create the User account and also create the Membership account.

          //The output to this is the newly created UserID.

          string UserID = string.Empty;

          string PasswordSalt = CreateSalt(5);

          string PasswordHash = CreatePasswordHash(password, PasswordSalt);

          status = 0;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_CreateUser");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@UserName", username);

          cmdSQL.Parameters.AddWithValue("@Password", PasswordHash);

          cmdSQL.Parameters.AddWithValue("@PassWordSalt", PasswordSalt);

          cmdSQL.Parameters.AddWithValue("@Email", email);

          cmdSQL.Parameters.AddWithValue("@PasswordQuestion", passwordquestion);

          cmdSQL.Parameters.AddWithValue("@PasswordAnswer", passwordanswer);

          cmdSQL.Parameters.AddWithValue("@IsApproved", 1);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@CreateDate", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UniqueEmail", 1);

          cmdSQL.Parameters.AddWithValue("@PasswordFormat", MembershipPasswordFormat.Clear);

          SqlParameter output = new SqlParameter("@UserID", SqlDbType.UniqueIdentifier);

          output.Direction = ParameterDirection.Output;

          cmdSQL.Parameters.Add(output);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          try

          {

     

            status = Convert.ToInt32(db.ExecuteNonQuery(cmdSQL));

            UserID = cmdSQL.Parameters["@UserID"].Value.ToString();

     

          }

          catch (Exception ex)

          {

            Console.WriteLine(ex.Message.ToCharArray());

          }

          MembershipUser user = GetUser(new Guid(UserID), true);

          //status = Error;

          return user;

        }

     

        public override MembershipUser GetUser(object provideruserkey, bool userisonline)

        {

          MembershipUser user = null;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetUserByUserId");

          cmdSQL.Parameters.AddWithValue("@UserID", provideruserkey);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UpdateLastActivity", userisonline);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          DataSet ds = db.ExecuteDataSet(cmdSQL);

          if(ds.Tables[0].Rows.Count > 0)

          {

            DataRow dr = ds.Tables[0].Rows[0];

            user = new MembershipUser(m_ProviderName, dr["UserName"].ToString(),

            provideruserkey, dr["Email"].ToString(), dr["PasswordQuestion"].ToString(),

            dr["Comment"].ToString(), Convert.ToBoolean(dr["IsApproved"]),

            Convert.ToBoolean(dr["IsLockedOut"]), Convert.ToDateTime(dr["CreateDate"]),

            Convert.ToDateTime(dr["LastLoginDate"]), Convert.ToDateTime(dr["LastActivityDate"]),

            Convert.ToDateTime(dr["LastPasswordChangedDate"]), Convert.ToDateTime(dr["LastLockoutDate"]));

          }

          return user;

        }

     

        public MembershipUser GetUser(string username, string applicationname, bool userisonline)

        {

          MembershipUser user = null;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetUserByName");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@Username", username);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@UpdateLastActivity", userisonline);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          DataSet ds = db.ExecuteDataSet(cmdSQL);

          if (ds.Tables[0].Rows.Count > 0)

          {

            DataRow dr = ds.Tables[0].Rows[0];

            user = new MembershipUser(m_ProviderName, username,

            new Guid(dr["UserID"].ToString()), dr["Email"].ToString(), dr["PasswordQuestion"].ToString(),

            dr["Comment"].ToString(), Convert.ToBoolean(dr["IsApproved"]),

            Convert.ToBoolean(dr["IsLockedOut"]), Convert.ToDateTime(dr["CreateDate"]),

            Convert.ToDateTime(dr["LastLoginDate"]), Convert.ToDateTime(dr["LastActivityDate"]),

            Convert.ToDateTime(dr["LastPasswordChangeDate"]), Convert.ToDateTime(dr["LastLockoutDate"]));

          }

          return user;

        }

     

        public string GetUserNameByEmail(string email, string applicationname)

        {

          string Username = string.Empty;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetUserByEmail");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@Email", email);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          Username = Convert.ToString(db.ExecuteScalar(cmdSQL));

          return Username;

     

        }

     

        public bool ValidateUser(string username, string password, string applicationname)

        {

          try

          {

              //First thing you need to do is validate the application name and get the

              //application ID from the database.

              string PasswordHash = string.Empty;

              string PasswordSalt = string.Empty;

              string HashedPassword = string.Empty;

              string ApplicationID = GetApplicationID(applicationname);

              if (ApplicationID == null || ApplicationID == string.Empty)

              {

                //Cannot find the application name therefore the user cannot

                //Exist for this application

                return false;

              }

              //Next you need to retrieve the salt and hash from the database in order to

              //verify the password.

              Database db = DatabaseFactory.CreateDatabase();

              SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetPasswordWithFormat");

              cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

              cmdSQL.Parameters.AddWithValue("@Username", username);

              cmdSQL.Parameters.AddWithValue("@UpdateLastLoginActivityDate", 0);

              cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", System.DateTime.Now);

              DataSet ds = null;

              cmdSQL.CommandType = CommandType.StoredProcedure;

              ds = db.ExecuteDataSet(cmdSQL);

              if (ds.Tables[0].Rows.Count > 0)

              {

                DataRow dr = ds.Tables[0].Rows[0];

                //The database does not name it's returned rows.

                //The Salt is stored in the first field returned (Password field)

                //The Hash is stored in the 3rd field returned (PasswordSalt)

                PasswordHash = dr[0].ToString();

                PasswordSalt = dr[2].ToString();

              }

              else

              {

                //No rows were returned from the database therefore

                //User does not exist.

                return false;

              }

              //Now we hash the password supplied.

              HashedPassword = CreatePasswordHash(password, PasswordSalt);

              //Now simply compare the hashed password just generated with that stored

              //in the database.  If they match then username and password are correct

              //otherwise they are not.

              if (HashedPassword == PasswordHash)

              {

                return true;

              }

              else

              {

                return false;

              }

            }

          catch (Exception ex)

          {

            // TODO: Exception Handling routine

            return false;

          }

        }

     

        public bool UnlockUser(string username, string applicationname)

        {

          int ReturnValue = 0;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_UnlockUser");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@Username", username);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          ReturnValue = Convert.ToInt32(db.ExecuteScalar(cmdSQL));

          if (ReturnValue == 0)

          {

            return true;

          }

          else

          {

            return false;

          }

        }

     

        public bool DeleteUser(string username, string applicationname, bool deleteallrelateddata)

        {

          int UserDeleted = 0;

          int ErrorCode = 0;

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Users_DeleteUser");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@UserName", username);

          if (deleteallrelateddata == true)

          {

            cmdSQL.Parameters.AddWithValue("@TablesToDeleteFrom", 15);

          }

          else

          {

            cmdSQL.Parameters.AddWithValue("@TablesToDeleteFrom", 0);

          }

          SqlParameter output = new SqlParameter("@NumTablesDeletedFrom", SqlDbType.Int);

          output.Direction = ParameterDirection.Output;

          //SqlParameter errorcode = new SqlParameter("@ErrorCode", SqlDbType.Int);

          //errorcode.Direction = ParameterDirection.ReturnValue;

          cmdSQL.Parameters.Add(output);

          //cmdSQL.Parameters.Add(errorcode);

          cmdSQL.CommandType = CommandType.StoredProcedure;

          db.ExecuteNonQuery(cmdSQL);

          UserDeleted = Convert.ToInt32(cmdSQL.Parameters["@NumTablesDeletedFrom"].Value.ToString());

          //ErrorCode = Convert.ToInt32(cmdSQL.Parameters["ErrorCode"].Value.ToString());

          if (UserDeleted == 0)

          {

            return false;

          }

          else

          {

            return true;

          }

        }

     

        public bool ChangePassword(string username, string oldpassword,

          string newpassword, string applicationname)

        {

          int ReturnCode = 0;

          string PasswordSalt = CreateSalt(5);

          string HashedPassword = CreatePasswordHash(newpassword, PasswordSalt);

          bool OldPasswordValidated = ValidateUser(username, oldpassword, applicationname);

          if(OldPasswordValidated == false)

          {

            return false;

          }

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_SetPassword");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@UserName", username);

          cmdSQL.Parameters.AddWithValue("@NewPassword", HashedPassword);

          cmdSQL.Parameters.AddWithValue("@PasswordSalt", PasswordSalt);

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          cmdSQL.Parameters.AddWithValue("@PasswordFormat", MembershipPasswordFormat.Clear);

          SqlParameter returncode = new SqlParameter("@ReturnCode", SqlDbType.Int);

          returncode.Direction = ParameterDirection.ReturnValue;

          cmdSQL.CommandType = CommandType.StoredProcedure;

          db.ExecuteNonQuery(cmdSQL);

          ReturnCode = Convert.ToInt32(cmdSQL.Parameters["@ReturnCode"].Value.ToString());

          if (ReturnCode == 0)

          {

            return true;

          }

          else

          {

            return false;

          }

        }

     

        public void UpdateUser(string applicationname, MembershipUser user)

        {

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_UpdateUser");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@UserName", user.UserName);

          cmdSQL.Parameters.AddWithValue("@Email", user.Email);

          cmdSQL.Parameters.AddWithValue("@Comment", user.Comment);

          cmdSQL.Parameters.AddWithValue("@IsApproved", user.IsApproved);

          cmdSQL.Parameters.AddWithValue("@LastLoginDate", user.LastLoginDate);

          cmdSQL.Parameters.AddWithValue("@LastActivityDate", user.LastActivityDate);

          cmdSQL.Parameters.AddWithValue("@UniqueEmail", 1); //Requires Unique Email

          cmdSQL.Parameters.AddWithValue("@CurrnetTimeUtc", DateTime.Now);

          SqlParameter returncode = new SqlParameter("@ReturnCode", SqlDbType.Int);

          returncode.Direction = ParameterDirection.ReturnValue;

          cmdSQL.CommandType = CommandType.StoredProcedure;

          db.ExecuteNonQuery(cmdSQL);

          //Since we are returning void, do we really need to check the

          //return type?  Only course of action would be to throw a

          //exception which won't work as this is a web service.

        }

     

        public int GetNumberOfUsersOnline(string applicationname)

        {

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL = new SqlCommand("aspnet_Membership_GetNumberOfUsersOnline");

          cmdSQL.Parameters.AddWithValue("@ApplicationName", applicationname);

          cmdSQL.Parameters.AddWithValue("@MinutesSinceLastInActive", 20);  //value of IIS timeout

          cmdSQL.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now);

          SqlParameter returnvalue = new SqlParameter("@NumOnline", SqlDbType.Int);

          returnvalue.Direction = ParameterDirection.ReturnValue;

          cmdSQL.Parameters.Add(returnvalue);

          db.ExecuteNonQuery(cmdSQL);

          return Convert.ToInt32(cmdSQL.Parameters["@NumOnline"].Value.ToString());

        }

     

        public MembershipUserCollection FindUsersByName(string applicationname, string username)

        {

          DataSet ds = null;

          int RecordstoGo = 1;

          int TotalRecords = 0;

          int PageIndex = 0;

          MembershipUserCollection users = new MembershipUserCollection();

          Database db = DatabaseFactory.CreateDatabase();

          SqlCommand cmdSQL =