现在的位置: 首页 > 综合 > 正文

WF4.0:四种自定义类型活动

2013年03月07日 ⁄ 综合 ⁄ 共 10717字 ⁄ 字号 评论关闭

     工作流中的活动就像用户自定义的控件,将许多的功能封装起来用。WF4.0中提供了四种可继承的活动类:CodeActivity 、AsyncCodeActivity、Activity、NativeActivity。这几种活动都有自己使用的适合场合,正确的使用这些活动将非常有利。

1、CodeActivity

     WF4.0中的活动是树形结构的,创建叶子活动最简单是方式就是使用CodeActivity ,它的逻辑都放在一个方法:Execute 里面,这个也是四种活动中最简单的一种。这里用一个简单的自定活动HttpGet来说明怎么使用CodeActivity。HttpGet的功能是从网络上抓取数据。

    public sealed class HttpGet : CodeActivity<string>
    {
        
public InArgument<string> Uri { getset; }

        protected override string Execute(CodeActivityContext context)
        {
            WebRequest request 
= HttpWebRequest.Create(this.Uri.Get(context));

            using (WebResponse response = request.GetResponse())
            {
                
//read everything response.GetResponseStream() as one string
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    
return reader.ReadToEnd();
                }
            }

        }

    }

    public InArgument<string> Uri { get; set; }是工作流中的一个属性,相当于类的属性,不过取它的值与类有点不同,你需要使用:Uri.Get(context))或者context.GetValue(Uri),Execute方法是这个活动的逻辑,特别注意CodeActivityContext context参数,这是WF的上下文,非常有用。

如何使用这个活动:

 HttpGet fetchMsn = new HttpGet
     {
         Uri 
= "http://www.msn.com"
     };
     
string msnContent = WorkflowInvoker.Invoke<string>(fetchMsn);
     Console.WriteLine(msnC
ontent);

2、AsyncCodeActivity

    AsyncCodeActivity 类似CodeActivity ,只是它是使用了 Begin/EndExecute 取代了CodeActivityExecute 方法。BeginExecute 开始一个异步操作,无需等待它完成,就返回IAsyncResult对象 。当这个操作完成的时候,就执行EndExecute 方法放回结果。HttpGet 能这样实现,请注意CodeActivityContext换成了AsyncCodeActivityContext:

   class HttpGet : AsyncCodeActivity<string>
    {
        
public InArgument<string> Uri { getset; }

        protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {
            WebRequest request 
= HttpWebRequest.Create(this.Uri.Get(context));
            context.UserState 
= request;
            
return request.BeginGetResponse(callback, state);            
        }

        protected override string EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
        {
            WebRequest request 
= (WebRequest)context.UserState;
            
using (WebResponse response = request.EndGetResponse(result))
            {
                
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    
return reader.ReadToEnd();
        
        }
            }
        }
    }

3、Activity

    Activity可以以组合的方式定义活动。开发人员可以使用已有活动构建一个活动树来实现这个活动。如果你需要在工作流中完成一些复杂的逻辑,可以使用这种方式。这里用一个flowchart为例:

代码

public sealed class FlowChartActivity : Activity
    {
        
public string promoCode { getset; }

        public int numKids { getset; }

        public FlowChartActivity(string promoCode, int numKids)
        {
            
this.promoCode = promoCode;
            
this.numKids = numKids;
            
base.Implementation = new Func<Activity>(CreateBody);
        }

        Activity CreateBody()
        {
            Variable<string> promo = new Variable<string> { Default = promoCode};
            Variable
<int> numberOfKids = new Variable<int> { Default = numKids };
            Variable
<double> discount = new Variable<double>();
            DelegateInArgument
<DivideByZeroException> ex = new DelegateInArgument<DivideByZeroException>();

            FlowStep discountNotApplied = new FlowStep
            {
                Action 
= new WriteLine
                {
                    DisplayName 
= "WriteLine: Discount not applied",
                    Text 
= "Discount not applied"
                },
                Next 
= null
            };

            FlowStep discountApplied = new FlowStep
            {
                Action 
= new WriteLine
                {
                    DisplayName 
= "WriteLine: Discount applied",
                    Text 
= "Discount applied "
                },
                Next 
= null
            };

            FlowDecision flowDecision = new FlowDecision
            {
                Condition 
= ExpressionServices.Convert<bool>((ctx) => discount.Get(ctx) > 0),
                True 
= discountApplied,
                False 
= discountNotApplied
            };

            FlowStep singleStep = new FlowStep
            {
                Action 
= new Assign
                {
                    DisplayName 
= "discount = 10.0",
                    To 
= new OutArgument<double>(discount),
                    Value 
= new InArgument<double>(10.0)
                },
                Next 
= flowDecision
            };

            FlowStep mnkStep = new FlowStep
            {
                Action 
= new Assign
                {
                    DisplayName 
= "discount = 15.0",
                    To 
= new OutArgument<double>(discount),
                    Value 
= new InArgument<double>(15.0)
                },
                Next 
= flowDecision
            };

            FlowStep mwkStep = new FlowStep
            {
                Action 
= new TryCatch
                {
                    DisplayName 
= "Try/Catch for Divide By Zero Exception",
                    Try 
= new Assign
                    {
                        DisplayName 
= "discount = 15 + (1 - 1/numberOfKids)*10",
                        To 
= new OutArgument<double>(discount),
                        Value 
= new InArgument<double>((ctx) => (15 + (1 - 1 / numberOfKids.Get(ctx)) * 10))
                    },
                    Catches 
= 
                    {
                         
new Catch<System.DivideByZeroException>
                         {
                             Action 
= new ActivityAction<System.DivideByZeroException>
                             {
                                 Argument 
= ex,
                                 DisplayName 
= "ActivityAction - DivideByZeroException",
                                 Handler 
=
                                     
new Sequence
                                     {
                                         DisplayName 
= "Divide by Zero Exception Workflow",
                                         Activities 
=
                                         {
                                            
new WriteLine() 
                                            { 
                                                DisplayName 
= "WriteLine: DivideByZeroException",
                                                Text 
= "DivideByZeroException: Promo code is MWK - but number of kids = 0" 
                                            },
                                            
new Assign<double>
                                            {
                                                DisplayName 
= "Exception - discount = 0"
                                                To 
= discount,
                                                Value 
= new InArgument<double>(0)
                                            }
                                         }
                                     }
                             }
                         }
                    }
                },
                Next 
= flowDecision
            };

            FlowStep discountDefault = new FlowStep
            {
                Action 
= new Assign<double>
                {
                    DisplayName 
= "Default discount assignment: discount = 0",
                    To 
= discount,
                    Value 
= new InArgument<double>(0)
                },
                Next 
= flowDecision
            };

            FlowSwitch<string> promoCodeSwitch = new FlowSwitch<string>
            {
                Expression 
= promo,
                Cases 
=
                {
                   { 
"Single", singleStep },
                   { 
"MNK", mnkStep },
                   { 
"MWK", mwkStep }
                },
                Default 
= discountDefault
            };

            Flowchart flowChart = new Flowchart
            {
                DisplayName 
= "Promotional Discount Calculation",
                Variables 
= { discount, promo, numberOfKids },
                StartNode 
= promoCodeSwitch,
                Nodes 
= 
                { 
                    promoCodeSwitch, 
                    singleStep, 
                    mnkStep, 
                    mwkStep, 
                    discountDefault, 
                    flowDecision, 
                    discountApplied, 
                    discountNotApplied
                }
            };
            
return flowChart;
        }

     }

 调用:

  WorkflowInvoker.Invoke(new FlowChartActivity("MWK"2));

    注意这个自定义活动实现与前面两个的区别,它在构造函数中指定实现活动的方法,而这个方法返回Activity类型。

4、NativeActivity

    这个活动是四种活动中最强大的一个,实现起来非常的灵活。WF4.0中内置的Sequence 、While 、If、Parallel 等活动都继承此类。如果前面三种都实现不了,这个活动可能能实现你需要的功能。例如自定一个While:

代码

public sealed class MyWhile : NativeActivity
    {
        Collection
<Variable> variables;

        public MyWhile()
        {
            
this.variables = new Collection<Variable>();
        }

        public Collection<Variable> Variables
        {
            
get
            {
                
return this.variables;
            }
        }

        public Activity<bool> Condition  { getset; }
        
public Activity Body { getset; }

        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            
//call base.CacheMetadata to add the Variables, Condition, and Body to the activity's metadata
            base.CacheMetadata(metadata);

            if (this.Condition == null)
            {
                
//MyWhile requires a Condition expression so - add a validation error if one isn't present
                metadata.AddValidationError(string.Format("While {0} requires a Condition"this.DisplayName));
                
return;
            }
        }        

        protected override void Execute(NativeActivityContext context)
        {
            InternalExecute(context, 
null);
        }

        void InternalExecute(NativeActivityContext context, ActivityInstance instance)
        {
            
//schedule the Condition for evaluation
            context.ScheduleActivity(this.Condition, new CompletionCallback<bool>(OnEvaluateConditionCompleted));
        }

        void OnEvaluateConditionCompleted(NativeActivityContext context, ActivityInstance instance, bool result)
        {            
            
if (result)
            {
                
if (this.Body != null)
                {
                    
//if the Condition evaluates to true and the Body is not null
                    
//schedule the Body with the InternalExecute as the CompletionCallback
                    context.ScheduleActivity(this.Body, InternalExecute);
                }
            }

        }
    }

     简单的看下这个MyWhile,很简单分两个部分看:属性和方法。属性有variables、Condition、和Body。方法有构造函数、CacheMetadata、Execute、OnEvaluateConditionCompleted。CacheMetadata、Execute覆盖父类的方法。ScheduleActivity完成之后执行OnEvaluateConditionCompleted。

总结:WF4.0的资料不多,但是相对WF3.0和3.5简单很多,自定义活动是非常重要学习内容。

抱歉!评论已关闭.