Wednesday, September 7, 2011

The Extensible and Reusable FEATURE Framework

As we all know there are two methods to develop/deploy various artifacts using SharePoint FEATURES : Declaratively using Feature.xml and element files and Programmatically.

Most examples that use programming approach either directly writes code in Feature Activated, Feature Deactivating etc. or use helper methods to promote the reusability of the code. While the second approach ensures reusability, it is not extensible, meaning, you must change code to change the actions that you want to perform in the Feature Receiver class. In my recent SharePoint implementation, I came across the need for extensibility and ended up writing a mini framework for the same.

Following are the elements of the framework and how they are connected to each other:

1. IFeatureAction class which has one method with following signature:

void Execute(object target, XmlElement actionData)

2. A Class named FeatureActionReceiver which is derived from SPFeatureReceiver. Overrides FeatureActivated and FeatureDeactivating methods.

3. The overriden FeatureActivated method looks for FeatureActivated.xml file under {Feature Root}\Actions directory and processes the file (more on processing later). Similarly, FeatureDeactivating looks for FeatureDeactivating.xml file under {Feature Root}\Actions directory

4. The Actions file (FeatureActivated.xml or FeatureDeactivating.xml) contains one of more Actions in following format:

<Actions>

<Action ActionName=”” Class=”” Assembly=””>

<AnyValidXML>

</Action>

<Action ActionName=”” Class=”” Assembly=””>

</Action>

</Actions>

4. Action Processing: the framework class reads the action one after another and for each action, it loads the specified Assembly and Specified class which must implement IFeatureAction class. After creating instance of the Action, it gives an opportunity of providing the target object (on which action needs to be performed) to the parent FeatureReceiver class by calling a virtual method “ProvideTargetObject”. The framework passes action name so that the feature’s receiver class can write a switch statement and provide appropriate target object to the framework. If no object is provided by Feature’s Receiver class, by default, framework will pass Feature’s Parent (depending on scope of feature) to the Execute method of the Action.

5. Now your Feature’s Receiver class must derive from FeatureActionReceiver  instead of SPFeatureReceiver and override FeatureActivated and FeatureDeactivating methods. Here, the Feature’s receiver must call Base.FeatureActivated and Base.FeatureDeactivating methods so that framework can process those actions. Apart from that, as usual other code can be written in the Feature Receiver.

Now, everything that I want to do in Feature Receiver is externalized in a set of Action Classes and those Action classes must get the parameters from XML file (the parameters varies from one project to another) while performing the actions. So that’s about reusability. In addition, performing a new action means writing a new action (if existing action does not satisfy the need, of course) and updating those XML files so that the action will be executed in FeatureActivated or FeatureDeactivating. That’s extensible!!

To give you a few examples, I developed following actions:

1. Create List – It would create list instance, add content types, set other properties, set the views and add fields to the view

2. Create Terms – Accepts a set of Term Groups, Term Sets and a hierarchical Terms data. This will ensure that all terms and term sets required by your application are provisioned using Features

3. Set Master Page – Sets the specified master page for the specified web

4. Create Web – creates the webs using specified Title and Web template

5. Add Feature – Activates a Feature. In my case, it was required to activate some features after creating the web so that my content authors do not need to perform the action

.. the list goes on and on..

I hope all dots are connected. Unfortunately, I cannot share the code here but let me know if you need more information about it.

No comments:

Post a Comment