Introduction
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).
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.