Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Pragmatic CQRS: Verifying Username Uniqueness When Registering a New User

5.00/5 (1 vote)
21 Nov 2011CPOL1 min read 15K  
In this article, I will show you a proper way to resolve the issue respecting CQRS/DDD principles

Introduction

Most people who get started with CQRS have issues with this classical example: "how do we verify username uniqueness when a new user registers?"

While user authentication is something that has been implemented numerous amounts of times before, and one should usually not reinvent the wheel but use an existing software library for this particular case, the problem in itself is rather interesting, and happens quite a lot in a domain.

When a user registers with a unique username
Then that registration should be approved
Given a user registration with a certain username was approved
When a new user registers with the same username
Then that registration should be rejected

In this small article, I will show you a simple and proper way to resolve the issue respecting CQRS/DDD principles.

Is That Really What We Want?

Let us think about another way to solve the issue. I will rewrite the scenario a little bit:

When a user registers with a certain username
Then that registration should be pending
Given a user registration with a certain username was approved
When a new user registers with the same username
Then that registration should be pending

Great, Now We Have A Pending Registration! How Is That Helpful?

Not so quick! I have a rule of thumb: whenever I have to communicate between different ARs (even the ones of the same AR type), I use a saga. What is uniqueness validation when you think about it ? Exactly!! A question to all the other ARs whether an entity with the same properties exists. So let us have a second scenario for the saga:

Given a user registration with a certain username is pending
When the information is processed
Then it will approve the registration with that username
Given a user registration with a certain username has been approved
Given a user registration with the same username is pending
When the information is processed
Then it will reject the registration with that username

Please note that scenarios for sagas are a little different:

Given [something happened]
When [all the sagas have processed the events]
Then [a command should be issued]

Example Code

C#
public class UserRegistrationSaga
{
    IIndexStore indexstore;
    IRunCommand bus;
    
    public UserRegistrationSaga(IRunCommand bus,IIndexStore indexstore )
    {
        this.indexstore= indexstore;
        this.bus = bus;
    }
    
    public void OnUserRegistrationPending(string UserRegistrationId,string Username)
    {
        if (indexstore.ContainsValue<string>("RegistrationUsername",Username))
        {
            bus.RunCommand(new RejectUserRegistration { UserRegistrationId = UserRegistrationId, 
              Reason = "Username "+Username+" is already in use"});
        }
        else
        {
            indexstore.Add<string>("RegistrationUsername",Username);
            bus.RunCommand(new ApproveUserRegistration { 
                UserRegistrationId = UserRegistrationId, Username=Username });
        }
    }
    
    public void OnUserRegistrationApproved(string UserRegistrationId,string Username)
    {
        if (!indexstore.ContainsValue<string>("RegistrationUsername",Username))
        {
            indexstore.Add<string>("RegistrationUsername",Username);
        }
    }
    
    public void OnUserRegistrationRejected(string UserRegistrationId,string Username)
    {
        if (indexstore.ContainsValue<string>("RegistrationUsername",Username))
        {
            indexstore.Remove<string>("RegistrationUsername",Username);
        }
    }
}

Conclusion

There you have it, a simple and elegant solution to a problem everybody struggles with in the beginning.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)