Dealing with Profile Access in ASP.NET MVC Applications

Wednesday Dec 21st 2011 by Bipin Joshi
Share:

While developing a Web Forms based website project developers can access profile properties in a strongly typed fashion. ASP.NET MVC and Web Application projects, however, lack this handy and useful feature. In this article Bipin Joshi shows you how to access user Profile in ASP.NET MVC applications as well as an alternative to overcoming this limitation.

Introduction

ASP.NET services such as Profile are available to MVC applications too and developers can make use of them when needed. While developing a Web Forms based website project developers can access profile properties in a strongly typed fashion. This strongly typed nature comes from the ProfileCommon class that is generated automatically in such projects. ASP.NET MVC and Web Application projects, however, lack this handy and useful feature. In this article you will learn how to access user Profile in ASP.NET MVC applications and also an alternative to overcome this limitation.

Enabling Profile Features for an ASP.NET MVC Application

Before you deal with profile properties, you must configure a SQL Server database for storing membership and profile information. We will not be discussing these preliminary steps in this article. Read "Using Forms Authentication in ASP.NET MVC Applications" and follow the instructions to enable these features for your database. We will also skip detailed code level discussion of utilizing membership features as discussed in the above article. The source code accompanying this article includes all the necessary controllers and views that make use of membership features for authenticating the user. For the sake of this article, we will assume that you already have an ASP.NET MVC Application  with SQL Express database residing in the App_Data folder. The following figure shows the Solution Explorer with SQL Express database and other files.

Solution Explorer with SQL Express database
Figure 1: Solution Explorer with SQL Express database

Configuring a Profile Provider in ASP.NET MVC Application

In order to use Profile features you must configure a Profile provider in web.config file. Open web.config file and add the following markup under <system.web> section:

<profile enabled="true" defaultProvider="MyProfileProvider">

  <providers>

    <add name="MyProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="connstr" />

  </providers>

  <properties>

    <add name="FirstName" />

    <add name="LastName" />

  </properties>

</profile>

The <profile> section enables Profile features for your application and also defines a Profile provider - MyProfileProvider. Further, it defines two Profile properties viz. FirstName and LastName. You will be setting these Profile properties in the CreateUser() action method of MembershipController. Have a look at the following code fragment:

    [HttpPost]

    public ActionResult CreateUser(CreateUserData data)

    {

        MembershipCreateStatus status;

        Membership.CreateUser(data.UserID,data.Password,data.Email,data.Question,data.Answer,true, out status);



        if (status == MembershipCreateStatus.Success)

        {

            //Set FirstName and LastName properties here

 

            ViewBag.StatusMessage = "User created successfully!";

        }

        else

        {

            ViewBag.StatusMessage = "Error creating user account!";

        }

        return View("CreateUserStatus");

    }

This way when a new user is registering with the system he can specify FirstName and LastName properties. The Profile properties can then be read in other parts of the application.

Defining the Problem

If you would have been working with an ASP.NET Website project, you would have accessed the Profile properties as shown below:

//Set profile properties

Profile.FirstName = "Tom";

Profile.LastName = "Jerry";

 

//Get profile properties

string fname = Profile.FirstName;

string lname=Profile.LastName

If you carefully observe Visual Studio intellisense while accessing the profile properties you should notice the ProfileCommon class as shown below:

ProfileCommon class
Figure 2: ProfileCommon class

The Profile object is actually an instance of ProfileCommon class. The ProfileCommon class gets generated on the fly for a particular website and contains properties equivalent to profile properties defined in the <properties> section. This way you can access FirstName and LastName profile properties in strongly typed fashion. The ProfileCommon class is not generated for ASP.NET MVC and ASP.NET Web Application project types. Since there is no ProfileCommon class you can't access profile properties in a strongly typed way.

Three Ways to Access Profile Properties

To access profile properties in ASP.NET MVC (and Web Application) projects you can resort to any of the following ways:

  • Use ProfileBase class indexer and access profile properties.
  • Create a custom class that inherits from ProfileBase class and mimic the behavior of ProfileCommon class.
  • Create a custom DynamicObject and set profile properties dynamically.

In the following sections, we will discuss each of these ways in detail.

Accessing Profile Properties using ProfileBase Indexer

The most basic way of accessing profile properties is by using ProfileBase class indexer. Have a look at the following piece of code:

[HttpPost]

public ActionResult CreateUser(CreateUserData data)

{

    MembershipCreateStatus status;

    Membership.CreateUser(data.UserID,data.Password,data.Email,data.Question,data.Answer,true, out status);



    if (status == MembershipCreateStatus.Success)

    {

        ProfileBase profile = ProfileBase.Create(data.UserID);

        profile["FirstName"] = data.FirstName;

        profile["LastName"] = data.LastName;

        profile.Save();

    }

    ....

    ....

}

The above code uses Create() method of ProfileBase class to get a ProfileBase object for a specified user. It then uses indexer syntax to set FirstName and LastName profile properties. Finally, Save() method is called that persists the assigned values in the database.

The drawback of this method of accessing profile properties is that it doesn't provide strongly typed access to them. You must know the profile properties defined in the web.config file. Any error in the profile property names will result in an exception at run time (see below).

Any error in the profile property names will result in an exception at run time
Figure 3: Any error in the profile property names will result in an exception at run time

Accessing Profile Properties Using a Custom Profile Class

Now, let's see how to bring back the strongly typed access to profile properties in an ASP.NET MVC application. In this technique, you will create a custom profile class that inherits from ProfileBase class. You will then add property definitions to this class as per your requirement. Finally, you will add a small configuration information so that ASP.NET is aware of your custom class.

Begin by adding a new class in the Models folder and name it as Profile. Next, code the Profile class as shown below:

public class Profile : ProfileBase

{

    public static Profile GetCurrent()

    {

        return (Profile)Create(Membership.GetUser().UserName);

    }

 

    public static Profile GetProfile(string userId)

    {

        return (Profile)Create(userId);

    }

 

    public string FirstName

    {

        get

        {

            return base["FirstName"] as string;

        }

        set

        {

            base["FirstName"] = value;

            Save();

        }

    }

 

    public string LastName

    {

        get

        {

            return base["LastName"] as string;

        }

        set

        {

            base["LastName"] = value;

            Save();

        }

    }

 

}

As you can see, the Profile class has two static methods - GetCurrent() and GetProfile(). The GetCurrent() method returns a Profile object for the currently logged in user whereas GetProfile() method returns a Profile object for a specific user. The Profile class also defines two public properties - FirstName and LastName. The "set" property of both the profile properties calls Save() method of ProfileBase base class so as to save the new property value immediately. If you prefer to save them at one go rather than individually you can also call Save() method in the calling code.

Now, open the web.config file again and modify the <profile> section as shown below:

<profile enabled="true" defaultProvider="MyProfileProvider" inherits="AuthInMVC.Models.Profile">

As you can see, the <profile> element now has inherits attribute that points to the fully qualified name of the custom profile class. This way ASP.NET knows about your custom profile class. Also, comment out the <properties> section you  added earlier. After making these changes you can set profile properties in the code as follows:

Profile profile = Profile.GetProfile(data.UserID);

profile.FirstName = data.FirstName;

profile.LastName = data.LastName;

profile.Save();

In order to retrieve profile properties for a logged-in user you will write:

Profile profile = Profile.GetCurrent();

ViewBag.DisplayName = profile.FirstName + " " + profile.LastName; 

Accessing Profile Properties Using a DynamicObject

The third technique that can be used to access profile properties is using a custom Dynamic Object. Normally when you wish to use some object in your code, you first need to create a class and write properties and methods in it. You can then create objects of that class, set their properties and invoke methods on them. Using dynamic objects, however, you can add properties to an object dynamically. One example of such a dynamic object can be found in ASP.NET MVC 3 itself. Consider the following piece of code written in a controller class:

ViewBag.StatusMessage = "Data saved successfully!";

ViewBag.StatusCode = "100";

ViewBag.LogDate = DateTime.Now;

ASP.NET MVC 3 provides a ViewBag object that allows you to store arbitrary values that you wish to pass to the View. As illustrated in the above example, you simply set properties on the ViewBag object as if they are coded in the ViewBag object itself. In reality, ViewBag doesn't contain any property definitions for StatusMessage, StatusCode and LogDate (these names are developer defined and you can use any valid name there). In other words, you added properties dynamically to the ViewBag object.

The System.Dynamic namespaces provides DynamicObject class that can be used to create your own custom dynamic object. In order to create your own dynamic object using DynamicObject class you need to inherit it from DynamicObject and override three methods, viz. TryGetMember, TrySetMember and TryInvokeMember. The first two methods allow you to get and set dynamic properties whereas the last method allows you to invoke method calls on the dynamic object. Let's create a DynamicProfile class that does just that. Add another class to Models folder and name it as DynamicProfile. Key-in the following code in the DynamicProfile class.

public class DynamicProfile : DynamicObject

{

    ProfileBase profile = null;

 

    public DynamicProfile()

    {

        profile = ProfileBase.Create(Membership.GetUser().UserName);

    }

 

    public DynamicProfile(string userId)

    {

        profile = ProfileBase.Create(userId);

    }

 

    public override bool TryGetMember(GetMemberBinder binder, out object result)

    {

        try

        {

            result = profile[binder.Name];

            return true;

        }

        catch

        {

            result = "Invalid Profile Property";

            return false;

        }

    }

 

    public override bool TrySetMember(SetMemberBinder binder, object value)

    {

        try

        {

            profile[binder.Name] = value;

            profile.Save();

            return true;

        }

        catch

        {

            return false;

        }

    }

 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)

    {

        if (binder.Name == "Save")

        {

            profile.Save();

            result = null;

            return true;

        }

        else

        {

            throw new NotSupportedException("Only Save method is supported!");

        }

    }

}

The DynamicProfile class inherits from DynamicObject base class. There are two overloads for the constructor. The first one instantiates a ProfileBase class for currently logged in user whereas the second one instantiates a ProfileBase class for a specific user. The TrySetMember() method sets a profile property value by using ProfileBase indexer. On the same lines, TryGetMember() method retrieves a profile property value using ProfileBase indexer. The TryInvokeMember() method ensures that only Save() method can be called on the DynamicProfile class and is intended to persist the profile property values. Detailed discussion of creating dynamic objects is beyond the scope of this article. See Using DynamicObject and ExpandoObject for more details.

Once the DynamicProfile class is ready you can assign the profile properties as shown below:

dynamic profile = new DynamicProfile(data.UserID);

profile.FirstName = data.FirstName;

profile.LastName = data.LastName;

profile.Save();

As you can see, the above code uses a dynamic keyword to create a dynamic object. It then assigns the profile properties FirstName and LastName. To retrieve the profile properties you will write:

dynamic profile = new DynamicProfile();

ViewBag.DisplayName = profile.FirstName + " " + profile.LastName;

Note that while using DynamicProfile, any errors in property names will still generate runtime exceptions. However, the overall usage is simplified as compared to using ProfileBase directly.

Summary

ASP.NET Website projects automatically generate ProfileCommon class so that profile properties can be accessed in strongly typed fashion. This feature is not available to ASP.NET MVC applications. However, with some efforts you can achieve the same effect in MVC applications too. This article discussed three ways of accessing profile properties in ASP.NET MVC applications. The first way involves using ProfileBase indexer and is a primitive way of dealing with profile properties. The second way is to create a custom class inheriting from ProfileBase class and then adding property definitions to it. Using this second approach you can access profile properties in a strongly typed way. The downside, however, is that you need to create an extra class and ensure that all profile properties have equivalent properties in the custom class. The third approach is using a dynamic object. Though this approach is not exactly the same as the second one, it does simplify coding. Depending on your need you can go for any one of these approaches.

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved