Activity Component Model


An activity type is more than just a class that derives, directly or indirectly, from Activity.

Table 7.1 lists five standard components that can be associated with any activity type. The Activity class carries defaults for all of these, and therefore when you define an activity type, you only need to develop custom versions of one or more of these components if a specific requirement of your activity demands it.

Table 7.1. Activity Components

Name

Description

Validator

Validates the correctness of an activity within a WF program

Code Generator

Emits code into the CLR type resulting from compilation of the WF program in which the activity resides

Designer

Renders the activity within a visual design environment

Toolbox

Item Represents the activity in the toolbox of a visual design environment

Designer Serializer

Serializes an activity to a specific format, such as XAML or CodeDOM


Before we move into deeper discussion of the component types, though, let's first consider the specific benefits of the design approach that allows these pieces of orthogonal functionality to be factored into different classes that are associated with an activity.

The basic principle behind the factoring of activity functionality into separate components is modularitythe separation of code into different modules among which there are well-defined relationships. This approach allows orthogonal pieces of functionality to be developed independently and to then be associated with one another in such a way as to improve the understandability (and the maintainability) of both the individual parts as well as the ways in which the parts relate. If WF did not embrace this principle, activity classes would be larger, more cumbersome and difficult to develop, and harder to understand.

There are several reasons that support the adoption of this design approach, beginning with the fact that it allows selective instantiation of an activity's capabilities. For example, the WF runtime does not care about the designer associated with an activity and therefore never needs to deal with this component. Aside from the cleanliness of the design, this helps keep the runtime (binary) serialization size of activity objects small, which can help the performance of an application that is executing WF program instances that travel to and from persistent storage.

Additionally, component attributes are inheritable, which means that an activity will inherit associations with components. For example, an activity writer only needs to develop a toolbox item component if the toolbox item of the activity's base class is not adequate. Also, the separation of orthogonal pieces of functionality allows the activity developer to get around restrictions on multiple inheritance by separately inheriting different activity components from the required base classes.

To summarize, every activity has an associated family of components that collectively determines its capabilities. The class that defines an activity type has two major purposes. The first is to specify the activity's properties. The second is to define the execution logic of the activity (as discussed in Chapters 3 and 4). Components associated with the activity provide additional aspects of the activity's functionality.

Table 7.2 lists the attribute types that are used to associate components with an activity. Only the ActivityValidatorAttribute and the ActivityCodeGeneratorAttribute are defined in a WF namespace; the other three are defined under System.ComponentModel.

Table 7.2. Attribute Types for Activity Components

Name

Attribute Type

Validator

System.Workflow.ComponentModel.Compiler.ActivityValidatorAttribute

Code Generator

System.Workflow.ComponentModel.Compiler.ActivityCodeGeneratorAttribute

Designer

System.ComponentModel.DesignerAttribute

Toolbox Item

System.ComponentModel.ToolboxItemAttribute

Designer Serializer

System.ComponentModel.Design.Serialization. DesignerSerializerAttribute


Table 7.3 displays the values of the ValidOn, AllowMultiple, and Inherited properties of each of the attribute types listed in Table 7.2. These are standard properties of all attributes, as defined by System.AttributeUsageAttribute. As you can see, an activity class can be associated with exactly one validator, one code generator, and one toolbox item (associations can also be inherited from the base class of the activity and interfaces implemented by the activity). And, an activity can be associated with any number of designers and serializers (which, again, may be inherited).

Table 7.3. Standard Properties of Attribute Types of Table 7.2

Attribute Type

ValidOn

AllowMultiple

Inherited

ActivityValidatorAttribute

Interface, Class

false

true

ActivityCodeGeneratorAttribute

Interface, Class

false

true

DesignerAttribute

Interface, Class

true

true

ToolboxItemAttribute

All

false

true

DesignerSerializerAttribute

Interface, Class

true

true


As you might expect, the Activity class has associations with a set of components, which act as default components for any activity. Custom activities only need to provide custom component associations when the defaults are not sufficient. If, for example, a custom toolbox item is not directly associated with an activity type, an association with the default activity toolbox item will be inherited from Activity. Listing 7.8 shows the Activity class's component associations.

Listing 7.8. Activity Components

 namespace System.Workflow.ComponentModel {   [ActivityValidator(typeof(ActivityValidator))]   [ActivityCodeGenerator(typeof(ActivityCodeGenerator))]   [Designer(typeof(ActivityDesigner), typeof(IDesigner))]   [Designer(typeof(ActivityDesigner), typeof(IRootDesigner))]   [ToolboxItem(typeof(ActivityToolboxItem))]   [DesignerSerializer(typeof(ActivityMarkupSerializer),     typeof(WorkflowMarkupSerializer))]   [DesignerSerializer(typeof(ActivityCodeDomSerializer),     typeof(CodeDomSerializer))]   [DesignerSerializer(typeof(ActivityTypeCodeDomSerializer),     typeof(TypeCodeDomSerializer))]   public class Activity : DependencyObject   {     ...   } } 


As expected, Listing 7.8 confirms that Activity has a validator, a code generator, and a toolbox item. Additionally, there are two default designer associationsone for an IDesigner and a second for an IRootDesigner (both of these designer interfaces are defined in the System.ComponentModel.Design namespace). Finally, there are three default serializersone for XAML, a second for standard CodeDOM, and a third for CodeDOM type serialization.

Listing 7.9 shows that CompositeActivity, which inherits from Activity, provides its own validator and code generator components, and also its own XAML serializer. Of course, based upon what we just learned, CompositeActivity will inherit associations with a toolbox item component, two designers, and two CodeDOM serializers from Activity.

Listing 7.9. CompositeActivity Components

 namespace System.Workflow.ComponentModel {   [ActivityValidator(typeof(CompositeActivityValidator))]   [ActivityCodeGenerator(typeof(CompositeActivityCodeGenerator))]   [DesignerSerializer(typeof(CompositeActivityMarkupSerializer),     typeof(WorkflowMarkupSerializer))]   public class CompositeActivity : Activity   {     ...   } } 


In the remainder of this chapter, we will examine the details of three of the five componentsvalidator, code generator, and designer serializer. We will begin with the two topics that are specific to the WF programming model: activity validation and code generation. The designer and toolbox item components will be given lighter treatment in Chapter 8, "Miscellanea," because here the WF programming model builds upon established elements of the .NET Framework.




Essential Windows Workflow Foundation
Essential Windows Workflow Foundation
ISBN: 0321399838
EAN: 2147483647
Year: 2006
Pages: 97

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net