干净架构中的用户实体

Tom*_*Tom 5 .net c# domain-driven-design asp.net-identity clean-architecture

我正在使用Jason Taylor Clean Architecture 模板创建一个新的 Web 应用程序。我的应用程序必须支持帖子和用户实体,并且这些实体是相关的。一个用户可以创建多个帖子。

现在我想实现这个用户实体,以便使用我的应用程序的人可以使用这些用户登录。通常我只会使用 ASP.NET Core Identity,但由于我需要在域项目中引用该引用,并且该项目应该独立于任何框架,所以我无法这样做。

这种情况我该怎么办?

afh*_*afh 4

如果您使用唯一标识符(例如 GUID、用户名、电子邮件等)引用某个域实体中的用户实体,为什么您的域模型中会有框架依赖项?

只是不要使用框架层中的某些身份类作为类成员(字段),而是使用原始类型(例如字符串),或者更好的是,使用一些自定义值对象类来代替我提到的用户身份唯一标识符。例如,您可以将其称为UserId

这样,您就已经将身份框架(可以被视为基础设施层的一部分)与域层完全解耦。

例如,如果您有一个需要了解客户(或买家)的Order域模型实体,您不使用身份层中的ApplicationUser类,而是仅使用独立于框架的用户 ID 类型UserId

您可以查看Microsoft eshopOnWeb以了解如何完成此操作的一些示例。

此示例显示了Order 域实体

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里您可以看到,对用户的引用只是通过字符串引用,这里是BuyerId 属性,它不会将任何身份框架依赖项引入域层。如果应用程序中的某个点需要用户身份对象,则可以从订单实体查询该买家 ID,并且可以从域层外部的基础设施请求用户身份对象。

在Order实体中应用的相同模式也可以应用于您的Post 实体,例如,通过引用用户的AuthorId属性之类的内容,该属性可以是域层中定义的某个字符串或自定义类(值对象)。