Creating ASP.NET Users Programmatically

One area in ASP.NET I see a lot of developers struggle with it deploying their sites. Compiling the application and then FTP-ing your files to a remote host is pretty easy. Then you need to set up a database. Often this is done by your ISP so you don't have to worry about that a lot either. But then you need to move your initial data from your development system to the remote server. By using the Database Publishing Wizard - now an integral part of Visual Studio 2008 - this is usually straight forward. You export the data to T-SQL Create and Update scripts and then execute those against the production database. While this works for most of your data, it doesn't always work correctly for the Membership and Roles data that is stored in your database. When it's not working, you typically do see your regular data in your application, but you can't seem to log in with the accounts you created on your local machine using the Web Site Administration Tool.

ASP.NET Configuration Settings

One of the reasons for this behavior is a mismatch between the application on the development server and the production server. By default, the ASP.NET Provider applications (Membership, Roles, Profile, and so on) create an entry in the aspnet_Applications table named after the current web site. On a local machine, you often run your site with an URL like http://localhost:43423/WebSite1. The WebSite1 in the URL results in an application called WebSite1 in the database.

When you move the site to the production environment, the site is often accessible through an address like http://www.yourdomain.com/. This results in an application called /. When you now try to log in in your production site, ASP.NET will try to match your credentials against the current application: /. Since the initial account was created against an application called WebSite1, your account cannot be validated and you're not allowed to login.

One way around this is to set the applicationName attribute to a fixed value in your web.config file. The following code snippet shows a default implementation for Membership, Roles and Profile, all with their applicationName set to /. If you use this setting before creating accounts, you minimize the risk of a mismatch between users in the development and production environments as both environments now use the same name.

<membership defaultProvider="AspNetSqlMembershipProvider">
  <providers>
    <clear />
    <add
      name="AspNetSqlMembershipProvider"
            type="System.Web.Security.SqlMembershipProvider, 
            System.Web, Version=2.0.3600.0, 
            Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
      connectionStringName="LocalSqlServer"
      applicationName="/"
      requiresUniqueEmail="false"
      passwordFormat="Hashed"
      enablePasswordRetrieval="false"
      enablePasswordReset="true"
      requiresQuestionAndAnswer="false"
      passwordStrengthRegularExpression=""
      minRequiredPasswordLength="1"
      minRequiredNonalphanumericCharacters="0"
      passwordAttemptWindow="10"
      maxInvalidPasswordAttempts="5"
      description="Stores and retrieves membership data 
            from a local Microsoft SQL Server database."
    />
  </providers>
</membership>

<roleManager
  defaultProvider="SqlProvider"
  enabled="true"
  cacheRolesInCookie="true"
  cookieName=".ASPROLES"
  cookieTimeout="30"
  cookiePath="/"
  cookieRequireSSL="false"
  cookieSlidingExpiration="true"
  cookieProtection="All"
  >
  <providers>
    <add
      name="SqlProvider"
      type="System.Web.Security.SqlRoleProvider"
      connectionStringName="localSqlServer"
      applicationName="/"
    />
  </providers>
</roleManager>

<profile defaultProvider="AspNetSqlProfileProvider">
  <providers>
    <clear/>
      <add
        type="System.Web.Profile.SqlProfileProvider, 
        System.Web, Version=2.0.0.0, 
        Culture=neutral, 
        PublicKeyToken=b03f5f7f11d50a3a"
      name="AspNetSqlProfileProvider"
      connectionStringName="localSqlServer"
      applicationName="/"
    />
  </providers>
  <properties>
    <add name="FirstName" type="System.String"/>
  </properties>
</profile>		

Creating Users Programmatically

Another way to solve this problem is to create users programmatically using the Membership and Roles APIs. These APIs always connect to the currently configured application so users are always created where you need them. A good place to do this is to create the users and roles on application startup, in the Application_Start event handler in the Global.asax file.

C#
void Application_Start(object sender, EventArgs e)
{
  const string adminRoleName = "Administrators";
  const string adminUserName = "YourUserName";
  const string adminPassword = "P4s$w0rd";

  if (!Roles.RoleExists(adminRoleName))
  {
    Roles.CreateRole(adminRoleName);
  }

  if (Membership.GetUser(adminUserName) == null)
  {
    Membership.CreateUser(adminUserName, adminPassword);
  }

  if (!Roles.IsUserInRole(adminUserName, adminRoleName))
  {
    Roles.AddUserToRole(adminUserName, adminRoleName);
  }
}

VB.NET
Const adminRoleName As String = "Administrators"
Const adminPassword As String = "P4s$w0rd"
Const adminUserName As String = "YourUserName"

If Not Roles.RoleExists(adminRoleName) Then
  Roles.CreateRole(adminRoleName)
End If

If Membership.GetUser(adminUserName) Is Nothing Then
  Membership.CreateUser(adminUserName, adminPassword)
End If

If Not Roles.IsUserInRole(adminUserName, adminRoleName) Then
  Roles.AddUserToRole(adminUserName, adminRoleName)
End If

This code simply creates a new role called Administrators. It then adds a new user and associated that user with the new role. Directly after this code has fired, you can login using the user name and password used in this code snippet.

Every time the web application starts for the first time (after a reboot, or after an application pool restart for example) this code is executed. To avoid the code from crashing if the user or role already exists in the system or if the user is already assigned to the role, it checks the database first (using RoleExists for the role, GetUser for the user account and IsUserInRole for the role assignment).

Obviously, it's not a good idea to store user names and passwords in clear text files on your server, so be sure to remove this code again from your Global.asax file as soon as the user and roles have been created successfully.

A Note for Windows Vista and Windows Server 2008 Users

If your site runs under IIS 7 on Windows Vista or Windows Server 2008, you can use the management tools of IIS to manage your ASP.NET user accounts. For more information, open up the IIS Manager, locate your web site, and then open items like .NET Users, .NET Roles, and .NET Profile. The dialogs are pretty straight forward, so you probably don't need the help files, but if you do, they are only one click away.


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Monday, September 29, 2008 12:53:28 PM Jose said:
I couldn't believe it when I saw the title for your post, since this morning I was just thinking on how to migrate my ever expanding user database.  I'll give Database Publishing Wizard a try.

Thanks,
On Tuesday, September 30, 2008 5:24:39 PM Jeff said:
Nice one Imar! I've actually been reading up on using OpenID in conjunction with Membership and Roles and this gives me a nice little heads up of some things I should know about a head of time for creating users.

I'm also looking forward to the next version of the N-Layered Web Applications series as using multiple class librarires and such in a single project still seems to mystify me and as I recall that was one of the things you were planning to cover.. :) So, until then, thanks as always.
On Tuesday, September 30, 2008 7:13:02 PM Imar Spaanjaars said:
Hi Jeff,

Working hard on the next version of my articles, although it may take a few more weeks before they'll be finished.

Send me an e-mail if you wish to preview some of it, giving you an early chance to look at them and give feedback, ideas and so on if you want.

Cheers,

Imar
On Wednesday, May 04, 2011 8:57:44 AM Islam Khattab said:
thank you for this great article,,

but i'm just wondring if i have a certain applicationpool (Sharepoint Applicationpool) and i want to add users to it programmatically ??? How could this be done.
On Wednesday, May 04, 2011 10:17:03 AM Imar Spaanjaars said:
Hi there,

Not sure I understand what you're asking, or why you'd want this. Application Pools are an IIS concept; why would you want to add users to it?

Imar
On Wednesday, August 17, 2011 4:25:13 AM Imran said:
Nice article but i would like to know after creating user programatically i want to send them a notification with their Username and password How to do that.
On Wednesday, August 17, 2011 4:31:14 AM Imar Spaanjaars said:
Since you have full control over the user name and password, you can just send them an ordinary e-mail.

If you search Google for SmtpClient and MailMessage you'll find plenty examples.

Cheers,

Imar
On Monday, November 07, 2011 6:20:34 AM Udeme Bassey said:
great work. but i am having difficulty here. In my application's database, i have a table called users which stores username and passwords. is it the same with the membership you are talking about? if not how do i go about it restricting some users from accessing some pages of my web application and allowing some to access them.
Your prompt response will be gladly appreciated

thanks
On Monday, November 07, 2011 6:42:19 AM Imar Spaanjaars said:
If you have custom tables, this won't work. This code uses the standard Membership API which uses its own tables. It also means you'll need to implement your own security mechanisms (outside the scope of this article / the comments feature of my site).

Cheers,

Imar
On Wednesday, December 21, 2011 1:49:01 AM Gilmer Donis said:
Hi Imar, thanks for the oportunity to talk to you.  The users and roles you mention, I found that it doesn't work with the paid version of sql-server installed alone, and I looked hard, so I wonder if I needed to install on a site that doesn't have te express version and they don't want it to install the express version, is there a way to create users and roles with sql server 2008R2 and use them in the asp.net app.
thanks in advance.
On Wednesday, December 21, 2011 1:04:38 PM Imar Spaanjaars said:
Hi Gilmer,

Take a look here: http://msdn.microsoft.com/en-us/library/x28wfk74.aspx

You can run aspnet_regsql in Wizard or Command Line mode to configure a SQL database for Membership and Roles.

Cheers,

Imar
On Wednesday, December 21, 2011 6:14:52 PM Gilmer Donis said:
Imar, thank you, I'm going to follow your suggestion. very helpful.
On Thursday, April 30, 2015 6:46:30 AM Slavimir said:
Your books are excellent and I enjoy in reading "Beginning ASP.NET 4.5.1". Examples are quite simple and hit the center of the target. I have one question about authentication and authorization. In my firm we don't use .NET as primary platform, and we have Progress 4GL database. Users and their passwords, are stored in database, and I would like to use ODBC data connection to read them and assign then to some role: admin, user, cooridinator, etc... Which type of ASP.NET identification is best suite for this task ? (application will be realized in ASP.NET Web forms)
On Thursday, April 30, 2015 1:45:48 PM Imar Spaanjaars said:
Hi Slavimir,

You can try building your own providers as explained here: http://imar.spaanjaars.com/560/using-the-microsoft-access-providers-for-membership-roles-and-profile-under-aspnet-4

Cheers,

Imar

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.