整洁架构下如何在应用层实现DTF框架的抽象?
结论先行
- DTF 确实属于基础设施层:它是第三方工作流调度实现,不属于业务逻辑范畴,符合整洁架构中基础设施层存放外部工具、第三方依赖实现的定位。
- 完全可以实现应用层完全不感知DTF的存在,核心思路是通过依赖倒置原则+适配器模式,将DTF的所有实现细节隔离在基础设施层,具体实现方案如下:
实现步骤
第一步:应用层定义业务无关的编排抽象
应用层只定义工作流的核心能力接口,不引入任何DTF相关的依赖:
// 应用层的编排抽象 public interface IOrchestration<TInput, TOutput> { Task<TOutput> RunAsync(IOrchestrationContext context, TInput input); } // 应用层的活动抽象 public interface IActivity<TInput, TOutput> { Task<TOutput> ExecuteAsync(TInput input); } // 应用层的编排上下文抽象,只暴露业务需要的方法 public interface IOrchestrationContext { Task<TOutput> ScheduleActivityAsync<TActivity, TInput, TOutput>(TInput input) where TActivity : IActivity<TInput, TOutput>; } // 应用层的编排触发客户端抽象 public interface IWorkflowClient { Task StartAsync<TOrchestration, TInput>(TInput input) where TOrchestration : IOrchestration<TInput, object>; }
第二步:应用层实现纯业务的工作流逻辑
所有的业务流程定义完全基于上面的抽象,和DTF没有任何耦合:
// 应用层的视频编码活动(业务逻辑在这里) public class EncodeVideoActivity : IActivity<string, string> { // 可自由注入应用层的其他服务,比如存储服务、媒体处理服务等 public async Task<string> ExecuteAsync(string input) { // 业务逻辑:编码视频 return "http://<azurebloblocation>/encoded_video.avi"; } } // 应用层的发送邮件活动 public class SendEmailActivity : IActivity<string, object> { public async Task<object> ExecuteAsync(string input) { // 业务逻辑:给用户发通知邮件 return null; } } // 应用层的视频编码编排(业务流程定义在这里) public class EncodeVideoOrchestration : IOrchestration<string, string> { public async Task<string> RunAsync(IOrchestrationContext context, string input) { string encodedUrl = await context.ScheduleActivityAsync<EncodeVideoActivity, string, string>(input); await context.ScheduleActivityAsync<SendEmailActivity, string, object>(input); return encodedUrl; } }
第三步:基础设施层实现DTF适配
所有和DTF相关的实现都放在基础设施层,通过适配器把DTF的原生能力和应用层的抽象做对接:
// 基础设施层:Orchestration适配器,对接DTF原生Orchestration和应用层IOrchestration public class DTFOrchestrationAdapter<TOrchestration, TInput, TOutput> : TaskOrchestration<TOutput, TInput> where TOrchestration : IOrchestration<TInput, TOutput> { private readonly TOrchestration _orchestration; public DTFOrchestrationAdapter(TOrchestration orchestration) { _orchestration = orchestration; } public override async Task<TOutput> RunTask(OrchestrationContext context, TInput input) { // 把DTF的原生上下文封装成应用层定义的IOrchestrationContext var appContext = new DTFOrchestrationContextAdapter(context); return await _orchestration.RunAsync(appContext, input); } } // 基础设施层:Activity适配器 public class DTFActivityAdapter<TActivity, TInput, TOutput> : TaskActivity<TInput, TOutput> where TActivity : IActivity<TInput, TOutput> { private readonly TActivity _activity; public DTFActivityAdapter(TActivity activity) { _activity = activity; } protected override async Task<TOutput> ExecuteAsync(TaskContext context, TInput input) { return await _activity.ExecuteAsync(input); } } // 基础设施层:上下文适配器 public class DTFOrchestrationContextAdapter : IOrchestrationContext { private readonly OrchestrationContext _dtfContext; public DTFOrchestrationContextAdapter(OrchestrationContext dtfContext) { _dtfContext = dtfContext; } public async Task<TOutput> ScheduleActivityAsync<TActivity, TInput, TOutput>(TInput input) where TActivity : IActivity<TInput, TOutput> { // 内部调用DTF原生调度方法,适配成应用层定义的接口调用 return await _dtfContext.ScheduleTask<TOutput>(typeof(DTFActivityAdapter<TActivity, TInput, TOutput>), input); } } // 基础设施层:WorkflowClient实现 public class DTFWorkflowClient : IWorkflowClient { private readonly TaskHubClient _dtfClient; public DTFWorkflowClient(TaskHubClient dtfClient) { _dtfClient = dtfClient; } public async Task StartAsync<TOrchestration, TInput>(TInput input) where TOrchestration : IOrchestration<TInput, object> { await _dtfClient.CreateOrchestrationInstance(typeof(DTFOrchestrationAdapter<TOrchestration, TInput, object>), input); } }
第四步:服务注册和启动逻辑放到入口层
所有DTF的初始化、适配器的注册都放在Program.cs等入口层,应用层完全不需要感知:
// 入口层Program.cs var builder = Host.CreateDefaultBuilder(args); // 注册应用层的编排和活动 builder.Services.AddScoped<EncodeVideoOrchestration>(); builder.Services.AddScoped<EncodeVideoActivity>(); builder.Services.AddScoped<SendEmailActivity>(); // 注册DTF相关服务 builder.Services.AddSingleton<TaskHubClient>(sp => new TaskHubClient("myvideohub", "connectionDetails")); builder.Services.AddSingleton<IWorkflowClient, DTFWorkflowClient>(); // 启动DTF Worker var hubWorker = new TaskHubWorker("myvideohub", "connectionDetails") // 注册适配后的编排和活动 .AddTaskOrchestrations(typeof(DTFOrchestrationAdapter<EncodeVideoOrchestration, string, string>)) .AddTaskActivities(typeof(DTFActivityAdapter<EncodeVideoActivity, string, string>), typeof(DTFActivityAdapter<SendEmailActivity, string, object>)) .Start(); var app = builder.Build(); app.Run();
最终效果
- 应用层所有代码完全不依赖DTF的任何类型,只依赖自己定义的抽象
- 后续如果需要替换工作流实现,只需要在基础设施层新增对应框架的适配代码即可,应用层的业务逻辑、流程定义不需要做任何修改
- 完全符合整洁架构的依赖规则:内层不依赖外层,外层实现内层定义的抽象
内容的提问来源于stack exchange,提问作者DarkLeafyGreen
相关产品推荐
相关产品推荐

