我正在使用Jason Taylor Clean Architecture模板创建一个新的web应用程序。我的应用程序必须支持帖子和用户实体,并且这些实体是相关的。一个用户可以创建多个帖子。
现在我想实现这个用户实体,这样使用我的应用程序的人就可以使用这些用户登录。通常我只会使用ASP.NET Core Identity,但由于我在Domain项目中需要该引用,并且该项目应该独立于任何框架,所以我不能这样做。
这种情况下我该怎么办?
如果您通过使用唯一标识符(例如GUID、用户名、电子邮件等(引用某个域实体中的用户实体,为什么您的域模型中会有框架依赖关系?
只是不要使用框架层的一些标识类作为类成员(字段(,而是使用基元类型(例如字符串(,或者更好的是,使用一些自定义的值对象类,它代表我提到的用户标识唯一标识符。例如,您可以将其称为UserId。
这样,您就可以将身份框架(可以被视为基础结构层的一部分(与域层完全解耦。
例如,如果您有一个Order域模型实体,它需要知道Customer(或buyer(,则不使用来自标识层的ApplicationUser类,而只使用与框架无关的用户id类型UserId。
您可以查看Microsoft eshopOnWeb,了解如何做到这一点。
此示例显示订单域实体:
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;
}
}
在这里,您可以看到,对用户的引用只是由一个字符串引用的,这里是BuyerId属性,它不会在域层中引入任何身份框架依赖项。如果在应用程序中的某个时刻需要用户标识对象,则可以从订单实体查询该买家id,然后可以从域层之外的基础设施请求用户标识对象。
在Order实体中应用的相同模式也可以应用于Post实体,例如,通过具有引用用户的AuthorId属性,该属性可以是域层中定义的某个字符串或自定义类(值对象(。