# VBForums CodeBank > CodeBank - ASP / ASP.NET / MVC / Web API >  Using the Profile Provider in ASP.Net 2.0

## gep13

Hello,

The following tutorial will attempt to explain the steps that need to be carried out in order to use the built-in ASP.Net Profile Provider.

Why would you want to use the built-in Profile Provider?

Let's say you wanted to store additional information about the user's that get created on your website, for instance, their first name, or their last name.  These are not things that are created for you out of the box, but with a few small steps you can add as many additional properties for each user as you want.

At the end of this codebank submission I have posted a small sample application that shows the use of the Profile Provider.

*Step 1:*
Create a new website project

*Step 2:*
Use the ASP.Net Website Configuration tool to select the Authentication Type for the Website as "From the internet".  Create the users and roles that you want to use on the website.

*Step 3:*
To make things easier later, I normally copy the standard Provider Settings from the machine.config file, and override them in my web.config file.  You can normally find the machine.config at the following location:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG

Here are the standard settings for each provider; Membership, Roles, and Profile:



```
<system.web>
    <membership>
        <providers>
            <add name="AspNetSqlMembershipProvider" 
                type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
                connectionStringName="LocalSqlServer" 
                enablePasswordRetrieval="false" 
                enablePasswordReset="true" 
                requiresQuestionAndAnswer="true" 
                applicationName="/" 
                requiresUniqueEmail="false" 
                passwordFormat="Hashed" 
                maxInvalidPasswordAttempts="5" 
                minRequiredPasswordLength="7" 
                minRequiredNonalphanumericCharacters="1" 
                passwordAttemptWindow="10" 
                passwordStrengthRegularExpression=""/>
            </providers>
        </membership>
	<profile>
	    <providers>
	        <add name="AspNetSqlProfileProvider" 
                    connectionStringName="LocalSqlServer" 
                    applicationName="/" 
                    type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
           </providers>
	</profile>
	<roleManager enabled="true">
	    <providers>
		<add name="AspNetSqlRoleProvider" 
                    connectionStringName="LocalSqlServer" 
                    applicationName="/" 
                    type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
	    </providers>
        </roleManager>
```

With this in place, you can then start to create the properties that you want to be available for each user.  These settings get added to the <profile> node in your web.config file using the <properties> node.  It is possible to create groups within this <properties> node to group common settings together.  Once in your code behind files, you will be able to access these properties in a strongly typed way.  Here is an example of the types of properties that you can add:



```
<properties>
    <add name="FirstName" type="String" serializeAs="String"/>
    <add name="LastName" type="String" serializeAs="String"/>
    <add name="Gender" type="String" serializeAs="String"/>
    <add name="BirthDate" type="DateTime" serializeAs="String"/>
    <add name="Occupation" type="String" serializeAs="String"/>
    <add name="Website" type="String" serializeAs="String"/>
    <group name="Forum">
        <add name="Posts" type="Int32" defaultValue="0"/>
        <add name="AvatarUrl" type="String" serializeAs="String"/>
        <add name="Signature" type="String" serializeAs="String"/>
    </group>
    <group name="Address">
        <add name="Street" type="String" serializeAs="String"/>
        <add name="PostalCode" type="String" serializeAs="String"/>
        <add name="City" type="String" serializeAs="String"/>
        <add name="State" type="String" serializeAs="String"/>
        <add name="Country" type="String" serializeAs="String"/>
    </group>
    <group name="Contacts">
        <add name="Phone" type="String" serializeAs="String"/>
        <add name="Fax" type="String" serializeAs="String"/>
    </group>
</properties>
```

Specifying the type will mean that these properties are treated as this type in your code.

*Step 4:*
Add the necessary controls to begin accessing these properties.  In the sample project, you will find that I have added a Login Control so we can log in as a specified user, and also a CreateUserWizard for creating new users and creating new profiles.

In order to piece all these things together, there are a number of things that need to be done.  For instance, when creating a new user, you need to specifically create a new profile, and this is done using the following in the CreatedUser Event:



```
    protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
    {
        // Create an empty Profile for the newly created user
        ProfileCommon p = (ProfileCommon)ProfileCommon.Create(CreateUserWizard1.UserName, true);

        // Save profile - must be done since we explicitly created it
        p.Save();
    }
```

This is a little bit of overkill here, as we are not actually adding anything to the profile, but you could add additional steps in the CreateUserWizard to capture information and add them here.

*Step 5:*
Now we need to extract the information.  When a valid user logs into the sample application, they are re-directed to another page, and that page loads information from the profile, and also allows the user to change the information and save it again.

The information is extracted in the load event using:



```
        if (!this.IsPostBack)
        {
            ProfileCommon p = this.Profile.GetProfile(this.User.Identity.Name);

            FirstNameTextBox.Text = Profile.FirstName;
            LastNameTextBox.Text = Profile.LastName;
            GenderTextBox.Text = Profile.Gender;
            BirthDateTextBox.Text = Profile.BirthDate.ToString();
            OccupationTextBox.Text = Profile.Occupation;
            WebSiteTextBox.Text = Profile.Website;
            PostsTextBox.Text = Profile.Forum.Posts.ToString();
            AvatarURLTextBox.Text = Profile.Forum.AvatarUrl;
            SignatureTextBox.Text = Profile.Forum.Signature;
            StreetTextBox.Text = Profile.Address.Street;
            PostalCodeTextBox.Text = Profile.Address.PostalCode;
            CityTextBox.Text = Profile.Address.City;
            StateTextBox.Text = Profile.Address.State;
            CountyTextBox.Text = Profile.Address.Country;
            PhoneTextBox.Text = Profile.Contacts.Phone;
            FaxTextBox.Text = Profile.Contacts.Fax;
        }
```

And then in the save button we save the information back again:



```
        ProfileCommon p = this.Profile.GetProfile(this.User.Identity.Name);

        p.FirstName = FirstNameTextBox.Text;
        p.LastName = LastNameTextBox.Text;
        p.Gender = GenderTextBox.Text;
        p.BirthDate = DateTime.Parse(BirthDateTextBox.Text);
        p.Occupation = OccupationTextBox.Text;
        p.Website = WebSiteTextBox.Text;
        p.Forum.Posts = int.Parse(PostsTextBox.Text);
        p.Forum.AvatarUrl = AvatarURLTextBox.Text;
        p.Forum.Signature = SignatureTextBox.Text;
        p.Address.Street = StreetTextBox.Text;
        p.Address.PostalCode = PostalCodeTextBox.Text;
        p.Address.City = CityTextBox.Text;
        p.Address.State = StateTextBox.Text;
        p.Address.Country = CountyTextBox.Text;
        p.Contacts.Phone = PhoneTextBox.Text;
        p.Contacts.Fax = FaxTextBox.Text;

        p.Save();
```

You can see here that I have specifically and to convert to and from integers and DateTime due to the settings that we used in the web.config file.

Hopefully this has showed you the basic steps to using a Profile within ASP.Net.

The default database that I created for whatever reason is 10MB in size!!  I have tried to shrink it, but it is not working.  Instead of attaching this file, I have created an sql file that will generate the required database.

If you have any questions, then feel free to post back.

Gary

----------


## Krokonoster

Do you have any advice on how to use this in an Asp.Net MVC project without using User Controls?

----------


## gep13

As far as I am aware, there are no built in controls for displaying a person's Profile content.  I have always simply created my own.

I still haven't played enough with MVC to answer the other part of your question  :Frown:

----------


## Krokonoster

No worries.  Found this and seems it might work : http://weblogs.asp.net/jgalloway/arc...ile-class.aspx

Yours are pretty clear and even I don't know web forms that well anymore makes perfect sense.  Good work

----------


## gep13

Yes, the link that you provide basically deals with the problem that ProfileCommon isn't available in anything but the Web Site Project Template.  I have been meaning to update this article to cover that, but I just haven't had a chance.

Gary

----------


## dionisis

Hi Gary, 

I have download the sample code and I have a question. I can’t understand how the database is updated with the profile properties. I am looking (in t-sql file for creating the database) the gender field or the birthday field and I can’t find it.. I suspect that the profile is not saved to the database.

thank you

----------


## gep13

Hello,

It definitely gets persisted to the database  :Smilie: 

Since there are an "n" number of potential properties created, the Profile Provider actually stores the profile properties as a delimited string, and stores it in one column within the profile database for each user.

I forget exactly "where" this is stored, but if you are still struggling, I will dig into it some more and find out exactly where the information is stored.

Gary

----------


## dionisis

ok.. if you say so.., i will take a look back again. 

thank you

----------


## dionisis

You are right Gary. The information is being storing in aspnet_profile table, in a field as delimeted string. Great.. !! 

I Soon realized that if (not often) come in need of query the table and read the vaIues for the strored properties, It  will not going to be so handy. Yes the vb code runs great and the properties are displayed correctly on my page but I like to feel that I can query (Sql Management Studio) everything easy and read the values not as a string but columns. Firstly I thought to start writing my own udf function but after a little search I found what I was looking for. I found a lot of posts asking about how to query that table and I am gonna share it with you because it is a really nice solution.

check it here

First create these two functions on SQL Server.



```
CREATE FUNCTION dbo.fn_GetElement
(
@ord AS INT,
@str AS VARCHAR(8000),
@delim AS VARCHAR(1) )
RETURNS INT
AS
BEGIN
-- If input is invalid, return null.
IF @str IS NULL
OR LEN(@str) = 0
OR @ord IS NULL
OR @ord < 1
-- @ord > [is the] expression that calculates the number of elements.
OR @ord > LEN(@str) - LEN(REPLACE(@str, @delim, '')) + 1
RETURN NULL
DECLARE @pos AS INT, @curord AS INT
SELECT @pos = 1, @curord = 1
-- Find next element's start position and increment index.
WHILE @curord < @ord
SELECT
@pos = CHARINDEX(@delim, @str, @pos) + 1,
@curord = @curord + 1
RETURN 
CAST(SUBSTRING(@str, @pos, CHARINDEX(@delim, @str + @delim, @pos) - @pos) AS INT)
END
```



```
CREATE FUNCTION dbo.fn_GetProfileElement
(
@fieldName AS NVARCHAR(100),
@fields AS NVARCHAR(4000),
@values AS NVARCHAR(4000))
RETURNS NVARCHAR(4000)
AS
BEGIN
-- If input is invalid, return null.
IF @fieldName IS NULL
OR LEN(@fieldName) = 0
OR @fields IS NULL
OR LEN(@fields) = 0
OR @values IS NULL
OR LEN(@values) = 0
RETURN NULL
-- locate FieldName in Fields
DECLARE @fieldNameToken AS NVARCHAR(20)
DECLARE @fieldNameStart AS INTEGER,
@valueStart AS INTEGER,
@valueLength AS INTEGER
-- Only handle string type fields (:S:)
SET @fieldNameStart = CHARINDEX(@fieldName + ':S',@Fields,0)
-- If field is not found, return null
IF @fieldNameStart = 0 RETURN NULL
SET @fieldNameStart = @fieldNameStart + LEN(@fieldName) + 3
-- Get the field token which I've defined as the start of the 
-- field offset to the end of the length
SET @fieldNameToken = SUBSTRING(@Fields,@fieldNameStart,LEN(@Fields)-@fieldNameStart)
-- Get the values for the offset and length
SET @valueStart = dbo.fn_getelement(1,@fieldNameToken,':')
SET @valueLength = dbo.fn_getelement(2,@fieldNameToken,':')
-- Check for sane values, 0 length means the profile item was 
-- stored, just no data
IF @valueLength = 0 RETURN ''
-- Return the string
RETURN SUBSTRING(@values, @valueStart+1, @valueLength)
END
```

According to Gary’s properties example use the query below, you can also save it as a view ready for execution.



```
SELECT     dbo.aspnet_Profile.UserId, dbo.aspnet_Users.UserName, dbo.fn_GetProfileElement(N'FirstName', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS FirstName, dbo.fn_GetProfileElement(N'LastName', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS LastName, dbo.fn_GetProfileElement(N'Gender', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS Gender, dbo.fn_GetProfileElement(N'BirthDate', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS BirthDate, dbo.fn_GetProfileElement(N'Occupation', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS Occupation, dbo.fn_GetProfileElement(N'Website', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS Website, dbo.fn_GetProfileElement(N'Forum.Posts', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS ForumPosts, dbo.fn_GetProfileElement(N'Forum.AvatarUrl', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS ForumAvatarUrl, dbo.fn_GetProfileElement(N'Forum.Signature', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS ForumSignature, dbo.fn_GetProfileElement(N'Address.PostalCode', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS AddressPostalCode, dbo.fn_GetProfileElement(N'Address.City', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS AddressCity, dbo.fn_GetProfileElement(N'Address.State', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS AddressState, dbo.fn_GetProfileElement(N'Address.Country', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS AddressCountry, dbo.fn_GetProfileElement(N'Contacts.Phone', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS ContactsPhone, dbo.fn_GetProfileElement(N'Contacts.Fax', dbo.aspnet_Profile.PropertyNames, 
                      dbo.aspnet_Profile.PropertyValuesString) AS ContactsFax
FROM         dbo.aspnet_Profile INNER JOIN
                      dbo.aspnet_Users ON dbo.aspnet_Profile.UserId = dbo.aspnet_Users.UserId AND dbo.aspnet_Profile.UserId = dbo.aspnet_Users.UserId
```

Gary thank you, thank you, thank you, thank you..!!!!!! You are newbies’ heaven..! Yours tutorial as this one, as about membership database, restricted menu.., sql injections have helped me so much..! thank you man, you are a really great guy…

----------


## gep13

Hello,

Glad to hear that I was able to help you!

And thanks for sharing the information about what you found, I really think it will help people going forward!

Gary

----------


## adhp123

With ASP.NET 2.0, you can add authentication, authorization, and profiles to your Web site without writing a single line of code. That's quite a step forward from the way things used to be.

----------


## gep13

> With ASP.NET 2.0, you can add authentication, authorization, and profiles to your Web site without writing a single line of code. That's quite a step forward from the way things used to be.


This is very true!

I have heard some people argue that the Membership Provider implementation is overly verbose, and "clunky", however, in my opinion, it does a very good job out of the box, and prevents the need to completely re-invent the wheel when it comes to allowing creation of users on your site.

Gary

----------

