Jim Rogers

Lives in Baton Rouge, LA, with two dogs, one cat, and one lovely wife. I'm a lead developer for GCR Incorporated.

Katrin and Jim

Month List

Using Email to Login with ASP.NET Membership

by Jim Jul 06, 2009 9:16 AM

One requirement of my latest job is to login with email, instead of a username. I’ve read some debate about whether this is a good design idea, but here’s how I did it. This post doesn’t cover the setup and use of the membership and controls – just the changes necessary to use the email instead of the username.

First we have to realize that the username must exist – it is the identifier for the user session, among other things. So we have to “fake” the username by creating one when the account is created.

If you haven’t already done this, convert the CreateUserWizard control to a template so that it can be modified. This is an option in the design view, as described here.

The UserName field must exist on the page, or the control will throw an exception. So we’ll move it from the table and hide it with CSS, while deleting the corresponding validation control. The email field is shifted to the top.

<div style="display: none;">
    <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
</div>
<table border="0" cellpadding="4">
    <tr>
        <td >
            <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">
                E-mail:</asp:Label></td>
        <td>
            <asp:TextBox ID="Email" runat="server"></asp:TextBox>
            <asp:RequiredFieldValidator ID="EmailRequired" runat="server" 
                ControlToValidate="Email"
                ErrorMessage="E-mail is required." 
                ToolTip="E-mail is required." 
                ValidationGroup="CreateUserWizard1">
                *</asp:RequiredFieldValidator>
        </td>
    </tr>
    <tr>
        <td></td>
        <td>You will log in with your email address.</td>
    </tr>

Now in the code, we handle the CreatingUser event, which fires before the user is created, and before the username is validated. We just make the username a Guid, to ensure uniqueness.

protected void Page_Load(object sender, EventArgs e)
{
    CreateUserWizard1.CreatingUser += 
        new LoginCancelEventHandler(CreateUserWizard1_CreatingUser);
}

void CreateUserWizard1_CreatingUser(object sender, LoginCancelEventArgs e)
{
    // We're using the email as the login, but it's still neccessary 
    // to have a username. 
    // So we'll create a "fake" one here.
    CreateUserWizard1.UserName = Guid.NewGuid().ToString();
}

No additional code is needed to enforce uniqueness of the email address. The membership system already does this, and will show an error message on the user creation step if a duplicate email is entered.

Now for the login page.

If the user’s login attempt fails, the Login control will show the username in that field. We don’t want this, so we need to hide the UserName field as we did above, and add a field to accept the email instead. The html is similar. In the code, it’s simple to retrieve the username with the email, then let the control finish the login process:

protected void Page_Load(object sender, EventArgs e)
{
    Login1.LoggingIn += new LoginCancelEventHandler(Login1_LoggingIn);
}

void Login1_LoggingIn(object sender, LoginCancelEventArgs e)
{
    string email = ((TextBox)Login1.Controls[0].FindControl("Email")).Text;

    string username = Membership.GetUserNameByEmail(email);

    if (!string.IsNullOrEmpty(username))
    {
        Login1.UserName = username;
    }
}

If the email address is not found, then the user winds up getting the default message of “Your login attempt was not successful. Please try again.” There’s no mention of UserName or Email, so it doesn’t need updating.

We must follow a similar process with the PasswordRecovery control, which will also populate the username if the security question is answered incorrectly.

Tags: ,

Code

Does My Type Subclass a Generic Type?

by Jim Mar 26, 2009 6:42 PM

It’s trivially easy to check if your type subclasses some other type with Type.IsSubclassOf(). But what if that subclass is a generic one? IsSubclassOf() doesn’t work for that.

Enter the IsSubclassOfGeneric() extension method. I’m pretty new to extension methods, and haven’t found a lot of practical uses for then yet, but I like this one. We’re using reflection and generics a lot in my current project and this has been nice in a couple of places…

/// <summary> 
/// Check if a type subclasses a generic type 
/// </summary> 
/// <param name="genericType">The suspected base class</param> 
/// <returns>True if this is indeed a subclass of the given generic type</returns> 
public static bool IsSubclassOfGeneric(this Type type, Type genericType)
{
    Type baseType = type.BaseType;

    while (baseType != null)
    {
        if (baseType.IsGenericType && 
            baseType.GetGenericTypeDefinition() == genericType)
            return true;
        else baseType = baseType.BaseType;
    }
    return false;
}

Tags:

Code

The C# as Operator

by Jim Jan 01, 2009 9:24 PM

It’s code review time!

The as operator is not the same thing as a cast. It is not better, it is different. It is appropriate in some situations, but not in others. Some people us it because they prefer the syntax, but it does different things, and the two are NOT interchangeable.

Using the as operator differs from a cast in C# in three important ways:

  1. It returns null when the variable you are trying to convert is not of the requested type or in its inheritance chain, instead of throwing an exception.
  2. It can only be applied to reference type variables converting to reference types.
  3. Using as will not perform user-defined conversions, such as implicit or explicit conversion operators, which casting syntax will do.

Number three is a good enough reason to prefer the cast as a general rule. By using the as operator you may be circumventing functionality that someone intentionally put into the class you’re referencing!

Here is a hard and fast rule for you:

IF YOU AREN’T GOING TO CHECK FOR THE NULL, DON’T USE THE as OPERATOR.

If there is a bug that results in the type you’re converting being the wrong type, you’ll get a null reference exception – possibly in code that is far from the as operator you used. Someone will have to debug that one day. And they’re going to waste time trying to figure out why the value is null, when they really need to be trying to figure out why the value is of the wrong type.

If you’re going to assume that the object is of a particular type, use the direct cast. This will result in an invalid cast exception, which is informative, and happens right there at the cast. The stack trace and the error message will tell someone precisely what happened and where:

System.InvalidCastException: Unable to cast object of type 'Foo' to type 'Bar'.

Now we know what went wrong – a NullReferenceException doesn’t tell us that.

Tags:

Code

Static Members on Generics

by Jim Oct 24, 2008 9:01 PM

I’m currently porting a library from Java to C# that relies heavily on generics. In the process I’m finding out all sorts of interesting things about generics in C#, including this tidbit:

A static member of a generic class has one instance per closed generic type, NOT one instance for the overall type definition.

So for instance if you have:

public class BadGeneric<T>
{ 
    public static Dictionary<int, string> stuff = new Dictionary<int, string>();
}

and you instantiate instances of this with different type parameters:

BadGeneric<int> test1 = new BadGeneric<int>();
BadGeneric<int> test2 = new BadGeneric<int>();
BadGeneric<string> test3 = new BadGeneric<string>();

you might think you would have one instance of the dictionary - and you would be wrong. The first two share a dictionary, but BadGeneric<string> is a different type, and gets its own separate instance of the dictionary!

Don’t be confused by the fact that Dictionary is itself generic; this happens with all static members, regardless of type. Dictionary is a likely example because it’s the sort of thing you might want to add to in constructors and access across all instances of BadGeneric<>.

Now what?

One solution, explained with much preamble here on CodeProject, is to wrap the static member in a non-generic class, defined separately:

public class GoodGeneric<T>
{
    public static Dictionary<int, string> stuff
    {
        get { return GenericStaticState._stuff; } 
    }
}

internal class GenericStaticState {
    public static Dictionary<int, string> _stuff = new Dictionary<int, string>();
}

Another possibility is to derive the generic class from a non-generic base:

public abstract class NonGenericBase {
    public static Dictionary<int, string> _stuff = new Dictionary<int, string>();
}

public class Generic<T> : NonGenericBase { 
    public static Dictionary<int, string> stuff
    {
        get { return _stuff; }
    }
}

I think the first is probably a little cleaner, unless you’re using a non-generic base anyway, or an interface that could be converted to one. But don’t see any particular weaknesses with either method.

Tags:

Code

HttpWebRequest 401

by Jim Jul 22, 2008 9:12 AM

Getting data with HttpWebRequest is straightforward, until it isn't...

My program stopped working recently, returning a 401 unauthorized from my request. I knew I was sending the right credentials.

A random newsgroup thread tipped me off to the solution:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
request.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, " + 
    "application/vnd.ms-excel, application/vnd.ms-powerpoint, " + 
    "application/msword, */*";
WebResponse response = request.GetResponse();

The key is setting the Accept property; I wasn't doing that before. I don't know what happened on the server that makes it now require this header, but now it works...