Asynchronous Model Validation

Categories:
Reading time: 3 minutes

Last week I found some great articles about Domain Driven Design. While I have been trying out various patterns and design principles like Clean Architecture and Domain Driven Design I was still finding out how to implement domain events. While doing some exercises I came up with a solution to validate domain entities with asynchronous validations which I want to share.

I realize I have not written anything here for a while now. Just recently I started a new job and got quite busy with learning new projects. Just last week I found some interesting code I thought might be small but interesting to share in a new post to get started with blogging again.

While I tried some of the sample code provided by Kamil Grzybek I found this piece of code.

private Customer()
{
    this._orders = new List<Order>();
}

public Customer(
    string email, 
    string name, 
    ICustomerUniquenessChecker customerUniquenessChecker)
{
    this.Email = email;
    this.Name = name;

    var isUnique = customerUniquenessChecker.IsUnique(this);
    if (!isUnique)
        throw new BusinessRuleValidationException("Customer with this email already exists.");

    this.AddDomainEvent(new CustomerRegisteredEvent(this));
}

The thing is, I am using EF Core and I implemented every call in my repositories asynchronously. To check if a customer is unique or not I have to execute an asynchronous query which is not going to work in a constructor. I kept thinking about a proper solution to validate a business entity before actually creating it. After a few trials I came up with the following code:

public class Customer
{
    private Customer(string email, string name)
    {
        Email = email;
        Name = name;
    }

    public string Email { get; private set; }
    public string Name { get; private set; }

    public static async Task<Customer> CreateNew(
        string email,
        string name,
        ICustomerUniquenessChecker customerUniquenessChecker)
    {
        if (!EmailValidator.IsValid(email))
            throw new BusinessRuleValidationException($"This email address is not valid: {email}");

        if (!NameValidator.IsValid(name))
            throw new BusinessRuleValidationException($"This name is not valid: {name}");

        var customer = new Customer(email, name);
        var isUnique = await customerUniquenessChecker.IsUnique(customer).ConfigureAwait(false);
        if (!isUnique)
            throw new BusinessRuleValidationException("Customer with this email already exists.");

        return customer;
    }
}

Now, when I want to create a new customer with a unique email address I can use the static method CreateNew in an asynchronous way:

public async Task SomeAsyncMethodInAService(string email, string name)
{
    try
    {
        var newCustomer = await Customer.CreateNew(
            email, 
            name, 
            _customerUniquenessChecker).ConfigureAwait(false);
    }
    catch(BusinessRuleValidationException ex)
    {
        // Do something or remove the try-catch
    }
}

By the way: I did not create an implementation of ICustomerUniquenessChecker, I used a mock in a test project (see the sample code on github)!

While it is nothing special I just like it and wanted to share it. Hope you liked it!

UPDATE: Kamil Grzybek commented on my article and pointed me in this direction: a blog post about Async OOP 2: Constructors by Stephen Cleary.

Comments

comments powered by Disqus