1

I have a site workflow on my Apps hostweb that I would like to call from within the app.

The issue I am facing is that while I can successfully query the WorkflowServicesManager, find the specific workflow subscription and initiate a startWorkflow - I am getting a NullReferenceException within the ULS logs.

My suspicion is that this has something to do with the App context not sending the correct information to the WorkflowServicesManager

var ctx = new SP.ClientContext(appweburl);
var appContextSite = new SP.AppContextSite(ctx, hostweburl);
ctx.load(appContextSite.get_web());

var wfServiceManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, appContextSite.get_web());
var wfSubService = wfServiceManager.getWorkflowSubscriptionService();
var wfSubs = wfSubService.enumerateSubscriptions();
var wfParams = new Object();
wfParams['personName'] = "Thomas";
var wfSub = null;
ctx.executeQueryAsync(function () {

  wfSubEnum = wfSubs.getEnumerator();
  while (wfSubEnum.moveNext()){ if(wfSubEnum.get_current().get_name() == "PersonWorkflow"){} wfSub = wfSubEnum.get_current(); }

  wfServiceManager.getWorkflowInstanceService().startWorkflow(wfSub, wfParams );
  ctx.executeQueryAsync(function () {

  })

})

The same code (with just Client context) on the hostweb works fine. Using wireshark I can see that the App sending an extra contructor in the XML during POST - but I am still thinking this is something to do with the appweb contexts or maybe the User Profile Service/WorkFlow manager not handling the App "user".

A similar post here going into quite alot of depth but the resolution does seem to be what I have already been doing. I don't think I am doing anything wrong in that regard.

Is it possible to call a hostweb site workflow from within a sharepoint App?

Update.

It seems as though my problem was with enumerateSubscriptions() I wanted to enumerate them to get the workflow based on its name, but get_current() does not return an object that startWorkflow can use.

the following code now works

var ctx = new SP.ClientContext.get_current();
var hostCtx = new SP.AppContextSite(ctx, hostweburl);

var wfServiceManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, hostCtx.get_web());
var wfSubService = wfServiceManager.getWorkflowSubscriptionService();
var wfSubs = wfSubService.enumerateSubscriptions();
var wfSub = null;
var wfParams = new Object();
wfParams['personName'] = "thomas";

ctx.load(wfSubs);
ctx.executeQueryAsync(
  function () {
   var wfSubEnum = wfSubs.getEnumerator();
   while (wfSubEnum.moveNext()){ if(wfSubEnum.get_current().get_name() == "PersonWorkflow"){ wfSub = wfSubService.getSubscription(wfSubEnum.get_current().get_id()) }  };
   wfServiceManager.getWorkflowInstanceService().startWorkflow(wfSub, wfParams);
    ctx.executeQueryAsync(function() {});
  }
);
0

This is what I use to start workflows on the host web.

var startWorkflow = function(subId, itemId) {
    var d = $.Deferred(),
        ctx = new SP.ClientContext.get_current(),
        hostCtx = new SP.AppContextSite(ctx, this.hostUrl),
        wfServiceManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, hostCtx.get_web()),
        wfSubService = wfServiceManager.getWorkflowSubscriptionService();
    ctx.load(wfSubService);

    ctx.executeQueryAsync(function() {
        var wfSubscription = wfSubService.getSubscription(subId);
        wfServiceManager.getWorkflowInstanceService().startWorkflowOnListItem(wfSubscription, itemId, new Object());

        ctx.executeQueryAsync(function() {
            console.log("Workflow started.");
            d.resolve();
        }, function(sender, args) {
            console.error("Failed to start the workflow. " + args.get_message());
            d.reject();
        });
    }, function(sender, args) {
        console.error("Failed to start the workflow. " + args.get_message());
        d.reject();args.get_message());
    });
    return d.promise();
};

The key difference being I pass in the subscription id of the workflow I need to start.

| improve this answer | |
  • Thank you for the reply. It seems as though my problem was with wfSub = wfSubEnum.get_current();. As far as I was concerned the current enumerated subscription object was the same as the object returned from wfSubService.getSubscription("id"). I was wrong. As I still wish to use the name, I have modified the code to the following working line. wfSub = wfSubService.getSubscription(wfSubEnum.get_current().get_id()). – greensmith Jul 6 '16 at 10:22
  • I'm surprised they don't expose a method to retrieve by name as well as id. And I just realized that you were calling the execute query method twice as well. Glad you got it working. – wjervis Jul 6 '16 at 12:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.