Tags
Wednesday
Oct152014

Setting up Azure Service Bus for debugging SharePoint 2013 Workflows

If you follow the instructions on http://blogs.msdn.com/b/officeapps/archive/2013/03/21/update-to-debugging-sharepoint-2013-remote-events-using-visual-studio-2012.aspx to set up an Azure Service Bus to debug your SharePoint 2013 you need to take careful note of this starting paragraph.

Update 9/19/2014: Please note Microsoft Azure Service Bus now supports two types of connection strings: SAS and ACS. For remote event debugging via Azure Service Bus, only ACS connection string is currently supported as shown below. Follow the instructions in Service Bus Authentication and Authorization to get an ACS connection string for any new Service Bus namespace created after August 2014.

I skim read, so I missed it, twice.  And then spent a lot of time digging through why my brand new Azure Service Bus (SAS) doesn't work with SharePoint 2013's debugging.

To redeem myself and me ranting at other people (for my own fault of ... not-reading).  I present the following:

The newbie picture guide on how to set up Azure Service Bus for Office 365

 

Go here: http://azure.microsoft.com/en-us/downloads/

Scroll down and install the command line tools.  I went with the Windows PowerShell option on the left.

The download will run the Web Platform Installer, which then lets you install MS Azure PowerShell

image

 

Installed, it is here.

image

 

Run two PowerShell commands.

  • Add-AzureAccount will open a browser window, allowing you to sign in with your Office 365 account and download a policy file
  • New-AzureSBNamespace -name <name> -location '<region>' -CreateACSNamespace $true

 

image

 

The Service Bus can be managed via the web interface - they just can't be created.

It appears as type "Mixed"

image

 

Set Up VS.NET

This will now give you an old style ACS connection string that you can use in VS.NET's project properties.

image

 

And here is VS.NET happily debugging Office 365 workflow again.

image

 

For completeness: this is the Wrong Way, if you use the Azure Portal

image

 

Looks different.

image

 

ACS Connection String looks like this:

  • Endpoint=sb://debug-jl.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=<code>=

SAS Connection String looks like this:

  • Endpoint=sb://debug-bad.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=<code>=

 

The SAS Connection String does not currently work with VS.NET

 

 

Summary

 

  • Download Azure PowerShell (or Azure CLI via npm) - they are two different things, don't mix them.
  • Run two PowerShell commands to create the old Azure Service Bus (with ACS)
  • Thank Greg Hurlman@justcallme98 and ☞ Scott Hoag ☜@ciphertxt for reaching out and assisting me with my bad Azure skills.
  • Apologies to people that had to read my uneducated rant.  I retract all of it.
Tuesday
Oct142014

Small Powershell Adventures -NotIn and Arrays

 

PowerShell v3 has a new syntax I quite liked:

$badIDs = "73574929","73573581","73575402","73576325","73575586","73575377","73574920"

for($i = 0; $i -lt $rows.length; $i++) {

    $row = $rows[$i];
    #echo $row
    $imageID = $row.ImageID
    if ($imageID -ne "none" -and $imageID -NotIn $badIDs ) {
        # don't do stuff
    }
}

Trouble is, this isn't available natively in PowerShell v2 (which is still quite common if you work on SP2010, Windows Server 2008R2).

Fortunately, we can just use Array.IndexOf static method to replace this.

if ($imageID -ne "none" -and [Array]::IndexOf($badIDs, $imageID) -eq -1 ) {
    # don't do stuff
}

Tuesday
Sep302014

KO binding for two SharePoint rich text editor controls

 

For a while now, I've been experimenting with a simple HTML editor for my forms.  Something to work with JavaScript databinding, in my particular case, KnockoutJS.

 

Why not TinyMCE and CKEditor?

 

But both libraries wants me to embed a bunch of additional 10-20 files.  I'm trying to build an App, which means packaging my assets.  I'm not going to package 20 files. 

Additionally, both TinyMCE nor CKEditor has official support for KnockoutJS binding anyway.  You end up on StackOverflow using someone's binding code.

 

An idea strikes!

Why not just use SharePoint's Rich Text Editor controls?  As long as you can create an ASPX page, you can use these controls that are out of the box.  As long as I don't postback, it doesn't matter what's the value inside of the controls.

 

SharePoint InputFormTextBox

 

image

<sharepoint:InputFormTextBox title="Title" class="ms-input" data-bind="spInputFormTextBox: CommentText1" ID="CommentTextBox1" Runat="server" TextMode="MultiLine" Columns="40" Rows="5" RichText="True" RichTextMode="Compatible"/>

 

Knockout Two-Way Binding:

 

ko.bindingHandlers.spInputFormTextBox = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());

        var baseElementID = $(element).attr("id");
        $(element).val(value);
        RTE_TransferTextAreaContentsToIFrame(baseElementID);

        //handle edits made in the editor
        var doc = RTE_GetEditorDocument(baseElementID);
        if (doc == null) return;

        var $editor = $(doc.body);

        $editor.on('blur', function (e) {

            RTE_TransferIFrameContentsToTextArea(baseElementID);

            var $elemSave = $("#" + baseElementID + "_spSave");
            if ($elemSave.length) {
                modelValue($elemSave.val());
            }
            else {
                modelValue($(element).html());
            }
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, context) {
        //handle programmatic updates to the observable
        var value = ko.utils.unwrapObservable(valueAccessor());

        var baseElementID = $(element).attr("id");
        $(element).val(value);
        RTE_TransferTextAreaContentsToIFrame(baseElementID);
    }
};

 

Thoughts:

  • SharePoint:InputFormTextBox is a nice little control you can drop in anywhere.  It's been around for a long time too, since SharePoint 2007. 
  • RichTextMode="Compatible" mode creates a smaller rich text control with a tiny toolbar. 
  • Biggest problem, is this control is IE-only.  Does not render nicely on other browsers.
  • The KnockoutJS data-bind syntax is very clean and can be used directly on the control.
  • Explanation: the Javascript focuses on borrowing the RTE_Transfer* functions in SharePoint to copy the value to a hidden field, then grab the HTML from there back to the observable.  This borrows SharePoint's other javascript function to clean up the HTML and do a bunch of encode/decode things.

 

SharePoint RichTextField

 

image

 

<div data-bind="spRichTextField: CommentText1">
<sharepoint:RichTextField CssClass="ms-input" ID="CommentTextBox1" Runat="server" FieldName="CommentText1" ControlMode="New"/>
</div>

KnockoutJS Two-Way Binding:

 

ko.bindingHandlers.spRichTextField = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());

        var $inplacerte = $(element).find("div.ms-rtestate-field.ms-rtefield div[id$=TextField_inplacerte]");
        $inplacerte.html(value);

        //handle edits made in the editor
        $inplacerte.on('blur', function (e) {
            var RTEhtml = RTE.Canvas.getEditableRegionHtml($inplacerte[0], false);

            modelValue(RTEhtml);
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, context) {
        //handle programmatic updates to the observable
        var value = ko.utils.unwrapObservable(valueAccessor());

        var $inplacerte = $(element).find("div.ms-rtestate-field.ms-rtefield div[id$=TextField_inplacerte]");
        $inplacerte.html(value);
    }
};

 

Thoughts:

  • The SharePoint Rich Text Field works on every browser, and it shows a nice Ribbon for interacting with rich text.
  • To use this, you do need to tie it to a Field on the current list item (which would be the page), this is quite annoying to set up.
  • I use data-bind to pull the value out and work with it via Javascript - so I don't actually bother with saving back to the list item via the UI.
  • You can't add the data-bind attribute to the RichTextField control.  It will complain about not knowing what the attribute is.  I work around this by wrapping the binding syntax outside of the ASP.NET control and use jQuery to look for the DOM elements within.
  • Explanation: This borrow SharePoint's RTE.Canvas javascript class to update and retrieve HTML from the Content-Editable DIV.  Again, SharePoint's Javascript does a bunch of encoding/decoding that makes the HTML nice to read at the end.
Tuesday
Sep162014

Demystifying SP2013 Workflow AppStep

 

A SharePoint 2013 workflow essentially can run as two different accounts.  The current user, or AppStep (which runs the action as the Workflow App account).

image

You will need to activate this feature.

But this is not where these notes end.

 

SP2013 AppStep is not the same as SP2010 Impersonation Step

 

In SP2010, when you use impersonation step, you gain additional activities, and because SP2010 doesn't have the concept of different permissions impersonations - essentially those activities lets you perform the action with elevated privileges in the code.

 

In SP2013, everything is an App.  That includes workflows.  So, when you activate this feature, you gain:

  • Ability to have App Step in your workflow designer (SharePoint Designer or Visual Studio .NET)
  • App Step runs the actions inside with App Permissions, and this is important: the App only has Read and Write.  It does not have full control or manage or any other fancy pants abilities.
  • When App Step updates the list item, you get a nice message on the list item that says Updated by Workflow on behalf of (user).

image

 

The power of HttpSend

 

You can of course call all the fancy new SP2013 REST API in your workflow.  http://msdn.microsoft.com/en-us/library/office/dn268594(v=office.15).aspx  - This gives your workflow a lot of power.  You can do this either as the current user or in the App account context.

image

 

Fabian and Chris has documented a number of really great articles on this.

Andrew Connell also has a great segment on Plural Sight on REST services.

 

There are ways to increase that permission level

 

If you are on-premises, there is a powershell command to grant the Workflow App account additional permissions.

Set-SPAppPrincipalPermission

 

If you are on Office 365, there is a hidden URL that lets you re-apply a permission mask to the Workflow Account.

/_layouts/15/appinv.aspx

 

Apps for SharePoint

Of course, the way Microsoft wants you to build workflows in the cloud would not be via a hidden URL.

The best way (but somewhat tricky at the moment, as tooling gets better this story will improve) is to build SP2013 workflows within an App for SharePoint.  The workflow is deployed in the App web, and has the same permissions that the user grants to the App web.  You can request additional permissions as you package your App and those will be available to the Workflow as well.

So this is fantastic for building self contained apps where lists, list definitions, javascript forms and SP2013 Workflows all tie together to form a small bit of functionality.

But having workflows in the App Web means that it can't be added to existing document libraries or lists or sites in the host web.  So there are a number of scenarios where Apps for SharePoint doesn't work that well.  I have been using SP2013's Sandbox Solutions for this purpose.  But Sandbox Solution Packages doesn't have its own App permissions (and thus you'll need to see the previous point about how to elevate that afterwards).

 

Integrated Workflow Apps

Microsoft has begun to talk about the new Integrated Workflow Apps in more detail.

The new syntax available for Integrated Workflow Apps will basically allow you to install workflow packaged as an App for SharePoint, but instead of deploying the Workflow to the App web, it will be deployed and made available on the Host Web. 

But tooling will need to improve in a future VS.NET update.  This is something I want to blog again later as more details are available.  But for now, there's a great link here.

There are a few pieces of the puzzle missing, and one may need to build additional javascript based UI to deploy assets (lists and workflow associations) to the host web.  But I'm loving the choices and I think SP2013 Workflows is moving in a fantastic direction.

Thursday
Sep112014

SP2013 Workflows and WSPublishState does not exist

Column 'WSPublishState' does not exist. It may have been deleted by another user.

This is a quick blog of something that troubled me for nearly an afternoon.

Scenario

  • SP2013 workflow
  • Packaged as Sandbox Solution with list definitions in Visual Studio

 

The errors happen during Feature activation.  Both from within Visual Studio's Deploy as well as via Site Settings - Activate Feature.  The feature activation fails because WSPublishState column doesn't exist.

 

Resolution

 

I fixed this by splitting the list definition and workflow definitions into different features.  This leads me to ponder if there is a conflict caused by the list, workflow and workflow association being created all within the same feature.

Saturday
Aug022014

TypeScript presentation (take 2) at SPSMEL

 

Earlier today I delivered possibly my best TypeScript session ever at SharePoint Saturday Melbourne.  The attendees were great, and I feel like I cracked jokes all the way through!

The secret, and this I think many attendees may not have realized, is that I started almost 10 minutes early.  So they went through 70 minutes of solid TypeScript wonderland with me.  I hope that extra time was good.

As I have actually done the rounds with TypeScript for a whole year.  I think this might be a good time to sunset this particular topic. 

Download Links

 

 

The Future of TypeScript

 

TypeScript, now that it has reached version 1, will never disappear:

There are some really big projects within Microsoft that is using TypeScript.  There is no alternative for them to switch to.

  • Dart - is not focused on building JavaScript.  Dart believes that JavaScript is broken fundamentally, and the only way to fix it is to introduce a new Virtual Machine.  Dart compiles down to JavaScript is almost a side-effect for adoption.  If Flash and Silverlight are bad for the web, what do you think people's reaction would be to Dart VM?
  • Coffee Script is great, and solves a genuine problem with JavaScript - that the language is too loose, and gives you too many ways to hang yourself.  Coffee Script's syntax, being so close to Ruby, will ensure a smooth path for them to work on Ruby and Coffee Script. 
    In the same vain that I feel a Ruby Developer should never use TypeScript - they should use CoffeeScript; a C#/.NET/Java/C++/JS developer should never use Coffee Script - they should learn the TypeScript syntax that's closer to what they already know, plus TypeScript will greatly help them learn, understand and write better Javascript.
  • ECMA Script v6 - is really the holy grail that will fix a lot of the odd JavaScript syntax (along with "option strict").  But ES6 does not include Type information.  What that means is that even with the eventual convergence of the Evergreen Browsers to ES6, TypeScript will still have a place as a superset to ES6.  The Type information is important for the tools to correctly check your code for you during design and compile time.

TypeScript sits in its own place.  It tries to give you "invisible railings" for your JavaScript. 

With TypeScript, you start with JavaScript, and you work within self imposed railings (which magically disappear when it's compiled back in JavaScript) so you get the benefit of a strong typed language to help you write code, but none of the performance penalties.

TypeScript enables teams to work together.  For projects that have hundreds of thousands of lines of JavaScript - there is no way back.

Remember: As your JavaScript codebase grow, it will become unmanageable and you will have code rot.  TypeScript is a great way to help you avoid that gruesome spaghetti situation. 

Tuesday
Jul222014

jQuery Promise syntax to wrap SharePoint SP.SOD

 

jQuery has a special function $.Deferred - which lets you create an Deferred object to build Promise(s).

We use this to simplify everything we do in SharePoint and other JavaScript libraries.

 

Wrapping SP.ClientContext

function GetCurrentUserName() {

var deferred = $.Deferred();
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var currentUser = web.get_currentUser();
ctx.load(currentUser);
ctx.executeQueryAsync( function(sender, args) {
    deferred.resolve();
}, function() {
    deferred.fail();
});

var promise = deferred.promise();
promise.done( function() {
    var title = currentUser.get_title();
});

return promise;
}

Wrapping SP.SOD

function SPLoaded() {

var deferred = $.Deferred();
SP.SOD.executeOrDelayUntilScriptLoaded( function() { deferred.resolve(); }, "sp.js");

return deferred.promise();

}

Resolving multiple promises

var promise1 = ...
var promise2 = ...
var promise3 = ...

$.when(promise1, promise2, promise3).done(function(){

// do something

});

 

Concatenating Arrays of promises

 

var promises = [];
promises.push(promise1);
promises.push(promise2);
...

// use this syntax when you don't know how many promises are there - may be calling REST in a loop.

return $.when.apply($, promises);

 

Combining Array of Promises and SP.SOD

 

function Ready() {

var promises = [];

var deferred1 = $.Deferred();
SP.SOD.executeOrDelayUntilScriptLoaded(deferred1.resolve, "sp.js");
promises.push(deferred1.promise());

var deferred2 = $.Deferred();
SP.SOD.executeOrDelayUntilScriptLoaded(deferred2.resolve, "sp.core.js");
promises.push(deferred2.promise());

 

return $.when.apply($, promises);

}

 

Combining promises

 

$(document).ready(function(){

    var vm = new ViewModel();  // not included in above script
    var promise = vm.Ready();
    promise.done( function() {
        vm.GetCurrentUserName();

    });

});

 

(Updated) And the grand finale

 

function Ready() {

var promises = [];

// using the special javascript argument "arguments"

$.each(arguments, function(index, arg) {
    var deferred = $.Deferred();
    SP.SOD.executeOrDelayUntilScriptLoaded(deferred.resolve, arg);
    promises.push(deferred.promise());
});

return $.when.apply($, promises);

}

 

$(document).ready(function(){

    var vm = new ViewModel();  // not included in above script
    var promise = vm.Ready("sp.js", "sp.core.js");
    promise.done( function() {
        vm.GetCurrentUserName();

    });

});

Tuesday
Jun172014

Nintex Workflow Inline Function to check if SPFile is locked

 

IsDocumentWritable

 

Nintex Workflow has a fairly useful function "IsDocumentWritable" that checks if the current item that the workflow is running on is writable.

There is a small problem, it only checks if the file is Checked Out (SPFile.CheckedOutType) and not if the file was locked, say by a Desktop Client Application.

 

Add Nintex Workflow Inline Function

We can add a simple Nintex Workflow inline function to get the behaviour we wanted:

I followed Vadim's excellent blog entry: http://www.vadimtabakman.com/nintex-workflow-developing-a-custom-inline-function.aspx

 

/*
* & 'C:\Program Files\Nintex\Nintex Workflow 2010\NWAdmin.exe' -o AddInlineFunction -functionalias "fn-IsFileLocked" -assembly "MY_DLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f7c41d4a6ea1fb3" -namespace "MYNamespace" -typename "MYInlineFunctions" -method "IsFileLocked" -description "Checks if file is locked." -usage "fn-IsFileLocked(itemPath)"
*/

public static bool IsFileLocked(string itemPath)
{
    bool result = false;
    try
    {
        SPSecurity.RunWithElevatedPrivileges(() =>
        {

            using (SPSite site = new SPSite(itemPath))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPFile file = web.GetFile(itemPath);
                    if (!file.Exists)
                    {
                        return;
                    }

                    // true if checked out

                    result = file.LockType != SPFile.SPLockType.None;
                    return;
                }
            }
        });
    }
    catch (Exception ex)
    {
    }
    return result;
}

 

You can call this method from within Nintex Workflow Designer.

image

Monday
Jun162014

Reading InfoPath template's default values in code

 

String xml = "";
FormTemplate template = this.Template;
using (Stream s = template.OpenFileFromPackage("template.xml"))
{
    XPathDocument reader = new XPathDocument(s);
    XPathNavigator nav = reader.CreateNavigator();
    XPathNavigator repeat = nav.SelectSingleNode("/my:myFields/my:Repeats/my:Repeat[1]", this.NamespaceManager);
    if (repeat == null)
    {
        return;
    }
    xml = tender.OuterXml;
}
if (!String.IsNullOrEmpty(xml))
{
    XPathNavigator destination = this.CreateNavigator().SelectSingleNode("/my:myFields/my:Repeats", this.NamespaceManager);
    destination.AppendChild(xml);
}

 

The top part of the code is particularly useful if you want to use the Default Values for repeating sections in InfoPath.  Your code will read the xml for the default values and insert them into the repeating section.  I've previously hardcoded these XML segments for insert, but that's extremely error prone when you inevitably update your XML template with new and more exciting child elements and attributes.

Monday
Jun022014

Wrap up: SharePoint Saturday Adelaide and Brisbane

 

There is always an relevant tweet.

Tomás Lázaro@tomzalt May 22 The book Javascript Ninja has a Samurai on the cover. That happens because JS is not strongly typed.

This is a Post-Event update post.

Adelaide

In Adelaide, I went at a good pace and gone through the TypeScript example, demos but had very little time remaining for discussions or questions.

The main feedback I got was perhaps there was too much time (still!) given to JavaScript and we can all spend more time in TypeScript and the demos.  Also, there was questions regarding deployment.

 

Brisbane

In Brisbane, I trimmed the JavaScript discussion but added a silly demo that got people laughing.  But possibly still ate my time.  I was not able to go through the sections on adding TypeScript to your existing JavaScript.  But I was able to cover the deployment scenarios for SharePoint 2010 and 2007.

 

Working with SP 2007

  • Editing:
    • Use Content Editor webpart and point to a HTML file, which then references a JavaScript file generated from TypeScript.
    • Use VS.NET 2012/2013 with WebDAV
  • Deploying:
    • Package as farm solution web part
    • Include map file to debug in IE12 / Chrome.

Working with SP 2010

  • Editing
    • You can use Content Editor as above
    • You can build VS.NET farm or sandbox solutions and use TypeScript directly
  • Deploying
    • Use Sandbox solution to deploy a sandbox webpart
    • Reference a JavaScript file generated from TypeScript
    • Package as sandbox solution

Deployment – SP 2013 / Office 365

  • Using App for SharePoint to deploy an App Part
  • Do not create code behind. Reference JavaScript file generated from TypeScript
  • Configure App permissions
  • Package as SharePoint “App”
  • When deploying – grant permissions to App

 

Download Links:

 

If you are using TypeScript in your environment, let me know and tell me how it is going for you.