Create a Custom Profile Provider in ASP.NET 2.0 Using LINQ To SQL For Kicks

Create a Custom Profile Provider in ASP.NET 2.0 Using LINQ To SQL For Kicks

by David Hayden ( Microsoft MVP C# ), Filed: ASP.NET 2.0

 

For kicks I thought I would create a rough and not totally complete Custom Profile Provider using LINQ To SQL since I was creating a custom profile provider for an application today anyway ( not using LINQ To SQL ). The process for creating a custom profile provider is very similar to creating custom membership and role providers as mentioned in the following tutorials:

 

ProfileProvider information is stored in the Web.config file. In the Profile ConfigurationSection one registers the custom profile provider, called CustomProfileProvider, as the default provider:

 

<profile

    enabled="true"

    defaultProvider="CustomProfileProvider">

 

    <providers>

        <clear />

        <add

            name="CustomProfileProvider"

            type="Providers.CustomProfileProvider, Providers"

            ApplicationName="Test" />

    </providers>

 

    <properties>

        <add name="ZipCode" allowAnonymous="false" />

        <add name="Phone" allowAnonymous="false" />

    </properties>

</profile>

 

Two properties will be tracked as part of the user profile: ZipCode and Phone, which are of type String.

Next, I need to create the CustomProfileProvider which will inherit from ProfileProvider and override its abstract properties and methods. As with custom membership and role providers, I don't need to implement all the abstract members right away, the two key methods that need to be implemented are GetPropertyValues and SetPropertyValues, which are used to get and save profile data to the datastore.

Here is a rough cut of the CustomProfileProvider Class:

 

public class CustomProfileProvider : ProfileProvider

{

    private string _applicationName;

    private readonly IProfileDataRepository _repository;

 

    public CustomProfileProvider()

    {

        _repository = ServiceLocator.Request<IProfileDataRepository>();

    }

 

    public CustomProfileProvider(IProfileDataRepository repository)

    {

        if (repository == null)

            throw new ArgumentNullException("repository");

        _repository = repository;

    }

 

    public override void Initialize(string name, NameValueCollection config)

    {

        if (config == null)

            throw new ArgumentNullException("config");

 

        if (string.IsNullOrEmpty(name))

            name = "CustomProfileProvider";

 

        if (string.IsNullOrEmpty(config["description"]))

        {

            config.Remove("description");

            config.Add("description", "My custom profile provider.");

        }

 

        _applicationName = config["ApplicationName"];

 

        base.Initialize(name, config);

    }

 

    public override string ApplicationName

    {

        get

        {

            return _applicationName;

        }

        set

        {

            _applicationName = value;

        }

    }

 

    public override SettingsPropertyValueCollection
       GetPropertyValues(SettingsContext context,
        SettingsPropertyCollection collection)

    {

        ProfileData data =

            _repository.FetchProfileData(context["UserName"].ToString(),
                  _applicationName,

                  !(bool) context["IsAuthenticated"]);

 

        return new ProfileDataConverter()

            .ConvertToSettingsPropertyValueCollection(collection, data);

 

    }

 

    public override void SetPropertyValues(SettingsContext context,
       SettingsPropertyValueCollection collection)

    {

        ProfileData data = new ProfileDataConverter()

            .ConvertFromSettingsPropertyValueCollection(collection);

 

        _repository.SaveProfileData(context["UserName"].ToString(),
               _applicationName, !(bool)context["IsAuthenticated"], data);

    }

}

 

IProfileDataRepository is responsible for saving and retrieving the data from the datastore and there is a ProfileDataConverter Class that converts ProfileData to and from a SettingsPropertyCollection used by the profile system. Note that the actual datastore could be a database or anything else. I created an implementation, called LINQProfileDataRepository that uses LINQ To SQL to access custom profile information from SQL Server. The tables in the database are called Profiles and ProfileData:

 

Custom Profile Provider Database Tables

 

The tables were dragged and dropped from Server Explorer on the LINQ To SQL Visual Designer Surface as follows:

 

LINQ To SQL Custom Profile Provider

 

The LINQProfileDataRepository looks as follows:

 

public class LINQProfileDataRepository : IProfileDataRepository
{
    public ProfileData FetchProfileData(string userName,
        string applicationName, bool isAnonymous)
    {
        using (ProfileDbDataContext db =
                    new ProfileDbDataContext())
        {
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Profile>(p => p.ProfileDatas);
            db.LoadOptions = options;
            Profile profile =
                db.Profiles.Single<Profile>(p =>
                p.UserName.Equals(userName) &&
                p.ApplicationName.Equals(applicationName) &&
                p.IsAnonymous == isAnonymous);
            return profile.ProfileDatas[0];
        }
    }

    public void SaveProfileData(string userName,
        string applicationName, bool isAnonymous,
        ProfileData data)
    {
        using (ProfileDbDataContext db =
                    new ProfileDbDataContext())
        {
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Profile>(p => p.ProfileDatas);
            db.LoadOptions = options;
            Profile profile = 
                db.Profiles.Single<Profile>(p =>
                p.UserName.Equals(userName) &&
                p.ApplicationName.Equals(applicationName) &&
                p.IsAnonymous == isAnonymous);

            ProfileData existingData = profile.ProfileDatas[0];
            existingData.Phone = data.Phone;
            existingData.ZipCode = data.ZipCode;
            db.SubmitChanges();
        }
    }
}

 

It is a pretty rough implementation done in a short amount of time, but it provides an idea of how one might go about using LINQ To SQL to store and retrieve custom profile information in a SQL Server Database. Personally I would stick with a couple of stored procedures and leave LINQ To SQL to more interesting matters.

 

News Feed: David Hayden ( Microsoft MVP C# ), Filed: ASP.NET 2.0

 

posted on Tuesday, October 30, 2007 4:30 PM

Main

News

Green Tea

.NET Development

Enterprise Library

Patterns & Practices