Content
3. Event Receivers and Item Updating Tasks
4. Content Types Definition Tasks
5. InfoPath Forms Development Tasks
This document describes the implementation of several tasks with Windows SharePoint Services and Microsoft Office SharePoint Server.
It also contains tips, important implementation details and risks.
If you have technical questions or remarks, please email Elena Popretinskaya (Elena.Popretinskaya@gersis-software.com).
If you like to discuss Sharepoint-related development projects, please email Walter Fertl (walter.fertl@nearshoresolutions.de)
|
Task
|
Description
|
Approach
|
Efforts
|
Risks
|
Links
|
|
Processing event OnTaskCreated
|
In many cases it is necessary to implement some actions when Task created (e.g. notify user by email without usage of standard email) |
1. Double-check that the OnTaskCreated event is triggered for any count of tasks. It is possible that the OnTaskCreated event will work (will fire) for 1 task, for 2 tasks, but won’t for 3 tasks. 2. If possible avoid this event, because of its instability. The workaround for this event is using Event Receiver for event ItemAdded for Task Content Type or Task List of Workflow. |
1. It is necessary to implement Event Receiver for Task and also register it for Task Content Type or Task List instead of implementing one method for OnTaskCreated activity. 2. To register Event Receiver you should use Object Model if possible (e.g. using Feature Receiver, or register it right at Workflow) because registering via CAML-file is quite instable. |
Sometimes this event is not triggered for all tasks and even causes Workflow hanging. Using Event Receiver causes additional efforts, since you need to keep them up-to-date (re-register properly Event Receivers when implementation changes). Moreover it is harder to maintain Workflow because you need to remember not only about the workflow itself but also about associated Event Receivers for Tasks |
Workflow hang when starting two workflows in between short time period. |
|
Processing all task events
|
|
1. Be sure that all Task-related activities (such as CreateTask, CompleteTask, OnTaskChanged, OnTaskDeleted, etc.) have the same Correlation Tokens 2. Be sure that there are no duplicated tokens with the same name at Workflowname.designer.cs. For example you may have two tokens (correlationToken1, correlationToken2) with name “taskToken” and parent activity “taskSequence”. Visual Studio produces such duplication when you copy/paste your activities at Workflow designer. It seems that events are not triggered properly when such duplicated tokens exist. 3. Be sure that all workflow activities attached to the same task have the same TaskId property (the same one that is being bound to CreateTask activity) 4. Be sure that all custom fields in your workflow/activity/event argument classes are serializable. Otherwise the workflow engine may be not able to deliver your events properly. |
You need to declare an activity for each task event and task action and create appropriate handlers for your activities. |
Since Visual Studio provides poor support for workflow configuration check, most problems occur only at Runtime. This causes risk for the solution stability. |
|
|
Cancelation of the workflow
|
Sometimes you need to cancel (not terminate) a workflow. The difference between cancelation and termination is: Termination of a workflow deletes all tasks associated with it. It also requires special permissions (you should have the permission to manage the list where a workflow is being used). Cancellation of a workflow is a business function that just finishes the workflow. |
1. Cancelation of a workflow should be implemented with the help of Workflow Modification. 2. Be sure that your EnableWorkflowModification activity and OnWorkflowModification activity have the same unique correlation token (you may call it “modificationToken”) 3. Place your EnableWorkflowModification activity to the same EventHanglingActivityScopeyou use for event processing of your tasks. 4. Be sure that EnableWorkflowModification and OnWorkflowModified that handles the same modification (in this case – Workflow Cancelation) have the same ModificationId (the one you have declared at workflow.xml) For example if at your workflow.xml you have declared modification <Modification_2cffa9d7-c7c7-4a71-9567-846239aa7e58_Name>Cancel the workflow</Modification_2cffa9d7-c7c7-4a71-9567-846239aa7e58_Name>
You need to set ModificationId property of EnableWorkflowModification and OnWorkflowModified to 2cffa9d7-c7c7-4a71-9567-846239aa7e58
5. In order to set custom status for your workflow tasks use UpdateAllTasks activity. 6. To cancel all tasks immediately, you may use an approach with exception. Just set the variables you need at the OnWorkflowModification event processing method, throw you custom exception. Then create FaultHandler for your exception and use UpdateAllTasks activity to process the task cancellation (e.g. set special task status to tasks) |
1. Declare a new modification at workflow.xml 2. Declare your EnableWorkflowModification and OnWorkflowModified activity for this modification 3. Declare the UpdateAllTasks activity to set custom status for your workflow tasks 4. If you want to finish the workflow immediately after cancellation (you don’t want to wait while the OnTaskChanged event will be triggered for every task), implement your custom Exception class and declare FaultHandler at EventHandlingActivityScope |
When you finish the workflow by awaiting of every OnTaskChanged event triggered in result of workflow cancelation, it is possible that OnTaskChanged events won’t fire for all tasks and it is a risk for the workflow stability. |
See SDK samples (Approval Workflow Sample).
|
|
Setting custom workflow status
|
When the workflow finishes, you need to set custom workflow status (not the standard one, e.g. Finished) |
1. Use the SetState activity to change the standard workflow status. 2. Don’t use standard status at SetStatus activities. The reason – when using standard statuses at a SetStatus activity, the workflow engine will fail with a “Value does not fall in expected range” error. If you need to set the status of the workflow to standard, just create your custom status with the same name. |
1. Declare SetState activity for your workflow 2. Declare your custom status at workflow.xml For example:
<ExtendedStatusColumnValues> <StatusColumnValue>Canceled by User</StatusColumnValue>
<StatusColumnValue>Finished</StatusColumnValue>
</ExtendedStatusColumnValues>
3. Use the code as shown below at SetState handler: workflowStatus = Convert.ToInt32(workflowWasCanceled ? SPWorkflowStatus.Max : SPWorkflowStatus.Max + 1); workflowStatus – variable that is bound to Status property of SetState activity. SPWorkflowStatus.Max corresponds <StatusColumnValue>Canceled by User</StatusColumnValue>
SPWorkflowStatus.Max + 1 corresponds <StatusColumnValue>Finished</StatusColumnValue> |
You need to duplicate standard status for your custom ones, and it may cause inconsistencies in the future. |
Ready, Set, Workflow – Using SetState to Update Workflow Status |
|
Updating List Items and Documents at Workflow
|
|
1. When updating Document at Workflow, avoid errors caused by situations when the document is checked out. Use SystemUpdate(false) method instead. |
Implement code as shown below:
SPSecurity.RunWithElevatedPrivileges(delegate{
listItem[BSEU_DOC_STATUS] = BSEU_DOC_STATUS_IN_WORK; listItem.SystemUpdate(false);
});
|
The workflow does not always change the value of Item Fields (e.g. we find this for a read-only field: when a document is checked out, the field value is not being updated) |
Update a SPListItem without having to check it out... |
|
Task
|
Description
|
Approach
|
Efforts
|
Risks
|
Links
|
|
Automatically change the field value on Item Updating |
In many cases it is necessary to implement an automatic change of the attribute of List Item or Document when some event occurs (e.g. automatically change the status of the document) |
1. You need to use Event Receiver for this purpose, registered for List or Content Type. 2. If the field you need to change is visible at edit form, change it at ItemUpdating event handler with the help of properties.AfterProperties[“<FieldName>”] 3. If the field you need to change is NOT visible at the edit form, change it at ItemUpdated event handler by changing the list Item itself: public override void ItemUpdated(SPItemEventProperties properties) { properties.ListItem[<FieldName>] = <Field Value>; properties.ListItem.SystemUpdate(false);//prevent additional Version incrementation } |
It is necessary to implement Event Receiver for Content Type and also register it for Task Content Type or List/Document Library. To register Event Receiver, you should use Object Model if possible (e.g. usage of Feature Receiver, or register it right at Workflow) because registering via CAML-file is quite instable. |
Sometimes changing values via properties.AfterProperties[“FieldName”] does not work. E.g. we found this situation when a field that is not showing at Edit form, it is not changed by the ItemUpdating event processor. |
|
|
Reading DateTime fields on Item Updating/Item Adding event |
|
1. Always check the format of DateTime field which comes to your event 2. In some cases DateTime field values come to the event in weird hex formats (like “0x01c9874e|0x98f28800”). This seems to occur only with Office 2007 documents (for other file types, the value is a standard string format for a date). The article says that the hexadecimal value represents the number of ticks since 1/1/1600. But in our project it was this number of ticks - 3 hours. So better always check results of workarounds proposed. |
Implement date parsing with code as shown below:
var published = properties.AfterProperties[DATE_PUBLISHED]; if (published == null) return; string dateString = published.ToString();
DateTime publishedDate;
try
{
publishedDate = DateTime.Parse(dateString);
}
catch (FormatException ex) {
//NOTE: For 2007 Office documents Workaround: publishedDate = new DateTime(long.Parse(dateString.Replace("0x", "").Replace("|", ""), System.Globalization.NumberStyles.HexNumber)).AddYears(1600).AddHours(3); }
|
This strange SharePoint behavior is undocumented and in future releases of SharePoint the meaning of this hex format may be changed. |
SPListItem.Properties DateTime Fields are in weird Hex format |
|
Update a document from code without changing its version |
|
1. Use listItem.SystemUpdate(false) method for this purpose. |
–
|
–
|
–
|
|
Task
|
Description
|
Approach
|
Efforts
|
Risks
|
Links
|
|
Content type definition schema
|
You need to create your own data structure to be used at your site. |
1. Use CAML to define new content types for your site. Content type is analog to the database schema for SharePoint, therefore it is better to have a definition file for this schema. 2. You should test your Content Type schema very carefully before using it in production. The reason: once this Content Type is being installed and activated there is no way to change the existing Content Type via the CAML file. 3. If you want to change the existing Content Type at the production environment, you should do this via UI or Object Model. Alternatively you can Define new Content Type and move old to hidden. Note: In a testing environment, you can delete the Content Type you need to change (for this purpose you should be sure that there are no documents and custom child content types for the Content Type you want to delete) and then reinstall it. 4. Alternatively you can keep the existing Content Type and create a new one with the same properties + new/changed properties. In this case, the out-of-date version of your content type should be moved to Hidden content types to avoid its future use. |
1. Define your new Content type at your CAML file 2. Define the feature that will be deployed to your site to install new Content type |
Since there is no way to change an existing Content Type via CAML file, this causes additional efforts to keep Content Type schema up-to-date and sometimes it is hard to say if it is actual or not. |
Content Type Deployment Using Features Content Type Feature with Document Template SharePoint - Provisioning a content type with CAML |
|
Content Type Inheritance
|
|
1. Use Content Type inheritance to create a group of Content Types with the same nature 2. Remember that all changes made to parent Content Type have an influence on their children. |
To Create Content Type inheritance in a CAML file, define a Content Type ID for child type as <ParentContentTypeID>00<UniqueIDForYourChild> E.g. if you have parent Content Type 0x010100D6B040DF31404711B830F12EF1259EEB for child content type IDcan be 0x010100D6B040DF31404711B830F12EF1259EEB00 6B21807A72D848B9AE27B77DBB023036 |
|
|
|
Task
|
Description
|
Approach
|
Efforts
|
Risks
|
Links
|
|
InfoPath Forms for Workflow
|
In many cases you need to set default values or initial values for your workflow. |
1. When creating an InfoPath form for Initiation and Association, be sure you use the same data schema for Initiation/Association data in your Initiation and Association forms 2. Do not forget to add the context.xml data source to your form to make the form workflow enabled. 3. Make sure that your form has at least domain level security. Better to use Full Trust security level. Otherwise web-enabled forms can be inaccessible for users 4. Do not forget to publish the form before you use it. |
1. Create a form template at InfoPath. Introduce custom data validation and conditional formatting rules for the form. 2. In order to use the form at your workflow, specify corresponding form URNs at workflow.xml. 3. In order to use Initiation/Association data at your code, you should save form templates as sources, and then generate class (<schemaName>) for saved xsd file with the help of the built in VS utility called xsd. |
InfoPath form deployment to SharePoint (as well as any kind of deployment to SharePoint) is not very informative. So even if you have got errors during deployment, you might not be able to see the reason or even to see any error at all. So every time you update the form, you should check if you are really working with the actual version. |
Создание XSN-форм для рабочих процессов (Workflow) Creating an association and initiation form in a workflow using VS.NET 2008 How to: Configure a Contact Selector Control on Your InfoPath Workflow Form Workflow + InfoPath Forms, Form is not workflow enabled?? |
|
Get User Details at InfoPath form
|
|
1. Use Web Services functionality provided by SharePoint 2. Be sure that the link to Web Service is set on Site level, not on Domain level. Otherwise users who don’t have access to the domain level site won’t be able to work with a form receiving 5566 error For example incorrect approach is shown below http://sp:5231/_vti_bin/UserProfileService.asmx?WSDL
correct version:
http://sp:5231/sites/bseu/_vti_bin/UserProfileService.asmx?WSDL
3. Check that security and network settings are configured properly for your site. The symptoms of incorrect settings are the 5566 error, which occurs during form opening. Check your <defaultProxy> Element (Network Settings) at web.conf file for the site. |
1. Define new data source which obtains the data from Web Services. 2. Use this data source for different validations at your InfoPath form. |
The link to Web Services at the InfoPath form is hard-coded, therefore every time you deploy a solution to a new site, you should change the form itself with the help of InfoPath. Moreover, in order to save the form you should connect to Web Services. It means you should be able to change the form from the PC on which the target site is accessible, and you should have permissions to access it. Such an approach is not scalable enough. Security and network settings configuration is a non-trivial thing and causes troubles during usage of Web Services, since error messages are not very informative. |
InfoPath - Get the current user without writing code InfoPath 2007: Ошибка при доступе к источнику данных (5566) |
|
Task
|
Description
|
Approach
|
Efforts
|
Risks
|
Links
|
|
Queries to Lists
|
In many cases you need to obtain list data by some criteria. |
1. You need to use CAML queries for this purpose 2. Use U2U CAML Builder or another tool to debug your queries. |
You need to build your CAML query and execute it for list or site: SPQuery yourList = someList;
SPQuery query = new SPQuery{
ViewFields = string.Format(
@"<FieldRef Name = {0}/><FieldRef Name ='{1}'/><FieldRef Name ='{2}'/>",<yourFieldName1>, <yourFieldName2>, <yourFieldName3>) };
query.Query = <yourCAMLQueryString>; yourList.GetItems(query;
|
Wrong queries do not throw any exception Therefore it is possible to overlook a wrong query if you don’t check it well enough. |
|
|
Changing visibility of menu Items for standard List View |
Sometimes you don’t need all the Items listed at the toolbar menu, or you simply want to change their names |
1. There is no standard way (via site settings or feature deployment) to change the content of the standard toolbar menu (Create/Upload/Actions/Settings) for list item view. 2. In order to hide menu items, you should use custom third-party WebParts (such as Toolbar Manager) or write your own (containing scripts that hide page elements) |
–
|
Since you need to use third-party or your own WebParts you should double-check their stability. When you are replacing a standard one with a workaround, then when the implementation of a standard element changes, this may cause faults with your workarounds. |
|
|
Editing the content of ECB-menu (context menu for items) |
|
1. There is no standard way (via site settings or feature deployment) to hide/change standard ECB menu items (Edit settings/View/Check Out/Check In, etc.) for list item view. 2. In order to change the ECB content, you need to use action features for deployment of your Custom menu items and you need to change the standard ECB rendering script if you want to modify standard ECB menu items |
In order to change the ECB content, you need to use action features for deployment of your Custom menu items and you need to change the standard ECB rendering script if you want to modify standard ECB menu items |
Since you need to change the standard menu rendering script, this causes risks and lower maintainability. Moreover if you need to change ECB only for a few lists, this approach greatly increase efforts necessary to implement this script, since all site pages use the same script for ECB rendering. |
How to: Hide a Menu Item in the ECB from SharePoint List Items |
|
List Users from Active Directory (AD) group added to site |
|
1. There is no standard way for SharePoint to list the users from AD group added to the site. In the Object Model, the AD group is represented with SPUser with property IsAdGroup = true. 2. Possibly you should query the AD group (e.g. query the LDAP server) from your code, in order to retrieve all users from AD group. |
–
|
You need to re-implement what is implemented already inside SharePoint. This causes additional risks for product maintainability, since you should manage AD-connection settings at your code. |
Add users of an AD Group to the SharePoint Site |
If you have any questions - we will do our best to answer these.
Please send your questions and remarks to Elena Popretinskaya (Elena.Popretinskaya@gersis-software.com).
If you like to discuss Sharepoint-related development projects, please email Walter Fertl (walter.fertl@nearshoresolutions.de)