Gui*_*ira 6 c# rest domain-driven-design event-sourcing
我正在尝试在REST Api中实现Json PATCH以更新事件源聚合,但我正在努力做到这一点.
我不想创建Anemic Model,因此我的Aggregate Root属性是私有的.出于这个原因,我无法使用ASP.NET Json PATCH库修补我的对象.
有什么技术可以实现这一点,或者我在尝试在事件源聚合上应用补丁时做错了什么?
示例:您将如何在Greg Young SimpleCQRS示例中修补InventoryItem ?
示例:您将如何在Greg Young SimpleCQRS示例中修补InventoryItem?
你可能不会. 与PUT一样,PATCH支持贫血数据存储的语义."使您的表示看起来像我的"意味着您正在控制远离远程域模型.您不应该告诉域模型下一个状态,您应该告诉它该做什么.
那就是说,让我们仔细看看PATCH
PATCH方法请求将请求实体中描述的一组更改应用于Request-URI标识的资源.该组更改以称为"补丁文档"的格式表示,该格式由媒体类型标识.
因此,在这种情况下,媒体类型将定义要应用于模型的零个或多个命令的列表的处理规则.从概念上讲,它类似于JSON-Patch,因为该文档描述了资源应用的一系列操作.
需要明确的是,JSON-Patch不是正确的媒体类型; 语义错了.因此,如果有人尝试JSON-Patch您的InventoryItem,那么您应该发回415不支持的媒体类型和严厉的注释.
例如,如果您查看Event Store的HTTP文档,您将看到写入流使用定制的媒体类型来描述事件:application/vnd.eventstore.events+json.
如果你看一下非常仔细,你会看到使用的方法是POST,而不是补丁.
记住,您的API中的资源与模型中的聚合之间存在一些间接性,这可能是个好主意.以下是Jim Webber描述它的方式
网络不是您的域名,它是一个文档管理系统.所有HTTP谓词都适用于文档管理域.URI不会映射到域对象 - 这违反了封装.工作(例如:向域模型发出命令)是管理资源的副作用.换句话说,资源是反腐败层的一部分.您应该希望集成域中的资源比业务域中的业务对象多得多.
资源使您的域模型适应Web
所以这就是重点:如果你打算使用PATCH(或PUT,那么),那么你提出的习惯是客户端获取资源的表示,修改该表示,然后将其返回给API ,此时API需要弄清楚这些更改实际意味着什么域命令.
以库存项目为例; 如果我们在模型外,看着库存项目的表示,那么我们通常希望以一个读模式,因此表现可能看起来像
GET /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
{
"Id": "ef4454ae-4a82-4bf2-82e1-3da9229ecc94",
"Version": 7,
"Name" : "REST in Practice",
"CurrentCount": 20
}
Run Code Online (Sandbox Code Playgroud)
在贫困领域,资源只是文件,我们可以简单地通过......更新当前的数量.
PUT /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
{
"Id": "ef4454ae-4a82-4bf2-82e1-3da9229ecc94",
"Version": 8,
"Name" : "REST in Practice",
"CurrentCount": 30
}
Run Code Online (Sandbox Code Playgroud)
但是,如果域不是贫血,那么我们需要将对文档状态的更改重新命名为发送到模型的命令.在这种特殊情况下,变化很简单,我们需要观察CurrentCount中的不同,计算差异,使用变化的符号来识别正确的命令,以及初始化该命令的变化幅度.
现在,正如我们所指出的那样,修补的表示是资源的表示,而不是库存项目的表示 ; 我们有更多的回旋余地.所以我们可以做点像......
GET /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
{
"Id": "ef4454ae-4a82-4bf2-82e1-3da9229ecc94",
"Version": 7,
"Name" : "REST in Practice",
"CurrentCount": 20,
"pendingCommands" : []
}
Run Code Online (Sandbox Code Playgroud)
然后一个聪明的客户可以尝试......
PUT /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
{
"Id": "ef4454ae-4a82-4bf2-82e1-3da9229ecc94",
"Version": 7,
"Name" : "REST in Practice",
"CurrentCount": 20,
"pendingCommands" : [
{
"command":"CheckIn",
"count": 10
}
]
}
Run Code Online (Sandbox Code Playgroud)
现在,API层的工作再次简单; 它只需要知道如何解析pendingCommand列表中的对象.
如果您对这种方法感到满意,那么您当然可以用PATCH替换PUT
PATCH /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
Content-Type: application/json-patch+json
[
{
"op":"add",
"path":"/pendingCommands/0",
"value":
{
"command":"CheckIn",
"count": 10
}
}
]
Run Code Online (Sandbox Code Playgroud)
请注意,PUT实际上并未承诺所接收的表示将是可观察的
给定表示的成功PUT将表明在相同目标资源上的后续GET将导致在200(OK)响应中发送等效表示.但是,不能保证这样的状态改变是可观察的,因为目标资源可能被其他用户代理并行地操作,或者在接收到任何后续GET之前可能受到源服务器的动态处理.成功的响应仅意味着用户代理的意图是在原始服务器处理时实现的.
在这种情况下,"动态处理"是pendingCommands的运行.
现在,如果您仔细查看JSON-Patch,您可能会发现它只是一个定义良好的命令列表,这些命令以"JSON Document"聚合为目标,这是正确的.
因此,通过类比,您可以定义InventoryItem-Patch格式,该格式描述了对InventoryItems有效的操作列表(因此,而不是操作 add/move/replace/...您将定义操作ChangeName/Checkin/Deactivate. ..)
GET /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
{
"Id": "ef4454ae-4a82-4bf2-82e1-3da9229ecc94",
"Version": 7,
"Name" : "REST in Practice",
"CurrentCount": 20
}
PATCH /ef4454ae-4a82-4bf2-82e1-3da9229ecc94
Content-Type: application/vnd.inventory-item-patch+json
[
{
"changeName" :
{
"newName" : "REST in Patch"
}
}
]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
495 次 |
| 最近记录: |