坚持学习WF(6):开发可复用的宿主程序

我们之前写工作流宿主程序一般都是直接写在program.cs文件里,这样复用性比较差。我们就简单的写两个类,这两个类主要实现的是对WorkflowInstance和WorkflowRuntime的封装。我们以后的例子都会使用这两个类。

第一个类是WorkflowInstanceWrapper,代码如下:


[Serializable]
    
public   class  WorkflowInstanceWrapper
    {
        
private  WorkflowInstance _workflowInstance;
        
private  ManualResetEvent _waitHandle  =   new  ManualResetEvent( false );
        
private  Dictionary < String, Object >  _outputParameters =   new  Dictionary
                < string ,  object > ();
        
private  Exception _exception;
        
private  String _reasonSuspended  =  String.Empty;

        
public  WorkflowInstanceWrapper(WorkflowInstance instance)
        {
            _workflowInstance 
=  instance;
        }        
        
public  Guid Id
        {
            
get
            {
                
if  (_workflowInstance  !=   null )
                   
return  _workflowInstance.InstanceId;
                
else
                   
return  Guid.Empty;
            }
        }        
        
public  Dictionary < String, Object >  OutputParameters
        {
            
get  {  return  _outputParameters; }
            
set  { _outputParameters  =  value; }
        }        
        
public  ManualResetEvent WaitHandle
        {
            
get  {  return  _waitHandle; }
            
set  { _waitHandle  =  value; }
        }        
        
public  Exception Exception
        {
            
get  {  return  _exception; }
            
set  { _exception  =  value; }
        }        
        
public  String ReasonSuspended
        {
            
get  {  return  _reasonSuspended; }
            
set  { _reasonSuspended  =  value; }
        }        
        
public  WorkflowInstance WorkflowInstance
        {
            
get  {  return  _workflowInstance; }
        }        
        
public   void  StopWaiting()
        {
            _waitHandle.Set();
        }
    }

1._exception,_reasonSuspended:表示当工作流非正常终止或挂起时的相关信息。
2. OutputParameters:用来接收工作流的输出参数,工作流运行时引擎将引发 WorkflowCompleted事件。
工作流运行时引擎将在WorkflowCompletedEventArgs 中传入工作流的所有输出参数。 这些参数包括工作
流的 out 和 ref 参数。
 

第二类是WorkflowManager代码如下:  

  public   class  WorkflowRuntimeManager : IDisposable
    {
        
private  WorkflowRuntime _workflowRuntime;
        
private  Dictionary < Guid, WorkflowInstanceWrapper >  _workflows
                               =   new  Dictionary < Guid, WorkflowInstanceWrapper > ();
      
        
public  WorkflowRuntimeManager(WorkflowRuntime instance)
        {
            _workflowRuntime 
=  instance;
            
if  (instance  ==   null )
            {
                
throw   new  NullReferenceException(
                    
" A non-null WorkflowRuntime instance is required " );
            }            
            SubscribeToEvents(instance);
        }

      
        
public  WorkflowInstanceWrapper StartWorkflow(Type workflowType,
            Dictionary
< String, Object >  parameters)
        {
            WorkflowInstance instance 
=  _workflowRuntime.CreateWorkflow(
                workflowType, parameters);
            WorkflowInstanceWrapper wrapper
                
=  AddWorkflowInstance(instance);
            instance.Start();
            
return  wrapper;
        }
        
        
public  WorkflowInstanceWrapper StartWorkflow(String markupFileName,
            String rulesMarkupFileName,
            Dictionary
< String, Object >  parameters)
        {
            WorkflowInstance instance 
=   null ;
            WorkflowInstanceWrapper wrapper 
=   null ;
            XmlReader wfReader 
=   null ;
            XmlReader rulesReader 
=   null ;
            
try
            {
                wfReader 
=  XmlReader.Create(markupFileName);
                
if  ( ! String.IsNullOrEmpty(rulesMarkupFileName))
                {
                    rulesReader 
=  XmlReader.Create(rulesMarkupFileName);
                    instance 
=  _workflowRuntime.CreateWorkflow( wfReader, rulesReader, parameters);
                }
                
else
                {
                    instance 
=  _workflowRuntime.CreateWorkflow(wfReader,  null , parameters);
                }
                wrapper 
=  AddWorkflowInstance(instance);
                instance.Start();
            }
            
finally
            {
                
if  (wfReader  !=   null )
                {
                    wfReader.Close();
                }
                
if  (rulesReader  !=   null )
                {
                    rulesReader.Close();
                }
            }
            
return  wrapper;
        }

       
public  WorkflowRuntime WorkflowRuntime
        {
            
get  {  return  _workflowRuntime; }
        }        
        
public  Dictionary < Guid, WorkflowInstanceWrapper >  Workflows
        {
            
get  {  return  _workflows; }
        }        
        
public   event  EventHandler < WorkflowLogEventArgs >  MessageEvent;    

       
        
public   void  ClearWorkflow(Guid workflowId)
        {
            
if  (_workflows.ContainsKey(workflowId))
            {
                _workflows.Remove(workflowId);
            }
        }
      
        
public   void  ClearAllWorkflows()
        {
            _workflows.Clear();
        }
       
        
private  WorkflowInstanceWrapper AddWorkflowInstance(
            WorkflowInstance instance)
        {
            WorkflowInstanceWrapper wrapper 
=   null ;
            
if  ( ! _workflows.ContainsKey(instance.InstanceId))
            {
                wrapper 
=   new  WorkflowInstanceWrapper(instance);
                _workflows.Add(wrapper.Id, wrapper);
            }
            
return  wrapper;
        }
     
        
public  WorkflowInstanceWrapper FindWorkflowInstance(Guid workflowId)
        {
            WorkflowInstanceWrapper result 
=   null ;
            
if  (_workflows.ContainsKey(workflowId))
            {
                result 
=  _workflows[workflowId];
            }
            
return  result;
        }
       
        
public   void  WaitAll(Int32 msecondsTimeout)
        {
            
if  (_workflows.Count  >   0 )
            {
                WaitHandle[] handles 
=   new  WaitHandle[_workflows.Count];
                Int32 index 
=   0 ;
                
foreach  (WorkflowInstanceWrapper wrapper
                    
in  _workflows.Values)
                {
                    handles[index] 
=  wrapper.WaitHandle;
                    index
++ ;
                }
                WaitHandle.WaitAll(handles, msecondsTimeout, 
false );
            }
        }
     
        
public   void  Dispose()
        {
            
if  (_workflowRuntime  !=   null )
            {
                _workflowRuntime.StopRuntime();
                _workflowRuntime.Dispose();
            }
            ClearAllWorkflows();
        }
      
        
private   void  SubscribeToEvents(WorkflowRuntime runtime)
        {
            runtime.Started 
+=   new  EventHandler < WorkflowRuntimeEventArgs > ( runtime_Started);
            runtime.Stopped 
+=   new  EventHandler < WorkflowRuntimeEventArgs > (runtime_Stopped);
            runtime.WorkflowAborted
+=  ......
            runtime.WorkflowCompleted
+=  ......
            runtime.WorkflowCreated  +=  ......    
            ............
        }

        
void  runtime_Started( object  sender, WorkflowRuntimeEventArgs e)
        {
            LogStatus(Guid.Empty, 
" Started " );
        }
        
void  runtime_Stopped( object  sender, WorkflowRuntimeEventArgs e)
        {
            LogStatus(Guid.Empty, 
" Stopped " );
        }
        
void  runtime_WorkflowCreated( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowCreated " );
        }
        
void  runtime_WorkflowStarted( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowStarted " );
        }
        
void  runtime_WorkflowIdled( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowIdled " );
        }

        
void  runtime_WorkflowCompleted( object  sender, WorkflowCompletedEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowCompleted " );
            WorkflowInstanceWrapper wrapper
                
=  FindWorkflowInstance(e.WorkflowInstance.InstanceId);
            
if  (wrapper  !=   null )
            {
                wrapper.OutputParameters 
=  e.OutputParameters;
                wrapper.StopWaiting();
            }
        }

        
void  runtime_WorkflowTerminated( object  sender,
            WorkflowTerminatedEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowTerminated " );
            WorkflowInstanceWrapper wrapper 
=  FindWorkflowInstance(e.WorkflowInstance.InstanceId);
            
if  (wrapper  !=   null )
            {
                wrapper.Exception 
=  e.Exception;
                wrapper.StopWaiting();
            }
        }

        
void  runtime_WorkflowSuspended( object  sender, WorkflowSuspendedEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowSuspended " );
            WorkflowInstanceWrapper wrapper 
=  FindWorkflowInstance(e.WorkflowInstance.InstanceId);
            
if  (wrapper  !=   null )
            {
                wrapper.ReasonSuspended 
=  e.Error;
            }
        }

        
void  runtime_WorkflowResumed( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowResumed " );
        }
        
void  runtime_WorkflowPersisted( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowPersisted " );
        }
        
void  runtime_WorkflowLoaded( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowLoaded " );
        }
        
void  runtime_WorkflowAborted( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowAborted " );
            WorkflowInstanceWrapper wrapper
                
=  FindWorkflowInstance(e.WorkflowInstance.InstanceId);
            
if  (wrapper  !=   null )
            {
                wrapper.StopWaiting();
            }
        }

        
void  runtime_WorkflowUnloaded( object  sender, WorkflowEventArgs e)
        {
            LogStatus(e.WorkflowInstance.InstanceId, 
" WorkflowUnloaded " );
        }

        
private   void  LogStatus(Guid instanceId, String msg)
        {
            
if  (MessageEvent  !=   null )
            {
                String formattedMsg;
                
if  (instanceId  ==  Guid.Empty)
                {
                    formattedMsg 
=  String.Format( " Runtime - {0} " , msg);
                }
                
else
                {
                    formattedMsg 
=  String.Format( " {0} - {1} " , instanceId, msg);
                }
                
// raise the event
                MessageEvent( this ,  new  WorkflowLogEventArgs(formattedMsg));
            }
        }

    }   
    
public   class  WorkflowLogEventArgs : EventArgs
    {
        
private  String _msg  =  String.Empty;
        
public  WorkflowLogEventArgs(String msg)
        {
            _msg 
=  msg;
        }

        
public  String Message
        {
            
get  {  return  _msg; }
        }

1._workflows:一个key为Guid,value为WorkflowInstanceWrapper的字典。
2.SubscribeToEvent():给workflowRuntime订阅事件.
3.StartWorkflow():实现创建,开始工作流.
4.MessageEvent:对Message进行格式化。
5.WaitAll()用来挂起当前的线程直到所有的workflows完成,每个WorkflowInstanceWrapper有一个WaitHandle属性以便宿主程序能灵活控制。 

下面是测试代码:
using  (WorkflowRuntimeManager manager
        
=   new  WorkflowRuntimeManager( new  WorkflowRuntime( " WorkflowRuntime " )))
{
   manager.MessageEvent 
+=   delegate (Object sender, WorkflowLogEventArgs e)
   {
      Console.WriteLine(e.Message);
   };
   manager.WorkflowRuntime.StartRuntime();
   Dictionary
< String, Object >  wfArguments =   new  Dictionary < string ,  object > ();
   wfArguments.Add(
" InputString " ,  " one " );
   WorkflowInstanceWrapper instance 
=  manager.StartWorkflow(
           
typeof (SharedWorkflows.Workflow1), wfArguments);
   instance.WorkflowInstance.Terminate(
" Manually terminated " );
   instance.WaitHandle.WaitOne(
10000 ,  false );
   
foreach  (WorkflowInstanceWrapper wrapperin manager.Workflows.Values)
   {
       
if  (wrapper.OutputParameters.ContainsKey( " Result " ))
       {
            Console.WriteLine(wrapper.OutputParameters[
" Result " ]);
       }
       
if  (wrapper.Exception  !=   null )
       {
     Console.WriteLine(
" {0}-Exception:{1} " ,wrapper.Id,wrapper.Exception.Message);
       }
       
if  (wrapper.ReasonSuspended.Length  >   0 )
       {
    Console.WriteLine(
" {0}-Suspended: {1} " ,wrapper.Id, wrapper.ReasonSuspended);
       }
}    manager.ClearAllWorkflows();























下面运行结果,从该结果可以清晰的看出工作流的执行过程:


1
 上一篇: 
下一篇:
ECC 工作流推送落地实战: 通过定时运行 RSWNSEL 与 /IWWRK/R_WF_ITEM_SELECTION_GW 打通 SAP Gateway 通知全链路 摘要:本文详细介绍了在ECC SAP系统与消费端应用间建立工作流任务推送的完整流程。通过定时运行RSWNSEL和/IWWRK/R_WF_ITEM_SELECTION_GW两个标准报告(推荐每15分钟执行),系统可将Work Item转化为可消费的任务通知。文章涵盖变式创建、作业调度(SM36)、监控(SM37)等核心环节,并特别强调顺序执行的重要性。同时提供了订阅机制设置指南、常见问题排查清单和上线准备事项,确保工作流通知的实时性和可靠性。文末附可打印的操作清单,便于实施参考。 阅读详情

相关推荐

WF4工作流设计与实现详解

WF4(Workflow Foundation 4)是.NET平台中用于构建工作流应用程序的一个框架。它提供了一套丰富的API和运行时环境,允许开发者设计、执行和管理业务流程。WF4不仅简化了工作流的构建过程,还通过引入活动(Activity)概念和状态机工作流(StateMachineWorkflow)等特性,增强了工作的灵活性和可扩展性。内置活动是WF4框架中预定义的活动,它们直接提供了构建工作流所需的各种基本操作和控制结构。

weixin_42126677的博客 586

坚持学习WF(8):本地服务之调用外部方法

WF提供了一组核心服务,例如在SQL 数据库中存储工作流实例的执行详细信息的持久性服务,计划服务,事务服务和跟踪服务。除了这些WF也提供了另外一种服务,叫做Local Service也可以叫做Data exchange service。主要是实现工作流和宿主程序之间的通信,使工作流能够使用方法和事件通过消息与外部系统交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序。 通...

fdqwfdsafdsa的博客 162

半导体EAP系统入门指南:从零开始理解设备自动化程序(附实战案例)

本文深入浅出地介绍了半导体制造中EAP(设备自动化程序)系统的核心作用与工作原理。EAP作为连接MES与生产设备的桥梁,负责指令翻译、数据采集与实时控制,是实现晶圆厂全自动化的关键。文章通过对比手动与自动模式,阐述了EAP在提升效率、保障良率方面的价值,并提供了一个实战案例,帮助读者从零构建对半导体CIM体系中这一关键组件的理解。

weixin_29200741的博客 736

WF工作流开发回顾:介绍

  工作流这个词是去年11月才进入自己的大脑词汇,借着一点时间回顾下自己学习的过程,在这作个记录,希望和大家多多交流,里面的很多都是自己的片面之词,对于这么高科技的东西自己也没把握,还是希望多多指教,小弟感激不尽。   我是用的微软Workflow foundation作为基础框架来开发的,在这里还要提一下,工作流应该是属于一个抽象的名词,而微软的WF只是实现工作流的其中一种基础框架,所以理解这...

weixin_33749131的博客 159

QGIS插件实战:用百度地图AOI数据做个城市公园分析,从下载到出图全记录

本文详细介绍了如何利用QGIS的百度地图AOI插件进行城市公园分析,从插件安装、数据获取到空间分析与可视化全流程。通过实战案例演示了公园面积统计、服务范围缓冲区分析及专题地图制作,帮助用户高效完成城市绿地评估工作。

weixin_30790841的博客 556

手把手教你用Nangate 45nm开源工艺库搞定数字电路仿真(附FreePDK资源)

本文详细介绍了如何使用Nangate 45nm开源工艺库进行数字电路仿真,包括环境搭建、关键文件解析、仿真环境配置及低功耗设计等实战内容。特别推荐FreePDK资源,帮助读者快速掌握从理论到实践的全流程操作,适用于学术研究和小规模数字电路设计。

weixin_30352645的博客 488

坚持学习WF文章索引

出处:http://www.cnblogs.com/carysun/archive/2008/05/29/WF.html坚持学习WF(1):从HelloWorld开始 本文主要通过实现了一个可以接受参数的HelloWorld程序来了解WF。 坚持学习WF(2):WF创作模式和设计时工具 坚持学习WF(3):WF框架概览 2.3两篇主要全面的阐述了WF框架和Visual Studio对开发WF的

1114

第八章 MobileNetv3网络详解

本文介绍了基于互补的搜索技术和新颖的架构设计的MobileNets的下一代。MobileNetV3通过硬件感知网络架构搜索(NAS)和NetAdapt算法相结合,针对移动电话CPU进行优化,随后通过新颖的架构改进技术进行了进一步提高。本文开始探索自动化搜索算法和网络设计如何相互协作,以利用互补的方法改进整体技术水平。通过此过程,我们创建了两个新的MobileNet模型:MobileNetV3-Large和MobileNetV3-Small,分别针对高资源和低资源使用情况。

ADICDFHL的博客 1万+

[转载]《博客园精华集》WF筛选结果(共39篇)

WF的权限与角色(2)管理权限体系 作者:WXWinter(冬)WF的权限与角色(3)一个简单的权限体系结构 作者:WXWinter(冬)WF的权限与角色(4)临时授权管理域 作者:WXWinter(冬)WF的异常捕获与资源补偿 作者:WXWinter(冬)工作流设计_时间引擎的例子 作者:WXWinter(冬)WF3.5 的SendActivity、ReceiveActivity与Workflo...

weixin_30631587的博客 108

DIY天文摄影:如何用NMP溶剂安全去除佳能CMOS传感器的拜耳滤镜(附详细步骤)

本文为天文摄影爱好者提供了一份详尽的DIY指南,介绍如何使用NMP溶剂安全去除佳能CMOS传感器的拜耳滤镜,将其改造为高灵敏度单色相机。文章深入剖析了NMP溶剂的作用原理与关键风险,并系统性地拆解了从材料准备、分步操作到后期验证的完整实践流程,旨在帮助具备动手能力的爱好者实现深空天体摄影的进阶目标。

w3x4y的博客 308

【目标检测】yoloV5算法详解

一、与yoloV4相比,yoloV5的改进 输入端:在模型训练阶段,使用了Mosaic数据增强、自适应锚框计算、自适应图片缩放 基准网络:使用了FOCUS结构和CSP结构 Neck网络:在Backbone和最后的Head输出层之间插入FPN_PAN结构 Head输出层:训练时的损失函数GIOU_Loss,预测筛选框的DIOU_nns 二、yoloV5结构框架 CBL:CBL模块是由Conv+BN+Leaky_relu激活函数组成 Res unit:借鉴ResNet中的残差结构,用来构建深层网络,CBM是

qq_40373651的博客 2万+

索尼WF-1000XM5实测:降噪旗舰的真实体验与验证方法

主动降噪技术已成为真无线耳机的核心卖点,其原理是通过麦克风采集环境噪声,再以芯片生成反向声波进行抵消,从而在通勤、办公等嘈杂场景中营造安静空间。作为降噪耳机的代表性产品,索尼WF-1000XM5在延续这一技术路线的基础上,进一步优化了降噪深度、佩戴贴合度与通话拾音表现,并支持LDAC高清音频传输与多点连接,兼顾了音质与跨设备协作效率。本文从蓝牙连接、LDAC编解码器设置、降噪效果测试、通话质量验证等多个维度,梳理了一套可复用的工程化评测流程,帮助用户在没有专业设备的情况下,通过地铁通勤、办公室会议、户外风噪

weixin_29164843的博客 303

高匿反爬实战:Python打造无痕爬虫,规避风控系统追踪

网络层匿踪:核心是使用住宅IP代理池,按真实用户IP画像匹配,控制请求频率;协议层匿踪:动态生成请求头(每次都不同),参数添加随机噪声,避免规律化;行为层匿踪:模拟人类的非规律行为(贝塞尔轨迹、随机停顿、非精准点击);设备层匿踪:伪造Canvas/WebGL指纹,禁用webdriver标识,每次请求更换指纹;核心原则:无痕爬虫的本质是“无限接近真实用户”,所有维度都要消除爬虫特征,而非单一维度伪装。打造真正的无痕爬虫需要全维度的匿踪策略,单一维度的伪装极易被高级风控系统识别。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2642

TFS 2010架构演进:WF构建引擎与本地工作区的ALM范式升级

应用生命周期管理(ALM)是支撑企业级软件交付的核心体系,其本质在于将需求、开发、测试、发布等环节通过可配置、可审计、可追溯的平台实现流程固化。TFS 2010作为微软ALM战略的关键里程碑,首次以Windows Workflow Foundation(WF)替代MSBuild构建引擎,实现构建逻辑可视化、状态可观察;同时引入本地工作区(Local Workspace),推动TFVC向乐观并发模型演进,显著提升离线开发与跨时区协作效率。该版本还通过规则引擎驱动工作项流转,使Scrum等敏捷实践真正落地为系统

as2886089的博客 460

uniapp - 实现移动端H5微信公众号网页内置浏览器中预览和下载word文档(doc)、excel表格(xls)、ppt文稿、pdf文档等文件,微信内部打开预览和下载到本地详教程,兼容安卓苹果手机

uni-app,微信公众号,h5,移动端,web平台端,网页,网站,Uniapp微信公众号H5网站,内置浏览器下载文档,如何在微信浏览器中预览office文件,word文档,excel文档,pdf文档,ppt文档,office,微信内置浏览器下载文件,下载文件,在微信浏览器里面实现下载任意文件,H5需要在微信浏览器中下载excel文件,UniApp实现网页在微信内置浏览器中下载文件详细教程,安卓点击下载会提示打开浏览器,后端返回流文件,如何解决无法下载文件,跳转至浏览器下载文件,发送到电脑微信,安卓,苹果,

🏆 前端领域优质创作者 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

MOSS 2010:Visual Studio 2010开发体验(26)——工作流开发概述

这一篇开始,我将介绍在MOSS 2010中进行工作流开发的最佳实践。这一篇主要介绍有关的几个概念 1.什么是工作流 工作流开发是这几年都比较火的一个领域。工作流,顾名思义就是工作的流程,而软件系统所要做的就是解决人们现实工作或者生活中的那些流程。所以从事实上说,任何软件系统都离不开工作流。 当然,工作流真正被广大开发人员所熟知,是因为.NET Framework 3.0中的Workflow Foundation(WF)。很显然,WF提供了一个前所未有的选择,就是它提供了运行时、可视化设计器、开箱即用的一些活

陈希章@中国 972

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C Interfaces and Implementations:打造可复用代码的终极指南

**C Interfaces and Implementations** 是一个基于经典书籍《C Interfaces and Implementations: Techniques for Creating Reusable Software》实现的开源项目,旨在提供一套高质量的 C 语言接口和实现,帮助开发者构建模块化、可复用的软件系统。该项目由 David R. Hanson 开发,包含了丰

gitblog_00221的博客 371

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

揭秘Dify工作流导出机制:如何一键生成可复用JSON并提升开发效率

掌握Dify工作流JSON导出技巧,一键生成可复用配置,提升开发效率。适用于多环境部署与团队协作,支持可视化编辑后自动转换为标准JSON格式,便于版本管理与快速迁移。操作简单,结构清晰,值得收藏。

VarPerch的博客 873
上一篇: MOSS点滴(2):自定义Application Page
下一篇: MOSS点滴(3):说说MOSS中的母版页
fdqwfdsafdsa
博客等级 码龄18年 2粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值