Walkthrough: Use SharePoint Full-Trust Workflow Activities with Business Connectivity Services
This walkthrough topic shows how to create a full-trust activity for a workflow that uses Microsoft Business Connectivity Services (BCS). It addresses a basic expense approval scenario that uses a workflow to get the approver and safe limit values from the external system by using Business Connectivity Services. These values correspond to the given employee, specified by an employee ID, and expense type.
Applies to: SharePoint Server 2010
This walkthrough topic is based on the BCS Full-Trust Workflow Activity sample, which is part of the Microsoft SharePoint 2010 Software Development Kit (SDK). For more information about how to get this sample, see Code Sample: BCS Full-Trust Workflow Activity Sample.
Full-trust activities are written in Microsoft Visual Studio and require the following:
Installation in the global assembly cache.
An .actions file placed in the workflow template folder in the file system of each server in the farm.
An AuthorizedTypes entry included in the web.config file on each server to allow the assembly to execute. These have to be deployed on every farm server, and therefore require much higher permissions and scrutiny.
Tips on BCS Action Usage and Common Mistakes
Use full-trust workflow activities for Business Connectivity Services in the following cases:
You have permission to deploy full-trust activities.
You want to do any of the following:
Read, create, and update data in an external system from a workflow with or without having an external list already provisioned.
Make as few calls to the external system as possible.
Use complex logic that requires looping over multiple items or associations to other external content types without using the Sandboxed Code Service.
When using full-trust workflow activities, be aware of the following:
Full-trust activities, as their name implies, run in full trust. This means that you should know exactly what the activity does and trust the author of the activity as though that author were an administrator before you deploy the activity.
If you are using this activity in Microsoft SharePoint Designer, you must return a fixed number of items as SharePoint Designer does not support looping.
Building the Full Trust Workflow Activity
The activity you will build in this how-to returns the approver and a safe limit for a given type of expense and employee ID. Information about the external content type is already built into the activity, and the activity will work only on that external content type.
Creating the Workflow Activity
This walkthrough accomplishes the same scenario as the one in How to: Creating Sandboxed Workflow Actions. However, here you are not working with an external list; you achieve the goals of the scenario solely by using the Business Data Connectivity (BDC) service APIs. This is slightly more complex than just reading an item in a list, because the BDC APIs offer much more flexibility than a flat list. Before looking at the code, you should understand the properties that are exposed by this activity. Although all of the activity's properties are exposed so that they can be edited in SharePoint Designer, some defaults are built in so that you do not have to enter the information for those that should be consistent across deployments.
Table 1. Sample workflow activity properties
The name of the external content type. You will hardcode this value in the sample as a default value, but you can override this value in the Properties grid. In a production environment, you might not want to allow EntityName, EntityNamespace, and LobSystemIsntanceName to be passed in to the activity at all. This is because any user of SharePoint Designer could then change the workflow to point to a different external content type and possibly get information he or she should not. These properties are here mostly so you can easily see how the code works.
The namespace of the external content type. You will hardcode this in the sample as a default value, but you can override this value in the Properties grid.
The external system's instance name. All of the instance names in SharePoint Designer are the names you type in when discovering the external system. However, external content types created outside of SharePoint Designer can have multiple names, which is why you need to specify one. You will hardcode this in the sample as a default value, but you can override this value in the Properties grid.
The employee ID that will be looked up.
The category of expenses. The implementation in the sample supports Morale, Equipment, and Travel as the only valid inputs for this parameter.
This is returned to the user from the external system. It is the user who should approve the expense.
This is returned to the user from the external system. It is the limit for that particular user, and for that type of expense.
To understand what this sample does, look at the activity code in BDCReadActivity.cs. Notice that all of the code is contained in the Execute method, which is what the workflow host calls to execute the activity. In this call, the first BDC action to do is to get the Metadata Store that contains the SafeLimits external content type, as shown in the following code.
private IMetadataCatalog GetMetadataCatalog(SPSite site, ISharePointService hostInterface)
The code might look simple but there are a few things to be aware of. First, the catalog is farm-scoped, not site-scoped. This means that this activity will work on any site that is using the same BDC service. Second, the SharePoint APIs used to get the Metadata Store will return null if the item is not found. This is different from the BDC APIs, which will throw exceptions if items are not found.
Now that we have the Metadata Store, you have to find the external content type and return the correct data, as shown in the following method example.
private void GetSafeLimits(IMetadataCatalog catalog, ISharePointService hostInterface)
Notice in the code sample that GetEntity is in a try/catch block, so that if the external content type was deleted, or was not in this catalog, a MetadataObjectNotFoundException exception would be thrown. To handle this exception, you add an entry into the workflow history list to inform you of the exception, and then re-throw the exception, which would allow the workflow to fail.
After you have an external content type, you must find a specific instance of that external content type. To do this, use the FindSpecific method of IEntity. This method takes two parameters. The first parameter is the Identity of the specific instance. In this example, EmployeeID was set as the identifier, so we need to pass the EmployeeID as the Identity. You can see at this point how the identity is specific to the external content type. Another external content type might have a different identifier with a different name and even a different type. The second parameter is the external system instance that we use to find the item. As stated before, because you are using SharePoint Designer, there is only one external system instance, and you use the name that is stored in the code for that. You should also notice that FindSpecific will throw a different exception if the item is not found: ObjectNotFoundException. Again, you want to catch this exception and return a friendly error to the user before re-throwing the exception so the workflow can fail. After you have the entity instance, the remaining work is simple. You can use the field names in the square brackets to get the values of the instance.
The following are steps to create a workflow based on the BCS Full-Trust Workflow Activity sample.
To set up the sample
Follow the steps in Code Sample: BCS Full-Trust Workflow Activity Sample to download and install the BCS Full-Trust Workflow Activity sample.
In SharePoint Designer, create an external content type named SafeLimits, with a namespace BCSBlog, and an external system instance named SafeLimit. Notice that these values are hardcoded in the sample activity code. Also, ensure the external content type has the following seven fields: EmployeeID, EquipmentLimit, EquipmentApprover, MoraleLimit, MoraleApprover, TravelLimit, and TravelApprover.
You must set up an external system, such as a database, with a data structure that contains the fields listed here.
(Optional) To verify the external content type, you can create an external list.
Open the solution in Visual Studio 2010.
Build the solution.
This results in BCSReadActivity.dll which is deployed on the front-end web server's global assembly cache (%windir%\assembly) so that SharePoint Server can find and load the activity.
Before you build the solution, ensure the defaults for EntityName, EntityNamespace, and LobSystemInstanceName are updated to match your setting. These are defined in the GetSafeLimits method.
Deploy the solution.
Add the assembly to the web.config file on each SharePoint farm server.
Open the web.config file of your SharePoint site on the farm server.
In the bottom section, look for <System.Workflow.ComponentModel.WorkflowCompiler>. Inside this tag, you should find an <authorizedTypes> section and an entry for each set of types. Add the following line (ensure that the type information is correct, including the public key token).
<authorizedType Assembly="BCSReadActivity, Version=126.96.36.199, Culture=neutral, PublicKeyToken=90f597110ccda6ac" Namespace="Microsoft.SharePoint.Samples" TypeName="SafeLimitActivity" Authorized="True" />
Deploy the BCSReadActivity.ACTIONS file on each SharePoint farm server.
On each farm server, copy BCSReadActivity.ACTIONS to the following folder in the SharePoint server install folder: %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\template\1033\workflow.
1033 is the LCID for the English-US locale. If you are using another locale, this folder name will be different.
Perform an iisreset command on each farm server.
To create the workflow
Create a document library for expense reports and name it ExpenseReports.
Add the following columns:
ExpenseType as a choice field with the following choices: Morale, Equipment, Travel
In SharePoint Designer, in the ExpenseReports document library, click New List Workflow.
Name the workflow and provide a description, and then click OK.
At this point, you are working in the workflow designer, and you can start to add your actions.
Insert the Get Safe Limits for Employee action.
Leave the first two parameters as they are. These are the output variables from the function for Approver and SafeLimit.
For the third parameter, specify the Category. This is already defined on your list, so as before, pick the ExpenseType column by using the CurrentItem by using the function (fx) button.
For the last parameter, pick the EmployeeID column using the CurrentItem by using the function (fx) button.
You should now see a new list workflow as shown in Figure 1.
Figure 1. New List workflow in Microsoft SharePoint Designer
Add another action for writing the output variables from the function for Approver and SafeLimit.
Insert the Update List Item action.
Click the this list link.
Click Add, and then select Approver.
In the Lookup for Single Line of Text dialog box, click the fx button.
For Data Source, select Workflow: Variables and Parameters.
For Field from Source, select Variable: Approver.
Close the dialog box.
Repeat steps c through g to add the variable for SafeLimit.
Save the workflow and then publish it.
Before running the workflow, ensure that you have set up proper permissions in your BDC model for the external system and the external content type so that the workflow can access these resources. Also, it is recommended that you use the Secure Store Service as the authentication type for the BDC model. For more information about workflows in Business Connectivity Services, see How to: Use Business Connectivity Services with SharePoint Workflows.
To run the workflow
Populate your external system with data.
Create one item in the ExpenseReports document library. Ensure that the employee ID and expense type values that you added exist in the external system.
Trigger the workflow.
The Approver and SafeLimit values fields in the document library entry should be populated by the workflow with values from the external system.