5

I am using Jason Taylor Clean Architecture template to create a new web application. My application will have to support post and user entities and those entities are related together. One user can create many posts.

Now I want to implement this user entity so that people who use my app can log in using these users. Normally I would just use ASP.NET Core Identity, but since I need that reference in the Domain project and that project should be independent of any framework I can't do that.

What should I do in this case?

1 Answer 1

3

If you reference a user entity in some domain entity by using a unique identifier (e.g. a GUID, username, email, etc.) why would you then have a framework dependency in your domain model?

Just don't use some identity class from the framework layer as a class member (field) but use a primitive type (e.g. a string), or even better, some custom value object class instead that represents that user identity unique identifier I mentioned. You could, for instance, call it UserId.

With that you have completely decoupled the identity framework (which can be considered as part of the infrastructure layer) from your domain layer.

For instance, if you have an Order domain model entity which needs to know the Customer (or buyer) you do not use the ApplicationUser class from the identity layer but rather use just the framework independent user id type UserId.

You can look into the Microsoft eshopOnWeb for some example how this can be done.

This example shows the Order domain entity:

public class Order : BaseEntity, IAggregateRoot
{
    private Order()
    {
        // required by EF
    }

    public Order(string buyerId, Address shipToAddress, List<OrderItem> items)
    {
        Guard.Against.NullOrEmpty(buyerId, nameof(buyerId));
        Guard.Against.Null(shipToAddress, nameof(shipToAddress));
        Guard.Against.Null(items, nameof(items));

        BuyerId = buyerId;
        ShipToAddress = shipToAddress;
        _orderItems = items;
    }

    public string BuyerId { get; private set; }
    public DateTimeOffset OrderDate { get; private set; } = DateTimeOffset.Now;
    public Address ShipToAddress { get; private set; }

    // DDD Patterns comment
    // Using a private collection field, better for DDD Aggregate's encapsulation
    // so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection,
    // but only through the method Order.AddOrderItem() which includes behavior.
    private readonly List<OrderItem> _orderItems = new List<OrderItem>();

    // Using List<>.AsReadOnly() 
    // This will create a read only wrapper around the private list so is protected against "external updates".
    // It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance)
    //https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx 
    public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly();

    public decimal Total()
    {
        var total = 0m;
        foreach (var item in _orderItems)
        {
            total += item.UnitPrice * item.Units;
        }
        return total;
    }
}

Here you can see, that the reference to the user is simply referenced by a string, here the BuyerId property, which does not introduce any identity framework dependencies into the domain layer. If the user identity object is required at some point in the application this buyer id can be queried from the order entity and than the user identity object can be requested from the infrastructure outside the domain layer.

The same pattern applied in the Order entity can also be applied to your Post entity, e.g. by having something like an AuthorId property referencing the user which can either be some string or custom class (value object) defined in the domain layer.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.