Satalyst Brilliance on 01 Dec 2014

Creating a list workflow for SharePoint Online 2013 using Visual Studio

A few months ago, we migrated from SharePoint 2010 on premise to SharePoint Online 2013 – a huge paradigm shift for us and our custom workflows. If you’re reading this blog you’ve probably noticed that documentation for SharePoint Online workflows is hard to come by, especially using Visual Studio rather than SharePoint Designer. So I’ll share my experiences and hope it helps.

Calling RESTful Services

The first pain point that I encountered was migrating to declarative workflow and losing code-behind functionality. All custom work must be done in a RESTful service, the response comes back as JSON, and must be parsed out of the new dynamic value type. The syntax is quite verbose:

Call Restful Service

I assign a string variable ServiceCall to the endpoint plus the method, like so: ServiceCall = “http://satalyst.com/services/MyService.svc/SomeRESTfulMethod”

Whether or not your method is returning a value, it should be tagged in the service interface with the WebGet attribute. Then I execute an HttpSend activity. The ResponseContent must be a variable of the new DynamicValue type.

Finally, I parse the dynamic value response. In this case, the response JSON looks like this:
{"IsCubeProcessingResult":{"Status":"COMPLETE"}}

 

 

 

 

 

So parsing the response using the GetDynamicValueProperties activity looks like this:
Dynamic value properties

Using the BuildDictionary activity

I couldn’t find any examples or documentation on how to use the BuildDictionary activity. I have a configuration table in my database and I wanted to load up the key/value pairs into a dictionary for later use. I kept getting this error:

Cannot implicitly convert type ‘System.Collections.Generic.IDictionary<string,string>’ to ‘System.Collections.Generic.Dictionary<string,string>’. An explicit conversion exists (are you missing a cast?)

Finally, I figured it out:
Build Dictionary activity

My variable, ConfigurationDictionary, had to be defined in the variables section as an IDictionary, not Dictionary. Probably pretty obvious in retrospect, but it never occurred to me to define a variable with anything but the concrete type. Loading the dictionary at least was relatively easy:

Parsing the dictionary

 

As you can see, I had to assemble the JSON PropertyName based on the index of the returned values. What I really wanted to do is pull back the entire data set and then parse the dynamic value into variables for later use, for example set up an EmailContact variable and populate it somehow. The JSON returned from my restful service looks like this:

{"GetConfigurationDataResult":
[
    {"ID":1,"name":"EmailContact","value":"me@satalyst.com"},
    {"ID":2,"name":"NetworkShare","value":"\\\\MyNetworkShare\\MYOBFolder\\"},
    {"ID":3,"name":"DataFileFolder","value":"MYOB"},
    {"ID":4,"name":"DataFileName","value":"CompanyMyobFile.MYO"}
]
}

 


Using the DynamicValue Evaluator solution, I tried many variations on this:

GetConfigurationDataResult/[name=EmailContact]

I was never able to get this to work. I kept getting this error:

System.InvalidOperationException: Looking up a value using a key is not supported on an instance of ‘Microsoft.Activities.Dynamic.DynamicArray’.

To date I haven’t found any examples of anyone doing any parsing like I wanted, and the error leads me to believe that it’s just not supported for SP 2013 workflows at the moment.

Claims-based Authentication

My workflow has the requirement to copy a file from SharePoint Online to a network location. Since this must be done in a RESTful service, this entails setting up claims-based authentication. Luckily, Wictor Wilen has already written a really excellent blog post on how to do Active authentication in SharePointOnline which still works for SharePoint Online 2013. I just followed his steps, then used his MSOnlineClaimsHelper in my RESTful service method like so:

internal bool DownloadSharepointFile(string sharepointOnlineUrl, string userId, string password, 
                                     string fileFolder, string fileName, string fileDestination)
{
   bool success = false;
   try
   {
      MsOnlineClaimsHelper loginHelper = new MsOnlineClaimsHelper(sharepointOnlineUrl, userId, password);

      using (ClientContext context = new ClientContext(sharepointOnlineUrl))
      {
         context.ExecutingWebRequest += loginHelper.clientContext_ExecutingWebRequest;

         List targetList = context.Web.Lists.GetByTitle(fileFolder);
         context.Load(targetList, lst => lst.RootFolder);
         context.ExecuteQuery();

         string fileToDownload = targetList.RootFolder.ServerRelativeUrl + "/" + fileName;
         FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, fileToDownload);

         using (Stream reader = fileInfo.Stream)
         {
            using (var fs = new FileStream(fileDestination, FileMode.OpenOrCreate))
            {
               reader.CopyTo(fs);
            }
         }

         success = true;
      }

   }
   catch (Exception ex)
   {
      throw new FaultException(new FileDownloadFault { errorMessage = ex.Message });
   }

   return success;
}

 

 

Deployment

In SharePoint Online 2013, your workflow must be a SharePoint App, and it must be deployed through the app catalog. You can still create a wsp and upload it and activate the feature, but your workflow will not be included in the wsp package, and I couldn’t find any way to force it to be included. Once I accepted this, publishing was actually pretty easy.

Prerequisites

I had been developing against a development template site, so I set up a team site to practice my deployment. I also had to request access to our internal company app catalog.

Publish and Deploy

Right-click on the SharePoint App Project in Visual Studio and select “Publish”. Navigate to your app catalog and select “Apps for SharePoint”, then “new app”.
Apps for Sharepoint

Update your details on the dialog, then click Save. Your app is enabled by default. To install your app, navigate to the team site where you want it. Go to Site Contents and select “add an app”. Your app should now be visible. Click it to install. When prompted about trusting your app, click “trust it” (unless you’ve written something that’s not trustworthy). Once your app is installed, it’s no longer available in the list of apps that you can install. To upgrade to a new version of your app, navigate to Site Contents, hover over your app, and click the ellipsis (…) that comes up.

 

upgradeApp4
Select “ABOUT”. If you’ve published a new version of the app, your screen will look like this. Simply click “Get it” to upgrade. Otherwise, although you have published a new version, the old version will continue to run.
Thanks for reading
Leah

Categories:
Tags: