views:

33

answers:

2

I'm using the default SqlMembershipProvider, but I've created a custom MembershipUser class (SoeMembershipUser) because I needed a "DisplayName" property. All the DisplayName does is look at the UserName and format it differently.

When I try to cast a MembershipUser to a SoeMembershipUser user I get an InvalidCastException. Exact error is: "Unable to cast object of type 'System.Web.Security.MembershipUser' to type 'Soe.Tracker.SoeMembershipUser'."

Here is the code that fails:

SoeMembershipUser user = (SoeMembershipUser)Membership.GetUser(username); // invalid cast

I have also tried casting later like so:

MembershipUser user = Membershipship.GetUser(username); // ok
...
string displayName = ((SoeMembershipUser)user).DisplayName; // invalid cast

Here is the SoeMembershipUser class: NOTE: I left off the constructors at first, but added them in later when I started having problems. Adding them made no difference.

public class SoeMembershipUser : MembershipUser
{
    public SoeMembershipUser()
        : base()
    {
    }

    public SoeMembershipUser(string providerName, string name,
        Object providerUserKey, string email, string passwordQuestion,
        string comment, bool isApproved, bool isLockedOut,
        DateTime creationDate, DateTime lastLoginDate,
        DateTime lastActivityDate, DateTime lastPasswordChangedDate,
        DateTime lastLockoutDate)
        : base(providerName, name, providerUserKey, email,
            passwordQuestion, comment, isApproved, isLockedOut,
            creationDate, lastLoginDate, lastActivityDate,
            lastPasswordChangedDate, lastLockoutDate)
    {
    }

    public virtual string DisplayName
    {
        get
        {
            if (UserName.Contains("@"))
                return UserName.Substring(0, UserName.IndexOf("@"));
            return UserName;
        }
    }
}

Any idea why this cast is invalid? Am I just overlooking something simple?

+2  A: 

You are trying to downcast from a base to a derived class (aka a narrowing conversion, as from an Animal to a Dog -- but not every animal is a dog). Create an extension method, ToMembershipUser, that will do the conversion since you know how it should proceed and the compiler doesn't.

Antony Highsky
As an alternative to an extension method, you can use the C# 'explicit' keyword, as exemplified here: http://msdn.microsoft.com/en-us/library/xhbhezf4(v=VS.100).aspx
Antony Highsky
Regarding "explicit": It seems as though I would need to add the explicit operator to the MembershipUser class itself for it to be useful in my situation (unless I'm reading the documentation wrong).
Rick
Yes, you're right -- explicit operator wouldn't work in this case. My bad. Just go with a standalone function or an extension method. Either one should work.
Antony Highsky
It seems like I'm working too hard to get a simple result, but I think I'll end up having to do it this way. It's frustrating because in my case the types are "swappable" (in that they would never conflict if given the chance to run). I do appreciate the analogy, and understand why I get the error though. CS 101...
Rick
+2  A: 

The problem is that you are using the default SqlMembershipProvider. You will have to create a custom MembershipProvider.

You can probably get by with just extending the SqlMembershipProvider on the GetUser methods.

public class SoeMembershipProvider : SqlMembershipProvider
{
    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        var sqlMembershipUser = base.GetUser(providerUserKey, userIsOnline);
        return new SoeMembershipUser(sqlMembershipUser);
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        var sqlMembershipUser = base.GetUser(username, userIsOnline);
        return new SoeMembershipUser(sqlMembershipUser);
    }
}
bendewey
+1 - the two go very much hand in hand :)
Russ Cam
+1 I agree that this would likely solve my problem, but it is not quite as extensible as I'd like since I want to be able to swap Membership Providers in and out for existing systems. Since .NET doesn't allow multiple inheritance, this would cause an issue even if I inherited from MembershipProvider rather than SqlMembershipProvider.
Rick
@Rick I see you accepted the other answer, so I'm assuming you have a plan. Best of luck.
bendewey