2014-08-26

Error occurred in deployment step ‘Activate Features': System.TimeoutException: The HTTP request has timed out after 20000 milliseconds.

I am running SP 2013 dev environment and I recently ran into a problem described in the post title. I tried to deploy a solution with feature activation which included SP 2013 Workflow SPIs. I tried to solve the issue by applying a solution described here but it wasn't helpful in my situation. I already had registry settings set up to extend timeout period for SharePoint deployment.

Visual studio output window might look like this:
  Activating feature 'Feature1' ...
Error occurred in deployment step 'Activate Features': System.TimeoutException: The HTTP request has timed out after 20000 milliseconds. ---> System.Net.WebException: The request was aborted: The request was canceled.
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at Microsoft.Workflow.Client.HttpGetResponseAsyncResult`1.OnGotResponse(IAsyncResult result)
   --- End of inner exception stack trace ---
   at Microsoft.Workflow.Common.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at Microsoft.Workflow.Client.Ht


I noticed that I had Fiddler2 running in the background while trying to deploy my solution. I exited Fiddler2 application and tried to deploy again. This time deploy was successful. It very well might be a cause of error. Just to be sure I tried to reproduce the same behavior again by starting Fiddler2 again and trying to deploy the wsp using Visual Studio 2012. This time VS couldn't delete workflows and workflow associations from the site but it was able to deploy successfully. I turned off Fiddler2 again and tried to deploy, and it went smooth, without any errors. I might be wrong but it seems to me that Fiddler's proxy is interfering with deployment of workflows.

I know there are many reasons causing this error but this solution helped me. Hopefully it helps someone else.

2014-08-20

Implementation of ribbon button availability by calling asynchronous methods

It is known that SharePoint ribbon can be extended by implementing CustomAction Ribbon.Library.Actions.AddAButton. SharePoint allows you to dynamically control whether this ribbon button should be enabled. This is done by implementing Javascript logic in CommandUIHandler's EnabledScript attribute.

The problem is if you want to include asynchronous call in aforementioned attribute because this Javascript block must return boolean value. So, when SharePoint calls asynchronous method it will not get the result immediately. Instead, it will get the result of async call in callback function but it's too late, Javascript block has already returned.

The solution to this problem was very well described by Andrew Connell on his blog post. Since no code snippets were included in this post I decided to provide it here because there is one caveat that is not so obvious from first look at the Andrew's post.

This is the implementation of ribbon button in Elements.xml:

    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition
          Location="Ribbon.Library.Share.Controls._children">
          <Button Id="Ribbon.Library.Share.NewRibbonButton"
                  Command="NewRibbonButtonCommand"
                  Image16by16="/_layouts/15/Style/buttonIcon16.png"
                  Image32by32="/_layouts/15/Style/buttonIcon32.png"
                  LabelText="New case"
                  ToolTipTitle="Get new case."
                  ToolTipDescription="Assigns new case to you."
                  TemplateAlias="o2" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler
          Command="NewRibbonButtonCommand"
          EnabledScript="javascript:IsCurrentUserMemberOfGroup('puk ref');       
       "/>
      </CommandUIHandlers>
    </CommandUIExtension>

Since our project doesn't include customized forms nor master pages we had to include external Javascript file to Elements.xml:

  <CustomAction
   ScriptSrc="/_layouts/15/Scripts/SPRibbonHelperScript.js"
   Location="ScriptLink"
   Sequence="1001">
  </CustomAction>

This makes it easier to debug the solution if Javascript code is included in external file. Prerequisite for this step is to add new Javascript file to layouts mapped folder.

Next piece of code is the actual implementation of enabling/disabling the button based on current user's group membership in SPRibbonHelperScript.js:

var isMemberOfGroup = false;

function IsCurrentUserMemberOfGroup(groupName) {
    var currentContext = new SP.ClientContext.get_current();
    var currentWeb = currentContext.get_web();
    var currentUser = currentContext.get_web().get_currentUser();
    currentContext.load(currentUser);

    var allGroups = currentWeb.get_siteGroups();
    currentContext.load(allGroups);

    var group = allGroups.getByName(groupName);
    currentContext.load(group);

    var groupUsers = group.get_users();
    currentContext.load(groupUsers);
    currentContext.executeQueryAsync(OnSuccess, OnFailure);

    function OnSuccess(sender, args) {
        var userInGroup = false;
        var groupUserEnumerator = groupUsers.getEnumerator();
        while (groupUserEnumerator.moveNext()) {
            var groupUser = groupUserEnumerator.get_current();
            if (groupUser.get_id() == currentUser.get_id()) {
                userInGroup = true;
                break;
            }
        }

        if (isMemberOfGroup == false || isMemberOfGroup == 'undefined') {
            if (userInGroup == true) {
                isMemberOfGroup = userInGroup;
                RefreshCommandUI();
            }
        }
    }

    function OnFailure(sender, args) {
    }

    return isMemberOfGroup;
}