Becky Bertram's Blog
Perspectives from a SharePoint developer




This blog has moved. You can find the new blog on Savvy Technical Solution's Web site, at www.savtechsol.com. You will be redirected to the following page in 10 seconds:

Becky Bertram's Blog > Posts > Using ASP.NET Profiles in a SharePoint FBA Site
August 03
Using ASP.NET Profiles in a SharePoint FBA Site
I have a requirement for my client that I'm supposed to allow users to authenticate using Forms Based Authentication. However, they also want users to be able to enter supplemental information such as their address, phone number, etc. Typically, this can be done rather easily using the ASP.NET Profile infrastructure.
 
However, an ASP.NET application has dynamically generated code that gets generated when the application is compiled on the fly. As you know, in SharePoint most all code has to be compiled ahead of time in order to run. Because of this, it becomes necessary to use strongly typed objects, and to reference these Types with their full namespace names, assembly references, etc., in the web.config. Unfortunately, I had to spend hours trying to dig through the Internet trying to look at ASP.NET examples and extrapolate how the code would have to be modified for a SharePoint environment.
 
There's a legend that goes something like this:
The cathedral in Florence had been built without a dome because the people of the city knew that they would one day have the know-how to build the world's largest dome -- they just didn't have it yet. Finally, when everything was completed but the dome, the people of the city held a competition to see who could build it. The competition required different architects to stand a piece of egg upright on a stone. According to the art historian Vasari, the architect Brunelleschi "...giving one end a blow on the flat piece of marble, made it stand upright. The architects protested that they could have done the same; but Filippo answered, laughing, that they could have made the dome, if they had seen his design."
 
In much the same way, the final solution doesn't seem that hard, but it took me quite a while to figure out how all the pieces fit together!
 
As a starting point, I was using the Forms Based Authentication module of the Community Kit for SharePoint, found on CodePlex. This code helped me do the work of allowing users to sign up, to edit their username and e-mail, add them to groups, etc. However, I wanted to be able to use the Profile table in the ASP.NET generated database I was already using to store user information.
 
In a vanilla ASP.NET application, I could simply type in "Profile." in my code-behind and Intellisense would automatically access profile properties I had defined in my web.config. However, this is available because the ASP.NET engine automatically compiles a class called "ProfileCommon" which it instantiates as an object called "Profile". To a developer, it all seems to work "automagically". Not so for the poor SharePoint developer. Because we don't get the benefit of any dynamically generated code, we need to write our own version of the "ProfileCommon" class, and add it to our solution.
 
At first, it's a pretty basic class. It only has one static method, which is used to generate a Profile object. It inherits from the System.Web.Profile.ProfileBase object.
 
using System.Web.Profile;
namespace BB.FBA
{
    public class UserProfile : ProfileBase
    {
         public static UserProfile GetProfile(string username)
        {
            return Create(username) as UserProfile;
        }
     }
}
 
The next thing I need to do is specify in my web.config that my profile is inheriting from this custom class. So, I add "inherits=BB.FBA.UserProfile" to my <profile> node. My final node looks something like this:
 
<profile defaultProvider="SqlProfileProvider" enabled="true" inherits="BB.FBA.UserProfile">
  <providers>
    <clear />
    <add name="SqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="FBAConnectionString" applicationName="/" />
  </providers>
  <!-- Define the properties for Profile... -->
  <properties>
  </properties>
</profile>
 
(I've set up my profile provider and connection string nodes according to regular Forms Based Authentication standards. You read about how to do set up your FBA site here.)
 
This seems pretty straight forward, but I ran into a problem. Again, because we don't have the benefit of classes being compiled at run-time, I got an error saying it couldn't find custom profile provider class. What I had to do was to add a reference to my dll in the <system.web><compilation><assemblies> node in my web.config, like this:
 
<add assembly="BB.FBA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8f1s7b751a09c4e0" />
 
Once I added that, the application could find my custom UserProfile class.
 
Next, I wanted to create a strongly typed object to store user information, rather than adding a million <property> nodes to my web.config. So, I created a "Person" class. For the sake of brevity, I've shortened it:
 
namespace BB.FBA
{
    public class Person
    {
        public Person()
        {
        }
        string phone = "";
        public string Phone
        {
            get { return phone; }
            set { phone = value; }
        }
        string fax = "";
        public string Fax
        {
            get { return fax; }
            set { fax = value; }
        }
    }
}
 
The next thing I needed to do was add it to my UserProfile class, so my new "Person" object could be accessed through it.
 
[SettingsAllowAnonymous(true)]
public Person Person
{
    get
    {
        return (base.GetPropertyValue("Person") as Person);
     }
     set 
     {
        base.SetPropertyValue("Person", value);
     }
}
 
(I made the mistake of also adding a reference to this Person class in my web.config, like this: <add name="Person" type="BB.FBA.Person"/>, but I got an error. I discovered that you can either define the property in your custom ProfileBase class, or you can define it in the web.config, but you cannot put it in both places, or you can get an error saying the property is duplicated.)
 
I know thought that I had everything wired up to work. Unfortunately, though, whenever I tried to access the HttpContext.Current.Profile property in my code, I kept getting a null value. I spent several hours beating my head against the wall until I read this posting which says you need to add the Profile module back to the web.config, because apparently SharePoint strips it out:
 
<httpModules>
<add name="Profile" type="System.Web.Profile.ProfileModule" />
</httpModules>
 
Finally! The code was working. I wanted to be able to access a given user's profile information so I could retrieve it or save it in the "UserEdit" page in the CKS code. My code now looks like this:
 
UserProfile profile = UserProfile.GetProfile(user.UserName);
Person person = profile.Person;
person.Fax = txtFax.Text;
person.Phone = txtPhone.Text;
profile.Save();
 
The "GetProfile" method is referencing the static method we added to the UserProfile class, which is simply generating a new Profile object that we can access for a particular user. I could just as easily access the UserProfile object for the currently-logged-in user if I were to use code like this:
 
UserProfile profile = (UserProfile)HttpContext.Current.Profile;
 
Here are two blog articles that I found particularly helpful when looking up how to write custom profile code:

Comments

Thanks - Very Helpful

I found this by way of the referenced forum post about the module. Thanks for the tips about using GetPropertyValue and SetPropertyValue to get around the compile-time issues in SharePoint.
 on 8/14/2009 12:17 PM

Thanks Was good

I found one issue after doing the same, I am facing a problem with the database, [dbo].aspnet_Profile Table was been created and was able to add data successfully, but all of a sudden, surprising to me I am getting a error as "Request failed". I think I lost connection between the data base and the WebPart where I am using the above code. Please help me as it is very urgent to resolve this problem
 on 10/1/2009 3:36 PM

Thanks

is there any way to check if property exists w/o using catch (SettingsPropertyNotFoundException)?
 on 11/5/2010 11:34 AM

Does this solution work SP2010

Hi Becky, Thank you for your great post. Do you know if this solution works for SP2010?
 on 2/22/2012 5:28 AM

Thanks

article is great. Worked perrfectly fine.
 on 8/21/2012 11:05 AM

Implemented according to your guidelines

Everything works. Thanks a lot. One thing is that if you use profiles with anonymous access disabled. You might get error - just remove [SettingsAllowAnonymous(true)] or set it to false. And last thing that might not be clear from above guide is that you put <provider> element inside <system.web> element
 on 10/25/2012 5:04 AM

You are awesome.

You don't know how much you helped me. From the past three days i am hitting my head to the wall.. :) Really Excellent work. Wonderful. Worked superb.
 on 4/30/2013 8:43 AM

Thanks a bunch

It took me hours to search through the internet and finally your blog gave the full solution.
Somehow for me the definition of properties didn't work from code, but from web.config only. Yet, it's good enough  for me.
So, again, thanks a lot!
 on 8/2/2013 5:59 AM

Great info but i get this error

Hi I get this error when doing the same kind of solution, when access the ProfileBase

Request for the permission of type 'System.Web.AspNetHostingPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed

Did you get this?
 on 10/14/2013 4:59 AM

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Comment Title *


Body *


Your Name


Your E-mail Address


Your Website

Type the Web address: (Click here to test)  

Type the description: 

Are you spamming my blog? *


This field is here in an attempt to stop spammers from entering comments. Enter a number, any number

Attachments