WF4.0:四种自定义类型活动
工作流中的活动就像用户自定义的控件,将许多的功能封装起来用。WF4.0中提供了四种可继承的活动类:CodeActivity 、AsyncCodeActivity、Activity、NativeActivity。这几种活动都有自己使用的适合场合,正确的使用这些活动将非常有利。
1、CodeActivity
WF4.0中的活动是树形结构的,创建叶子活动最简单是方式就是使用CodeActivity ,它的逻辑都放在一个方法:Execute 里面,这个也是四种活动中最简单的一种。这里用一个简单的自定活动HttpGet来说明怎么使用CodeActivity。HttpGet的功能是从网络上抓取数据。
{
public InArgument<string> Uri { get; set; }
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的上下文,非常有用。
如何使用这个活动:
{
Uri = "http://www.msn.com"
};
string msnContent = WorkflowInvoker.Invoke<string>(fetchMsn);
Console.WriteLine(msnContent);
2、AsyncCodeActivity
AsyncCodeActivity 类似CodeActivity ,只是它是使用了 Begin/EndExecute 取代了CodeActivity的Execute 方法。BeginExecute 开始一个异步操作,无需等待它完成,就返回IAsyncResult对象 。当这个操作完成的时候,就执行EndExecute 方法放回结果。HttpGet 能这样实现,请注意CodeActivityContext换成了AsyncCodeActivityContext:
{
public InArgument<string> Uri { get; set; }
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 string promoCode { get; set; }
public int numKids { get; set; }
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;
}
}
调用:
注意这个自定义活动实现与前面两个的区别,它在构造函数中指定实现活动的方法,而这个方法返回Activity类型。
4、NativeActivity
这个活动是四种活动中最强大的一个,实现起来非常的灵活。WF4.0中内置的Sequence 、While 、If、Parallel 等活动都继承此类。如果前面三种都实现不了,这个活动可能能实现你需要的功能。例如自定一个While:
{
Collection<Variable> variables;
public MyWhile()
{
this.variables = new Collection<Variable>();
}
public Collection<Variable> Variables
{
get
{
return this.variables;
}
}
public Activity<bool> Condition { get; set; }
public Activity Body { get; set; }
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简单很多,自定义活动是非常重要学习内容。
(全文完)
以下为广告部分
您部署的HTTPS网站安全吗?
如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!
快速了解HTTPS网站安全情况。
安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。
安装部署SSL证书变得更方便。
SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。
让服务器远离SSL证书漏洞侵扰
TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。