标签:
上一篇:《DDD 领域驱动设计-如何控制业务流程?》
开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新,并增加了应用层代码)
在 JsPermissionApply 领域模型中,User 被设计为值对象,也就是 JsPermissionApply 实体中的 UserId 属性,这个没啥问题,但后来再实现代码的时候,就出现了一些问题,在 JS 权限申请和审核系统中,用户的一些操作如下:
对于上面的四个用户操作,因为每个请求都会耗费时间,所以我们需要尽量简化其操作,尤其是第四个操作,如果管理员要审核 10 个申请,那么就得请求用户服务 10 次,那怎么省掉这个操作呢?就是用户在申请 JS 权限的时候,我们先获取用户信息,然后存在 JsPermissionApply 实体中,如何这样设计,那么第二个用户验证操作,也可以省掉。
代码如何实现?我之前想在 JsPermissionApply 实体中,直接增加如下值对象:
public int UserId { get; set; }
public string UserLoginName { get; set; }
public string UserDisplayName { get; set; }
public string UserEmail { get; set; }
public string UserAlias { get; set; }
这样实现也没什么问题,但 JsPermissionApply 实体的构造函数参数赋值,就变的很麻烦,UserId 标识一个 User,那一个 User 也是标识一个 User,所以我们可以直接把 User 设计为值对象,示例代码:
namespace CNBlogs.Apply.Domain.ValueObjects
{
public class User
{
public string LoginName { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string Alias { get; set; }
[JsonProperty("SpaceUserID")]
public int Id { get; set; }
}
}
JsonProperty 的作用是在 UserService 获取用户信息的时候,映射源属性名称,GetUserByLoginName 示例代码:
namespace CNBlogs.Apply.ServiceAgent
{
public class UserService
{
private static string userHost = "";
public static async Task<User> GetUserByLoginName(string loginName)
{
using (var httpCilent = new HttpClient())
{
httpCilent.BaseAddress = new System.Uri(userHost);
var response = await httpCilent.GetAsync($"/users?loginName={Uri.EscapeDataString(loginName)}");
if (response.StatusCode == HttpStatusCode.OK)
{
return await response.Content.ReadAsAsync<CNBlogs.Apply.Domain.ValueObjects.User>();
}
return null;
}
}
}
}
JsPermissionApply 实体代码:
namespace CNBlogs.Apply.Domain
{
public class JsPermissionApply : IAggregateRoot
{
private IEventBus eventBus;
public JsPermissionApply()
{ }
public JsPermissionApply(string reason, User user, string ip)
{
if (string.IsNullOrEmpty(reason))
{
throw new ArgumentException("申请内容不能为空");
}
if (reason.Length > 3000)
{
throw new ArgumentException("申请内容超出最大长度");
}
if (user == null)
{
throw new ArgumentException("用户为null");
}
if (user.Id == 0)
{
throw new ArgumentException("用户Id为0");
}
this.Reason = HttpUtility.HtmlEncode(reason);
this.User = user;
this.Ip = ip;
this.Status = Status.Wait;
}
public int Id { get; private set; }
public string Reason { get; private set; }
public virtual User User { get; private set; }
public Status Status { get; private set; } = Status.Wait;
public string Ip { get; private set; }
public DateTime ApplyTime { get; private set; } = DateTime.Now;
public string ReplyContent { get; private set; }
public DateTime? ApprovedTime { get; private set; }
public bool IsActive { get; private set; } = true;
public async Task<bool> Pass()
{
if (this.Status != Status.Wait)
{
return false;
}
this.Status = Status.Pass;
this.ApprovedTime = DateTime.Now;
this.ReplyContent = "恭喜您!您的JS权限申请已通过审批。";
eventBus = IocContainer.Default.Resolve<IEventBus>();
await eventBus.Publish(new JsPermissionOpenedEvent() { UserId = this.User.Id });
return true;
}
public