如何自定义Activity
自定义Activity
一、为什么要自定义Activity
Acitity是工作流的基本组成单元,可以被重用。我们以前谈OO,很核心的一个话题就是重用,而工作流就可以做为一个容器,我们可以将业务逻辑,服务封装成为一个个的Acitity,如果Activity的粒度合适,那么每个Acitity之间是完全解耦的。实现面向流程编程也应该是未来的发展方向。好像在MSDN WebCast上听过:未来的程序员会有一部分专职写Acitivity。所以在WF的应用上,自定义Acitivity是非常重要的一个技能。
二、如何自定义
我在博客园里面看到有几篇文件都是在讲如何自定义Activity的,这里整理了一下,
http://www.cnblogs.com/zhuhee/archive/2007/01/31/635965.html
http://www.cnblogs.com/lovesanni/archive/2007/01/30/634519.html
http://www.cnblogs.com/foundation/archive/2006/10/09/524086.html
下面是一些自己的理解和补充
1.自定义分Activity分为Compact Activity和Basic Activity两种,Compact Activity制作简单,如果是组合逻辑最好用Compact Activity。Basic Activity顾名思意,象lab02那样的send mail Acitivity就应该使用Basic Activity
写Basic Activity多用 Insert Snippet,arrtibute写起来实在比较麻烦。
2.充分利用arrtibute的强大功能
lab02上面有两个例子,分别实现了设计时和运行时对Activity校验,设计时修改Activity的外观。下面的图片就是改变外观的例子
常见的Attribute如下:
Designer: This component defines the visual representation of the activity on the workflow and custom activity designers.
Code generator: This is an extensibility point to generate custom code for an activity in a workflow. InvokeWebService, which is an out-of-the-box activity has such an implementation.
Validator: This component enforces the activity semantics both at the design time and run time (only during dynamic update).
Toolbox item: Defines the custom behaviour of the toolbox item representing the activity in a design environment like Visual Studio.
Executor: This is a stateless component which implements the execution semantics of an activity. This component may not be defined for simple cases, where the Execute() method of the activity is overridden as it was the case in the previous exercise.
Serializer: Provides customized serialization behaviour if needed.
Deployer: This code is run when a workflow including the activity is deployed to a hosting environment.
3.关于lab中activity校验的翻译
自定义acitivity校验:有设计时检验和运行时检验两种能力
根据你创建的是basic还是composite,分别采用ActivityValidator或CompositeActivityValidator做基类建校验类
Override ValidateProperties进行逻辑校验,校验逻辑写在另一个被调用方法内。
{
ValidationErrorCollection validationErrors = new ValidationErrorCollection(base.ValidateProperties (manager, obj));
SendMailActivity sendMailActivityToBeValidated = obj as SendMailActivity;
if (sendMailActivityToBeValidated == null)
{
throw new InvalidOperationException("Parameter obj is not of type SendMailActivity");
}
if (!IsValidEmailAddress(sendMailActivityToBeValidated.To))
{
ValidationError CustomActivityValidationError =
new ValidationError(String.Format("\'{0}\' is an Invalid destination e-mail address", sendMailActivityToBeValidated.To), 1);
validationErrors.Add(CustomActivityValidationError);
}
if (!IsValidEmailAddress(sendMailActivityToBeValidated.From))
{
ValidationError CustomActivityValidationError =
new ValidationError(String.Format("\'{0}\' is an Invalid source e-mail address", sendMailActivityToBeValidated.From), 1);
validationErrors.Add(CustomActivityValidationError);
}
return validationErrors;
}
public Boolean IsValidEmailAddress(String address)
{
// must only proceed with validation if we have data
// to validate
if (address == null || address.Length == 0)
return true;
Regex rx = new Regex(@"[^A-Za-z0-9@\-_.]", RegexOptions.Compiled);
MatchCollection matches = rx.Matches(address);
if (matches.Count > 0)
return false;
// Must have an '@' character
int i = address.IndexOf('@');
// Must be at least three chars after the @
if (i <= 0 || i >= address.Length - 3)
return false;
// Must only be one '@' character
if (address.IndexOf('@', i + 1) >= 0)
return false;
// Find the last . in the address
int j = address.LastIndexOf('.');
// The dot can't be before or immediately after the @ char
if (j >= 0 && j <= i + 1)
return false;
return true;
}
记得给自定义Activity加上ActivityValidator attribute