ASP.NET Core模块化单体应用中两模块间数据一致性保障方案咨询
ASP.NET Core模块化单体应用中两模块间数据一致性保障方案咨询
嘿,这个场景我之前在做模块化单体项目的时候也碰到过,给你几个实际可行的落地思路,完美适配你说的“不管上传和扫码顺序,都能正确关联”的需求:
核心思路:引入全局关联ID + 共享元数据实体
因为是模块化单体架构,我们可以在模块之间定义一个共享的核心元数据层(比如单独抽一个Core模块,或者在两个模块都能访问的共享数据库上下文里加实体),用来统一管理发票图片和扫码数据的关联关系。
具体实现步骤
1. 定义共享的关联实体
先创建一个InvoiceCorrelation实体(或者叫InvoiceMetadata),用来存关联关系和状态:
public class InvoiceCorrelation { // 全局唯一的关联ID,用Guid就行 public Guid CorrelationId { get; set; } // 图片模块返回的图片ID,可为空(扫码先发生时还没上传) public Guid? ImageId { get; set; } // 扫码模块解密后的发票数据,可以用JSON字符串或者对应的数据模型 public string DecryptedInvoiceData { get; set; } // 关联状态:待上传图片/待扫码/已完成关联,方便后续排查和处理 public string Status { get; set; } // 乐观锁字段,处理并发更新问题 public byte[] RowVersion { get; set; } }
2. 前端主导生成关联ID(最省心的方式)
让前端在发起任意一个操作(上传图片或扫码)之前,先生成一个全局唯一的CorrelationId(比如用Guid.NewGuid()),然后在上传图片和扫码的请求里都带上这个ID。这样不管哪个操作先执行,两边都用同一个ID关联。
3. 图片上传模块的处理逻辑
当图片上传成功后:
- 生成图片模块内部的
ImageId - 到共享的
InvoiceCorrelation表中,根据传入的CorrelationId,更新ImageId字段 - 检查
DecryptedInvoiceData是否已经存在:如果存在,就把状态改成"已完成关联";如果不存在,状态设为"待扫码" - 不需要和扫码模块直接交互,完全通过共享实体解耦
4. 扫码解密模块的处理逻辑
因为你说扫码模块的HandleAsync方法要返回NoContent,那处理逻辑可以这样:
- 接收前端传入的
CorrelationId,解密QR码得到发票数据 - 到共享的
InvoiceCorrelation表中,根据CorrelationId,更新DecryptedInvoiceData字段 - 检查
ImageId是否已经存在:如果存在,状态改成"已完成关联";如果不存在,状态设为"待上传图片" - 直接返回
NoContentResult()即可,不需要给前端返回额外数据
特殊场景的处理
- 扫码先于上传:此时
InvoiceCorrelation里只有解密数据和待上传图片状态,等后续图片上传时,会自动补全ImageId并更新状态 - 并发操作:因为加了
RowVersion乐观锁字段,当两个操作同时更新同一个CorrelationId记录时,数据库会自动拦截并发冲突,你只需要在代码里捕获并发异常,重试或者返回友好提示即可 - 模块化解耦:两个业务模块只需要依赖共享的Core模块(包含
InvoiceCorrelation实体和数据访问接口),不需要直接引用对方模块,完全符合模块化单体的设计原则
备选方案:模块自动生成关联ID
如果前端不方便生成ID,也可以让先执行的模块生成CorrelationId:
- 如果图片先上传:上传模块生成
CorrelationId,返回给前端,前端扫码时带上这个ID - 如果扫码先执行:扫码模块生成
CorrelationId,虽然返回NoContent,但可以通过响应头(比如X-Correlation-Id)把ID传给前端,前端后续上传图片时带上这个ID
这个方案稍微麻烦一点,需要前端处理响应头,但也能实现需求。
备注:内容来源于stack exchange,提问作者Stæin
相关产品推荐
相关产品推荐

