`

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

阅读更多

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

下图说明本地通信服务如何与其主机应用程序通信:

01

下面首先说说如何开发一个本地服务:

1.使用C#的接口定义服务契约,在接口中定义你方法和事件。并使用[ExternalDataExchangeAttribute]装饰该接口,用于说明这是一个本地服务的接口。
2.开发一个实现了该接口的类,用于实现你的逻辑。
3.创建一个工作流实例,并将该本地服务添加到工作流引擎中去。

我们开发一个简单的本地服务的例子,根据AccountID来修改Balance的值,并使用三种方式来调用:
1.定义一个Account类,代码如下(Account.cs)

using System;
namespace CaryWorkflows
{
    [Serializable]
    public class Account
    {
        private Int32 _id;
        private String _name = String.Empty;
        private Double _balance;

        public Int32 Id
        {
            get { return _id; }
            set { _id = value; }
        }
        public String Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public Double Balance
        {
            get { return _balance; }
            set { _balance = value; }
        }
    }
}
2.定义一个接口,需要ExternalDataExchange属性,代码如下(IAccountServices.cs):

using System;
using System.Workflow.Activities;
namespace CaryWorkflows 
{
    [ExternalDataExchange]
    public interface IAccountServices
    {
        Account AdjustBalance(Int32 id, Double adjustment);
    }
}

3.实现该接口,代码如下():

using System;
using System.Collections.Generic;
namespace CaryWorkflows 
{
    public class AccountService : IAccountServices
    {
        private Dictionary<Int32, Account> _accounts= new Dictionary<int, Account>();
        public AccountService()
        {
            Account account = new Account();
            account.Id = 101;
            account.Name = "Neil Armstrong";
            account.Balance = 100.00;
            _accounts.Add(account.Id, account);
        }
       public Account AdjustBalance(Int32 id, Double adjustment)
        {
            Account account = null;
            if (_accounts.ContainsKey(id))
            {
                account = _accounts[id];
                account.Balance += adjustment;
            }
            return account;
        }       
    }
}
 
服务定义好了,我们下面就要在工作流中条用该服务,我们有三种方式:

代码方式

在工作流中定义三个属性:
using System;
using System.Workflow.Activities;
namespace CaryWorkflows 
{
    public sealed partial class BalanceAdjustmentWorkflow: SequentialWorkflowActivity
    {
        private Int32 _id;
        private Double _adjustment;
        private Account _account;
        private IAccountServices _accountServices;

        public Int32 Id
        {
            get { return _id; }
            set { _id = value; }
        }
        public Double Adjustment
        {
            get { return _adjustment; }
            set { _adjustment = value; }
        }
        public Account Account
        {
            get { return _account; }
            set { _account = value; }
        }
        public BalanceAdjustmentWorkflow()
        {
            InitializeComponent();
        }
    }
}
 
然后我们向工作流中拖入一个CodeActivity,Activity有一个方法OnActivityExecutionContextLoad(),我们通过该
的IServiceProvider的GetService方法来获取本地服务,代码如下:
protected override void OnActivityExecutionContextLoad( IServiceProvider provider)
{
     base.OnActivityExecutionContextLoad(provider);           
     _accountServices = provider.GetService(typeof(IAccountServices))as IAccountServices;
     if (_accountServices == null)
     {                
        throw new InvalidOperationException("Unable to retrieve IAccountServices from runtime");
     }
}
 
在CodeActivity的ExecuteCode事件中调用本地服务的方法,代码如下:
 
private void codeAdjustAccount_ExecuteCode(object sender, EventArgs e)
{
     Account = _accountServices.AdjustBalance(Id, Adjustment);
}
 
最后要将该服务添加到工作流引擎当中去,
1. 先将ExternalDataExchangeService服务对象添加到引擎。
2.再将我们自己开发的服务绑定到ExternalDataExchangeService服务中。
宿主程序的代码如下:
using System;
using System.Collections.Generic;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using CaryWorkflows ;
namespace ConsoleLocalServices
{
    public class LocalServiceTest
    {
        public static void Run()
        {
            using (WorkflowRuntimeManager manager= new WorkflowRuntimeManager(new WorkflowRuntime()))
            {
                AddServices(manager.WorkflowRuntime);
                manager.WorkflowRuntime.StartRuntime();                
                Dictionary<String, Object> wfArguments= new Dictionary<string, object>();              
                Console.WriteLine("开始....");
                wfArguments.Add("Id", 101);
                wfArguments.Add("Adjustment", -25.00);
                WorkflowInstanceWrapper instance = manager.StartWorkflow(
typeof(CaryWorkflows.BalanceAdjustmentWorkflow), wfArguments); manager.WaitAll(2000); Account account = instance.OutputParameters["Account"] as Account; if (account != null) { Console.WriteLine( "Revised Account: {0}, Name={1}, Bal={2:C}",account.Id,
account.Name, account.Balance); } else { Console.WriteLine("Invalid Account Id\n\r"); } Console.WriteLine("结束...."); } } private static void AddServices(WorkflowRuntime instance) { ExternalDataExchangeService exchangeService = new ExternalDataExchangeService(); instance.AddService(exchangeService); exchangeService.AddService(new AccountService()); } } }
这样我们使用代码方式调用外部方法就结束了,结果如下:
开始....
Revised Account: 101, Name=Neil Armstrong, Bal=¥75.00
结束....
 
配置文件方式
 
1.添加一个app.config到项目中,代码如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="WorkflowRuntime" 
      type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection,
        System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral,
        PublicKeyToken=31bf3856ad364e35" />
    <section name="LocalServices" 
      type="System.Workflow.Activities.ExternalDataExchangeServiceSection, 
        System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
  </configSections>
  <WorkflowRuntime Name="ConsoleLocalServices" >
    <CommonParameters>
      <!--Add parameters common to all services-->
    </CommonParameters>
    <Services>
      <!--Add core services here-->
    </Services>
  </WorkflowRuntime>
  <LocalServices >
    <Services>
      <!--Add local services here-->
      <add type="CaryWorkflows.AccountService, 
        CaryWorkflows,Version=1.0.0.0, 
        Culture=neutral, PublicKeyToken=null" />
    </Services>
  </LocalServices >
</configuration>
2.我们只要需改动宿主程序中如下部分:
using (WorkflowRuntimeManager manager= new WorkflowRuntimeManager(new 
WorkflowRuntime("WorkflowRuntime"))); ExternalDataExchangeService exchangeService = new ExternalDataExchangeService("LocalServices");
 
使用自定义活动方式

1.首先自定义一个活动(AdjustAccountActivity.cs), 我们在自定义活动中获取本地服务,并且调用其中方法,代码如下:
using System;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Workflow.Activities;
namespace CaryWorkflows 
{
    public partial class AdjustAccountActivity : Activity
    {
        public static DependencyProperty IdProperty= System.Workflow.ComponentModel
.DependencyProperty.Register("Id", typeof(Int32), typeof(AdjustAccountActivity)); [Description("Identifies the account")] [Category("Local Services")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Int32 Id { get { return ((Int32)(base.GetValue(AdjustAccountActivity.IdProperty))); } set { base.SetValue(AdjustAccountActivity.IdProperty, value); } } public static DependencyProperty AdjustmentProperty = System.Workflow.ComponentModel.
DependencyProperty.Register("Adjustment", typeof(Double), typeof(AdjustAccountActivity)); [Description("The adjustment amount")] [Category("Local Services")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Double Adjustment { get { return ((Double)(base.GetValue(AdjustAccountActivity.AdjustmentProperty))); } set { base.SetValue(AdjustAccountActivity.AdjustmentProperty, value); } } public static DependencyProperty AccountProperty= System.Workflow.ComponentModel.
DependencyProperty.Register("Account", typeof(Account), typeof(AdjustAccountActivity)); [Description("The revised Account object")] [Category("Local Services")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Account Account { get { return ((Account)(base.GetValue( AdjustAccountActivity.AccountProperty))); } set { base.SetValue(AdjustAccountActivity.AccountProperty, value); } } public AdjustAccountActivity() { InitializeComponent(); } protected override ActivityExecutionStatus Execute( ActivityExecutionContext
executionContext) { IAccountServices accountServices =executionContext.GetService<IAccountServices>(); if (accountServices == null) { throw new InvalidOperationException( "fail IAccountServices from runtime"); } Account = accountServices.AdjustBalance(Id, Adjustment); return base.Execute(executionContext); } } }
2.在工作流中我们将该自定义活动拖到工作流中,并设置相应的属性即可。
 
使用CallExternalMethodActivity
 
使用该方式我们只需要拖一个CallExternalMethodActivity到工作流中,并且设置起相应属性即可,如下图:
02
这三种方式的执行结果都是一样的。
上一篇:坚持学习WF(7):流程控制(Flow Control)
下一篇:坚持学习WF(9):本地服务之事件处理
分享到:
评论

相关推荐

    WF教程_坚持学习WF

    坚持学习WF(1):从HelloWorld开始 本文主要通过实现了一个可以接受参数的HelloWorld程序来了解WF。 坚持学习WF(2):WF创作模式和设计时...坚持学习WF(8):本地服务之调用外部方法 坚持学习WF(9):本地服务之事件处理

    坚持学习WF,WF学习教程

    坚持学习WF(8):本地服务之调用外部方法 坚持学习WF(9):本地服务之事件处理 工作流能够使用方法和事件通过消息与宿主程序交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序,8.9两篇...

    坚持学习WF

    坚持学习WF(8):本地服务之调用外部方法 坚持学习WF(9):本地服务之事件处理 工作流能够使用方法和事件通过消息与宿主程序交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序,8.9两篇...

    WF从入门到精通(第八章):调用外部方法及工作流(一)源码

    通过学习本章内容,你将掌握如何在WF中创建自定义活动以调用外部方法,如何设计和执行工作流,以及如何利用WF提供的特性来优化和管理工作流程。这将为你的WF开发能力打下坚实的基础。在实际项目中,结合这些知识,你...

    坚持学习WF(1):从HelloWorld开始 源码

    深入WF的学习,还需要掌握活动库的使用、自定义活动的创建、持久化机制、工作流服务(WF45中的WCF Workflow Service)以及与WF相关的设计模式。这将帮助你构建更复杂、灵活且适应性强的业务流程解决方案。 总结来说...

    坚持学习WF(5):自定义活动(CustomActivity) 源码

    自定义活动是WF强大之处,因为它使得开发者能够扩展WF的功能,以满足独特的需求。 二、创建自定义活动 1. 创建类:首先,你需要创建一个继承自`System.Activities.Activity`的类。这个类将成为你的自定义活动的基础...

    WF工作流学习资料

    6. **WF与WCF集成**:WF和Windows Communication Foundation(WCF)紧密集成,允许工作流作为服务公开,或者调用其他服务。这使得WF工作流可以轻松地参与分布式系统中的服务交互。 7. **WF版本发展**:WF经历了从...

    wf工作流资料<转自网上的笔记>

    "坚持学习WF(9)本地服务之事件处理"探讨了WF中的事件处理机制,这是工作流与外部系统交互的关键。这部分可能会讲解EventActivity以及如何使用事件触发工作流的行为。 "坚持学习WF(10)在工作流中使用关联"会涉及工作...

    WPF承载WF并调用WCF

    微软官方示例,WPF中载入WWF,并通过WWF调用WCF应用,是典型的.net 3.0架构整合示例

    Apress - Beginning WF: Windows Workflow in .NET 4.0 Mar 2010

    - **在WCF服务中托管工作流**:展示如何将工作流嵌入到WCF服务中,以便于跨系统间的调用和服务集成。 #### 三、章节详解 1. **第1部分:简介** - **第1章:构建简单的工作流**:从零开始介绍如何构建第一个工作流...

    WF4.5+WCF示例

    7. **工作流与服务交互**:使用WCF客户端调用服务,或者在工作流中直接引用服务代理类,实现工作流与外部服务的通信。 8. **错误处理和事务**:理解如何在WF4.5和WCF中处理异常和回滚事务,确保服务的健壮性。 9. ...

    Code(WF从入门到精通).rar

    第八章:调用外部方法及工作流 第九章:逻辑流活动 第十章:事件活动 第十一章:并行活动 第十二章:策略和规则 第十三章:打造自定义活动 第十四章:基于状态的工作流 第十五章:工作流和事务 第十六章:声明式工作...

    WF工作流例子

    此外,WF还支持与WCF(Windows Communication Foundation)集成,使得工作流可以作为服务对外提供,便于远程调用和集成。 在压缩包文件“WF”中,可能包含了以下内容: 1. 示例代码:展示了如何创建和执行WF工作流...

    pro wf windows workflow in dot net 3.5

    8. **工作流版本管理和迁移**:讨论了如何处理工作流的版本升级,以及如何在不中断服务的情况下迁移现有的工作流实例。 9. **工作流持久性框架**:介绍了WF的持久性接口和策略,以及如何实现自定义持久化提供者,以...

    WF从入门到精通(1-16章)

    - **外部方法调用**:讨论如何在WF中调用外部代码,包括托管代码和服务端点等。 - **嵌套工作流**:介绍如何在一个工作流中嵌套另一个工作流,从而实现更复杂的功能组合。 - **调用模式**:探讨不同的调用模式,如...

    WF从入门到精通(第十七章):关联及本地主机通信(上)源码

    在WF中,关联是一种连接工作流实例与数据的方式,它允许工作流实例与外部实体进行交互。例如,一个工作流可能需要访问数据库中的订单信息,这时就需要建立与订单数据的关联。关联可以通过活动设计时定义,也可以在...

Global site tag (gtag.js) - Google Analytics