Thursday, July 31, 2014

Get the display name of a value in person of group field from SharePoint 2013 "_api/web/lists" service

Let’s assume that we need to access a SharePoint list using built in web services. To do the task we can use a service like below.
http://sp13/sites/dev/_api/web/lists/getbytitle('Regions')/items 
What happen if we have a “Person or Group” column in the list? We would get a result like below.

image

As you can see we get only the User Id instead of other properties like login name or display name.
To get those properties, we just need to expand respective properties as shown below.
http://sp13/sites/dev/_api/web/lists/getbytitle('Regions')/items?$select=Area_x0020_General_x0020_Manager/Name,Area_x0020_General_x0020_Manager/Title&$expand=Area_x0020_General_x0020_Manager/Id
Following is the result I got, which is what I expected

image

Friday, July 25, 2014

Cross site collection data access via HTTP web service for a SharePoint 2013 designer workflow. Resolving Unauthorized exception

Recently I created a SharePoint 2013 approval workflow where I had to take approvers from a list located at a different SharePoint site collection.

In this example I have two site collections named Config and Project where I have created the workflow in the Project site collection using SharePoint Designer. In the Config site collection I have a list called Approvers where I store relevant information regarding approvers.

Following diagram shows the scenario I described.

image
To get relevant information from Config site collection, I will use SharePoint api web services. For an example I could use following service to return all items in that list.
http://sp13/Sites/config/_api/web/lists/getbytitle('Approvers')/items
Calling a HTTP web service through a SharePoint 2013 Designer based workflow is straight forward. I have explained that in this blog post.

Although I have followed the steps correctly, I was getting an “Unauthorized” exception all the time. I’ve given necessary permissions to the list and web application but still I was getting the same error.

Later I figured out that we need to provide permissions to the workflow explicitly if we need to access resources beyond the current site. Following are the steps I followed to configure permissions to the workflow

1. Activate “Workflows can use app permissions” site feature in the site where I create the workflow (http://sp13/Sites/project )
image
2. Navigate to Site Settings –> Site app permissions where you can see an item called workflow
image
3. Copy the client section of the App Identifier as shown below
image
4.Navigate to <site url>/_layouts/15/appinv.aspx to configure permissions. Then add the client section of the App Identifier in the App Id section and click Lookup to populate content.
image
5. Then we need to specify App’s Permission Request XML
<AppPermissionRequests>
    <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
Since we are accessing beyond the current site collection, we will use “http://sharepoint/content/tenant” as the scope. More information on app permission and available scopes can be found on this article.

6. Finally we will trust the workflow
image
This will allow our workflow to access resources beyond the current site collection.

Monday, July 14, 2014

SharePoint 2013 Workflow-Check if required documents are available inside a Document Set prior to the approval process

We can use SharePoint Designer workflows to author an approval process. Sometimes the approval process can be complex where we need to create advanced workflows. In SharePoint 2013 workflows we can use HTTP web services and loops to assist such instances.

Recently I created an approval workflow to a library which stores document sets. Following is the pre-condition to the approval.

Each document set has two allowed content types named “Policy Document” and “Policy Checklist”. The approval process proceeds if the document set contain at least one document from each document set. Otherwise the approval process terminates.

Following are the questions we need to address

  • How can we access documents within a document?
  • How can we get the content type ID of each document?

We will call two web service methods to obtain relevant information and will use built in loop to assist the process. Following are the steps I used to answer above questions

1. Construct the server relative URL for document sets

Let’s assume our document set is located at “https://sp13/sites/dev/Shared Documents/DocumentSet1”. Below activity will remove “https://sp13/sites/dev/” component and assigns “Shared Documents/DocumentSet1” to a variable named “itemFolder

image

2. Prerequisites to call SharePoint REST API

As I mentioned earlier, SharePoint 2013 workflows can call RESTful services by default. In this case we will use services provided in “_api/web”. Since those services provide xml output we have convert them to JSON.

To do that we will create a dictionary. For both “Accept” and “Content-Type” variables provide “application/json;odata=verbose” as the value

image 

image

3. Call web service to get all items within the document set

To get items under a document set we will use GetFolderByServerRelativeUrl() method. Following is a sample service call

https://sp13/sites/dev/_api/web/GetFolderByServerRelativeUrl('Shared Documents/Set1')/Files

If you need further information on this method you can refer this blog post. To call the service using workflow we will use Call HTTP web service activity as shown below.

Following are the sub steps

A. When constructing  the url, we will use the sever relative path created in step 1

image

B. Create an empty dictionary variable named JSONResults

C. Edit properties of the activity to assign “Header” and “JSONResults” dictionaries to RequestHeaders and ReseponseContent parameters.

image

Finally the activity looks like below

image

Unfortunately this service doesn’t return Content Type ID property. As a result we will get a property from this service which can be input to our second service to obtain Content Type Id. We will call the second service in step 8.

4. Store results to a separate dictionary called allItems

image

5. Get count of items to start the loop

image

6. Store variable to hold content type IDs

image

7. Create a loop to iterate each item we have in allItems dictionary

Create an integer variable named index.

image

Then we will get the ServerRelativeUrl property from the item and assign it to variable serverRelativeUrl

image

8. Call the second web service to get content type id.

Since “GetFolderByServerRelativeUrl()/Files” method does not return the content type of items. As a result we need to execute another service to do so. We will use the ServerRelativeUrl property returned from step 7 as an input to the second service

This time we will call GetFileByServerRelativeUrl() method. Following is a sample of the service call.

https://sp13/sites/dev/_api/Web/GetFileByServerRelativeUrl('/sites/dev/Shared Documents/Set1/3.txt')/ListItemAllFields

If you need further information on this method you can refer this blog post as well.

As we did for the first method we will call HTTP web service activity as shown below

image

image

9. Get ContentTypeId property of the item

This service returns just a single item. So it is easy to get the value

image

10. Create Boolean variables to store content type availability 

Since we have two content types, we have two Boolean variables named “ct1IsAvailable” and “ct2IsAvailable”

image

11. Set Boolean value true if the content type was found

image

12. Specify Termination condition at the end of the loop

image

13. Conditionally allow or restrict the approval

image

14. Terminate the workflow

image

Summary

In the above article I explained how to use http web services available in “_api/web” within SharePoint 2013 workflows. A practical scenario was also explained where we need to check at least one document from each content type available in the document set.