Application Services III: implementing a win forms credential provider
In the last post on the series we've seen how we can use the new ClientFormsAuthenticationMembershipProvider to authenticate a user. Today we're going to see how we can implement the IClientFormsAuthenticationCredentialsProvider in order to create or own windows forms login form. The IClientFormsAuthenticationCredentialsProvider interface has only one method: GetCredentials. This method returns an instance of the ClientFormsAuthenticationCredentials which is responsible for keeping the login information that is going to be validated (ie, it will have to be filled with the username, password and the remember me field).
The idea here is that you should build a class that implements the interface. This class will be responsible for getting the necessary data and packaging it into an instance of the ClientFormsAuthenticationCredentials. The recommended way of doing this is to create a new form which has the necessary windows forms' controls for getting the necessary data and implements the previous interface.
Ok, now that we know the theory, lets see how easy it is. Suppose that we've already created a new Form (called Login) which has two textboxes (txtUsername and txtPassword). I could also have added a remember me checkbox, but I've decided to always ask for the credentials during a login operation. This is what I've got:
public partial class Login : Form, IClientFormsAuthenticationCredentialsProvider
private String a = "";
public ClientFormsAuthenticationCredentials GetCredentials()
if( this.ShowDialog() == DialogResult.OK)
return new ClientFormsAuthenticationCredentials(txtUsername.Text, txtPassword.Text, false);
The code might be a little different from what you'd expect:
- the form is responsible for showing itself to the user. You may be used to creating a new form and then calling ShowDialog over that instance. That would have worked here too, but you'd have to write additional code so that you could get the values from the textboxes. This approach is much more simple and involves writing less code (that makes it a clear winner, right :) );
- If the user doesn't hit the OK, I just return null. This will automatically cancel the current login process.
By now you may be thinking on how you configure your windows forms app to use this new class. First, you need to setup the provider on the app.config file so that it knows that your app has a credentials provider. To do this, we need to setup the credentialsProvider attribute when we add the provider:
type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=184.108.40.206, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
credentialsProvider="login.Login, login" />
Now, to automatically get the credentials provider instantiated you only need to call the Membership.ValidateUser but this time you need to pass empty strings for both the username and password parameters:
static class Program
static void Main()
if(! Membership.ValidateUser("", "") )
If you run the previous code (I'm assuming that you've already set up the server side as explained before), you'll automatically get the login dialog when the ValidateUser method is called. As a bonus, you'll see that you'll have 3 chances for getting the introducing the correct credentials. If you miss those three attempts and have similar code to the one I've show above, the application will be automatically terminated (it won't run the main form).
What could have been a cool feature ended up being a "wanna be" cool feature. Unfortunately, you cannot setup the number of retries. It's simply hard coded to three, as you can see by looking at the ValidateUserCore method with .NET Reflector. Now, I can tell you that I've tried understanding this, but I simply didn't found any good explanation for this behavior. After all, how hard would it be to get the number of retries from an attribute that would be setup on the app.config file???
Anyway, there are still one or two things to talk about these providers, but I'll leave them for a future post.