Document Workflow


Workflow is truly a necessity for a system like Office 2003, and its absence from SharePoint Services is significant. What makes the situation worse is the fact that SharePoint Portal Server 2001 (SPS2001) had a workflow engine ”albeit a simple one. This means that users of SPS2001 may see the lack of workflow as an indication that SPS2003 is a lesser product.

On the positive side, you can reproduce the workflows that were available in SPS2001 using the SharePoint Services object model. This object model will allow you to capture events associated with a document library and respond to those events by moving documents, sending mail, or other actions.

Note

If you want to move beyond basic workflow to automate more complex processes, you may find that SharePoint Services does not offer enough functionality. In these cases, you will want to investigate the use of third-party workflow engines. My favorite engine is K2.net 2003 available at www.k2workflow.com .

Capturing Events

You begin developing document workflow by trapping events that occur in a document library. To capture events, you must perform a series of configuration and programming tasks. These tasks include enabling event handlers, creating the event-handling class, and connecting the class to a target document library.

Enabling Event Handlers

Before you begin to receive the events, however, you have to enable document events for libraries associated with your SharePoint installation.

To enable document library events, follow these steps:

  1. Log on to SPSPortal as the local administrator.

  2. Select Start All Programs SharePoint Portal Server SharePoint Central Administration.

  3. On the SharePoint Portal Server Central Administration page, select Portal Site and Virtual Server Configuration Configure Virtual Server Settings from the Virtual Server List.

  4. On the Virtual Server List page, select the link for the site where you have installed SharePoint Services (typically Default Web Site).

  5. On the Virtual Server Settings page, select Virtual Server Management Virtual Server General Settings.

  6. On the Virtual Server General Settings page, in the Event Handlers section, select to turn on event handlers.

  7. Click OK.

Creating the Event Handler

Once event handlers are enabled for document libraries, you may trap them by creating a custom class library that implements the Microsoft.SharePoint.IListEventSink interface. This interface has only one member, the OnEvent method. This method is called whenever a trappable event occurs in a targeted document library and receives an SPListEvent object that describes the event through the SPListEventType enumeration. Table 9-1 lists the events that are trapped by the OnEvent method.

Table 9-1: Document Library Events

EVENT

DESCRIPTION

SPListEventType.CheckIn

Fires when a document is checked into the library

SPListEventType.CheckOut

Fires when a document is checked out of the library

SPListEventType.Copy

Fires when a document is copied

SPListEventType.Delete

Fires when a document is deleted

SPListEventType.Insert

Fires when a new document is added to the library

SPListEventType.Move

Fires when a document is moved to another library

SPListEventType.UncheckOut

Fires when a checkout is overridden by an administrator

SPListEventType.Update

Fires when a document is edited or the status changes

Typically, when you code the OnEvent method, you use conditional programming to trap the event of interest. In the branch logic, you can then take appropriate action to respond to the event. Listing 9-1 shows a simple Select-Case structure that allows a class to trap any event fired by a document library.

Listing 9-1: Trapping Library Events
start example
 Public Sub OnEvent(ByVal listEvent As Microsoft.SharePoint.SPListEvent) _ Implements Microsoft.SharePoint.IListEventSink.OnEvent     Dim objWriter As StreamWriter     objWriter = New StreamWriter("c:\events.txt", False)     Select Case listEvent.Type         Case SPListEventType.CheckIn             objWriter.WriteLine("CheckIn")         Case SPListEventType.CheckOut             objWriter.WriteLine("CheckOut")         Case SPListEventType.Copy             objWriter.WriteLine("Copy")         Case SPListEventType.Delete             objWriter.WriteLine("Delete")         Case SPListEventType.Insert             objWriter.WriteLine("Insert")         Case SPListEventType.Invalid 'Not used         Case SPListEventType.Move             objWriter.WriteLine("Move")         Case SPListEventType.UncheckOut             objWriter.WriteLine("UncheckOut")         Case SPListEventType.Update             objWriter.WriteLine("Update")     End Select     objWriter.Close() End Sub 
end example
 

Although the basics of coding the class are simple, there is one wrinkle when implementing it in production. Event handling classes run in the context of the Internet Information Server (IIS) Application Pool Identity. This identity typically has little permission and cannot access objects in SharePoint Services. You can find out what account is running the application pool using the IIS Manager.

Here are the steps to follow to view the Application Pool Identity:

  1. Log on to SPSPortal as the local administrator.

  2. Select Start Administrative Tools Internet Information Services (IIS) Manager.

  3. In the Internet Information Services (IIS) Manager dialog, expand the tree and open the Application Pools folder.

  4. Right-click the MSSharePointPortalAppPool node and select Properties from the pop-up menu.

  5. Click the Identity tab.

Note

If you have set up your test environment in accordance with this book, your Application Pool Identity will be the local administrator for SPSPortal . Although this is fine for the test environment, you may want to consider changing it for production systems. You can change the identity in the SPS Central Administration pages in the same way you initially did during setup.

Because the Application Pool Identity does not generally have permission to access the SharePoint Services namespaces necessary to manage the document workflow, you need to change the identity under which the event handler runs. You can do this by retrieving a new Windows token for an account that has the appropriate permissions and creating a new System.Security.Principal.WindowsIdentity object. A WindowsImpersonationContext object is then created to build a context under which the handler can run. Listing 9-2 shows how to create the new context in VB.NET using the Windows API Function LogonUser .

Listing 9-2: Changing the Identity Context
start example
 Dim objContext As WindowsImpersonationContext Dim objToken As New IntPtr(0) Dim ID As WindowsIdentity Const LOGON32_PROVIDER_DEFAULT As Integer = 0 Const LOGON32_LOGON_NETWORK As Integer = 3 'Logon using the new credentials objToken = IntPtr.Zero Dim blnReturn As Boolean = _    LogonUser ("administrator", "sps", "password", _       LOGON32_LOGON_NETWORK, _       LOGON32_PROVIDER_DEFAULT, objToken) 'Create the new identity context ID = New WindowsIdentity(objToken) objContext =ID.Impersonate 'Handle library events here 'Tear down context objContext.Undo 
end example
 

Once the class is written, you are ready to build it and connect it to a target library. Event handling classes must be placed in the Global Assembly Cache (GAC) to function correctly, and assemblies in the GAC require strong names . Therefore, you need to create a key pair for the class and reference the key pair in the AssemblyInfo file. These steps will not be repeated here because you have performed them several times when you were building web parts in the earlier chapters.

After you have given the assembly a strong name and compiled it, you may place it in the GAC. Although a special utility called gacutil.exe is available for adding assemblies to the GAC, all you really need to do is drag the assembly to C:\Windows\assembly and drop it. This directory contains the GAC and is outfitted with a special shell extension that will automatically add your assembly to the GAC.

Connecting to the Target Library

Once the assembly is properly installed in the GAC, you can connect it to a target document library. Connecting the event handler to a library is accomplished from within SPS itself. You must navigate to the target library and select to change the advanced settings. The connection is made by specifying the full strong name for the assembly in the form Assembly,Version,Culture,PublicKeyToken .

The required format is identical to the format you have already used to mark web parts as safe in the web.config file. However, you must be very careful to type in the string correctly and observe case-sensitivity with the assembly and class name. Any mistake in the string will cause SharePoint Services to throw an error.

Here is what you need to do to connect the event handler to a library:

  1. Log in to SPS as a member of the Administrator site group .

  2. Navigate to a document library from which you want to receive events.

  3. Click the Modify Settings and Columns link in the Actions list.

  4. On the Customize Library page, select General Settings Change Advanced Settings.

  5. On the Document Library Advanced Settings page, locate the Event Handler section.

  6. In the Assembly Name text box, type the full, case-sensitive strong name of the assembly. The following code shows an example:

     LibraryEvents,Version=1.0.0.0,Culture=Neutral, PublicKeyToken=b2bb66c9e13ee2f9 
  7. In the Class Name text box, type the full, case-sensitive name of the handling class. The following code shows an example:

     LibraryEvents.Handler 
    Note

    The Properties field is optional and may contain any text. This value is available in the event handler from the SinkData property of the SPListEvent object, which is discussed momentarily.

  8. Click OK.

  9. Restart IIS.

Manipulating Documents

After you have trapped the document library events, you will want to respond by taking programmatic action on the targeted document. The SharePoint Services namespace contains classes that allow you access to library structures, document properties, and document actions. Using these classes, you can detect a wide variety of user actions, from document changes to approvals and rejections. Your event handler can then complete the workflow by moving or copying files based on these user actions.

Referencing Event Information

Once an event is received by your handling class, you will immediately want to know key information about the event such as what document caused it to fire. The OnEvent method receives an SPListEvent object that contains references to many of the objects that you will need to respond to user-generated events. Table 9-2 lists each property of the SPListEvent class with a brief explanation.

Table 9-2: Properties of the SPListEvent Class

PROPERTY

TYPE

DESCRIPTION

Type

Microsoft.SharePoint. SPListEventType

Returns the type of event that was trapped.

ListID

System.Guid

Returns the Globally Unique Identifier (GUID) of the document library where the event occurred.

Site

Microsoft.SharePoint. SPSite

Returns the parent site object containing the document library that caused the event. This is useful if the same handler is connected to multiple libraries.

WebUrl

String

Returns the absolute URL of the site where the event occurred.

SinkData

String

The value of the user-defined text entered in the Properties text box when the event handler is initially connected to the document library. This is useful if the same handler is connected to multiple libraries.

Title

String

The title of the document library that raised the event.

PropertiesBefore

System.Collections. Hashtable

Returns a set of key-value pairs that represents the state of the document before the event was fired.

PropertiesAfter

System.Collections. Hashtable

Returns a set of key-value pairs that represents the state of the document after the event is fired.

UrlAfter

String

Returns the site-relative URL of the document after the event is fired. The document URL can change based on user actions such as document rejection .

UrlBefore

String

Returns the site-relative URL of the document before the event was fired.

UserDisplayName

String

Returns the display name of the user whose actions fired the event.

UserID

Int32

Returns the ID of the user whose actions fired the event.

UserLoginName

String

Returns the user name of the user whose actions fired the event.

If you examine the properties returned by the SPListEvent object, you will notice that it does not have a property to return the document that caused the event to fire. In workflow applications, however, you will almost always manipulate the document in response to an event. Retrieving a reference to the document itself is actually accomplished through the SPWeb object in conjunction with the SPListEvent object. The following code shows how to return a reference to the document that caused the event to fire.

 Dim objSite As SPWeb = listEvent.Site.OpenWeb Dim objFile As SPFile = objSite.GetFile(listEvent.UrlAfter) 

Accessing Document Properties

Once you have retrieved a reference to the SPFile object, you can use it to access a multitude of properties for the target document. These properties may subsequently be the target of changes generated by an event-handling class. You may choose, for example, to change the Approval Status property based on some user action.

File properties come in three main categories that are each accessed in a different way. Some document properties like Name , Author , and Title are accessible directly as properties of the SPFile object. Other properties that represent document metadata are available only through a Hashtable object. Still other properties, such as Approval Status, are available only by accessing the SPListItem object that contains the file data in the library list. Accessing the properties that are available directly from the SPFile object is simple. The properties are available immediately upon retrieving a reference to the target document. The other categories of properties, however, take a little more effort.

The Properties collection of the SPFile object contains a set of key-value pairs that represent document metadata. Most of the metadata is of limited use, but you can access the values of custom columns in the document library using this collection. In order to access this set of properties, you must use a Hashtable object. Listing 9-3 shows the code required to print out the metadata values to a file.

Listing 9-3: Writing Out Metadata Values
start example
 objWriter = New StreamWriter("c:\events.txt", False) 'Get document associated with this event Dim objSite As SPWeb = listEvent.Site.OpenWeb Dim objFile As SPFile = objSite.GetFile(listEvent.UrlAfter) 'List the metadata Dim objHashTable As System.Collections.Hashtable = objFile.Properties Dim objKeys As System.Collections.ICollection = objHashTable.Keys Dim objKey As Object For Each objKey In objKeys     objWriter.WriteLine(objKey.ToString & ": " & _         objFile.Properties(objKey.ToString).ToString) Next 
end example
 

Metadata properties contain many values associated with the document as it relates to the web site along with any custom columns you have defined in the library. Although you are focused on using the SPFile object for documents in libraries, this metadata can also be retrieved for web pages on a site. Listing 9-4 shows a typical set of key-value pairs for a Microsoft Word document stored in a document library. Take special note of the Status property, which is a custom property defined just for this particular document library.

Listing 9-4: Typical Metadata Values for a Word Document
start example
 vti_categories: vti_author: SPS\administrator Status: Editor Reviewed vti_modifiedby: SPS\administrator vti_nexttolasttimemodified: 11/1/2003 7:27:18 AM vti_filesize: 20480 vti_approvallevel: vti_cachedtitle: vti_timelastmodified: 11/1/2003 8:52:10 AM vti_title: vti_docstoreversion: 2 vti_sourcecontrolcookie: fp_internal vti_sourcecontrolversion: V2 vti_timecreated: 11/1/2003 7:27:18 AM vti_cachedcustomprops: vti_approvallevel vti_categories vti_assignedto vti_title Status vti_assignedto: vti_docstoretype: 0 
end example
 

Some of the document properties that are of value to us in designing workflow can only be accessed through the SPListItem object that contains the document. The SPListItem class represents a single row in the document library. Using this object, you can access the values of all of the columns in the document library. Listing 9-5 shows how to write these values out to a file.

Listing 9-5: Accessing SPListItem Fields
start example
 Dim objListItem As SPListItem = objFile.Item Dim objFields As SPFieldCollection = objListItem.Fields Dim objField As SPField For Each objField In objFields     objWriter.WriteLine(objField.Title & ": " & _        objListItem.Item(objField.Title).ToString) Next 
end example
 

Probably the most significant field in the SPListItem object is the Approval Status field. This field can have a value of 0, 1, or 2 to represent status values of Approved, Rejected, or Pending respectively. This field will be the foundation of many workflow processes that rely upon document approval by multiple people in an organization. Along with this field you can access several other valuable properties including the same custom fields that we accessed using the Hashtable approach. Listing 9-6 shows a typical set of properties and values retrieved from an SPListItem object. Take special note of the Approval Status property and the custom Status property.

Listing 9-6: Typical SPListItem Fields and Values
start example
 ID: 9 Created Date: 11/1/2003 2:27:17 AM Created By: 1;#SPS\administrator Last Modified: 11/1/2003 3:52:09 AM Modified By: 1;#SPS\administrator Approval Status: 0 URL Path: /sites/showroom/Events Library/Doc3.doc URL Dir Name: 9;#sites/showroom/Events Library Modified: 11/1/2003 3:52:09 AM Created: 11/1/2003 2:27:17 AM File Size: 20480 File System Object Type: 0 ID of the User who has the item Checked Out: 9;# Name: Doc3.doc Virus Status: 9;#20480 Checked Out To: 9;# Checked Out To: 9;# Document Modified By: SPS\administrator Document Created By: SPS\administrator owshiddenversion: 2 File Type: doc Name: Doc3.doc Name: Doc3.doc Select: 9 Select: 9 Edit: Type: doc Server Relative URL: /sites/showroom/Events Library/Doc3.doc Encoded Absolute URL: http://spsportal/sites/showroom/Events%20Library/Doc3.doc Name: Doc3.doc File Size: 20480 Order: 900 Status: Editor Reviewed 
end example
 

Beyond reading and writing values, accessing document properties in a workflow application is significant because it allows your event handler to respond to situations that go beyond the events defined by the SPListEventType object. The SharePoint Services event model allows you to trap most user actions directly; events such as document deletion are unambiguous and you can typically respond to them directly. However, when an SPListEventType.Update event is trapped, you cannot immediately determine what caused the event. This is because the SPListEventType.Update event can occur when the body of a document is changed, its approval status is changed, or its property profile is changed. The only way to determine the exact cause of the event is to examine properties of the document causing the event.

Acting on Documents

Once you have determined that an event of interest has occurred, you will want to take action on the target document. In most cases, this simply means moving or copying the document to another library. For example, when your handler receives the SPListEventType.Update event, you may check the Approval Status of the document. If this value is 0 (Approved), you may then move it to a library where it would await the next level of review and approval. This technique of using libraries as review and approval queues works well for automating workflow. Interested parties can simply set up alerts against the libraries of interest and await notification that a document has reached their particular review stage in the workflow. Listing 9-7 shows a simple example of using the MoveTo method to move a document based on its approval status.

Listing 9-7: Moving Documents
start example
 If listEvent.Type = SPListEventType.Update Then     Dim objSite As SPWeb = listEvent.Site.OpenWeb     Dim objFile As SPFile = objSite.GetFile(listEvent.UrlAfter)     Select Case objFile.Item.Item("Approval Status")         Case 0 'Approved             objFile.MoveTo("http://spsportal/sites/showroom/Approved/" & _                 objFile.Name, False)         Case 1 'Reject             objFile.MoveTo("http://spsportal/sites/showroom/Rejected/" & _                 objFile.Name, False)         Case 2 'Pending             objFile.MoveTo("http://spsportal/sites/showroom/Pending/" & _                 objFile.Name, False)     End Select End If 
end example
 

Along with moving documents, the SPFile object also supports copying, deleting, and check in/out functions. Using these methods , you can build simple workflows that support business processes within the organization.




Microsoft SharePoint[c] Building Office 2003 Solutions
Microsoft SharePoint[c] Building Office 2003 Solutions
ISBN: 1590593383
EAN: N/A
Year: 2006
Pages: 92

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