Managing ASP.Net Authentication from a Console Application

Many developers are familiar with the ASP.Net Web Configuration Manager in Visual Studio to maintain or create users in their SQL databases. The application allows the creation of users, as well as role creation and assignment. However, to my surprise, this functionality is no longer available in Visual Studio 2013. This was due to the removal of the Cassini web server in place of IIS Express. There is a workaround if you still like using the tool (as I do). The information can be found in this MSDN blog post.

Recently, I needed to move a small number of users from an older application to a new MVC 4 application using forms authentication. With the previously mentioned issues concerning the web configuration tool, I decided to build a console application to import the users automatically. This would also allow me to repeat the process for any interim users that would be created prior to launch.

Another small caveat to the import was that I was also going to be utilizing profiles for extended information. As I discovered, information is a bit sparse concerning profile usage outside of an ASP.Net application. After a fair amount of trial and error along with the odd exception here and there, I got it to work as expected with a very small amount of code.

The Code

As with an ASP.Net application, you need several elements in the app.config file. Basically the same as would be in your web.config for an ASP.Net application. In my case, I added the SQL membership, rolemanager, and profile providers in order to create the profile and attach additional user related fields.

<connectionStrings> <add name="MyConnectionString" connectionString="Data Source=MySqlServer;Initial Catalog=MyDB
   &lt;/connectionStrings>

Then in a “system.web” section add the following:

<membership defaultProvider="AspNetSqlMembershipProviderEncrypted"> <providers> <clear /> <add name="AspNetSqlMembershipProviderEncrypted" type="System.Web.Security.SqlMembershipProvider" connectionStringName=" MyConnectionString " enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/" requiresUniqueEmail="false" passwordFormat="Encrypted" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="3" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" /> </providers> </membership> <profile defaultProvider="AspNetSqlProfileProvider"> <providers> <clear /> <add name="AspNetSqlProfileProvider" connectionStringName=" MyConnectionString " applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> </providers> <properties> <add name="userHomePhone" type="string" /> </properties> </profile> <roleManager enabled="true"> <providers> <clear /> <add connectionStringName=" MyConnectionString " applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> </providers> </roleManager>

In order to use the role provider and profile provider, we need to instantiate them. In a standard ASP.Net application, these objects are instantiated behind the scenes so we need to bring them up ourselves. I did this with simple static methods and a couple of properties outlined in my app.config.

Roleprovider:

public static SqlRoleProvider GetRoleProvider()
        {
            var prov = new SqlRoleProvider();
            var coll = new NameValueCollection
            {
                {"connectionStringName", "PEFAppsConnectionString"},
                {"applicationName", "/"}
            };
            prov.Initialize("AspNetSqlRoleProvider", coll);
            return prov;
        }

Profileprovider:

public static SqlProfileProvider GetProfileProvider()
        {
            var prov = new SqlProfileProvider();
            var coll = new NameValueCollection
            {
                {"connectionStringName", "PEFAppsConnectionString"},
                {"applicationName", "/"}
            };
            prov.Initialize("AspNetSqlProfileProvider", coll);
            return prov;
        }

The Membership object is instantiated normally utilizing the fields from the app.config without any static methods. You will need to add references to System.Web and System.Security.

To access the member data from SQL, you use the normal routines. For example, to get user information:

var user = Membership.GetUser("userName");

In order to get role information, we use one of our static methods to retrieve a role provider:

var rp = GetRoleProvider();
var rpRole = rp.IsUserInRole(“userName, "roleName");

To retrieve profile information, we use ProfileBase.Create(“username”). This does seem a bit odd, since we aren’t actually, creating a new profile. The method name (“Create”) is a bit misleading since you are not actually creating a profile, but a connection to it. You can then set your property values:

pr.SetPropertyValue("userPhoneNumber", “username”);
pr.Save();

I utilized standard EF 6 functionality to import users from the old database. I then simply looped through them and created members, roles and profiles using the above methods. One other small piece I added that was helpful was a simple static method to create a role if it wasn’t already present. I then passed the role provider and role name to my CreateNewRole method:

public static void CreateNewRole(SqlRoleProvider roleProvider, string roleName)
        {
            var newRole =
           roleProvider.GetAllRoles().FirstOrDefault(x => x.Contains(roleName));
            if (newRole == null)
            {
                roleProvider.CreateRole(roleName);
            }
        }

In summation, it is very easy to move large numbers of users from an existing, non-ASP. Net authentication database to a new ASP. Net Forms Authentication database with a console application. This method takes a fraction of the time when compared with a simple MVC web site or the ASP.Net configuration manager to perform the operation.

Want brilliance sent straight to your inbox?