Saturday, 31 May 2014

Web Development Tools & Reference

Just a list of tools and reference material which I think is really useful for Web Development:

JavaScript:


1) jslint : http://www.jslint.com/

JSLint is a JavaScript program that looks for problems in JavaScript programs. It is a code quality tool. JSLint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily a syntax error, although it often is. JSLint looks at some style conventions as well as structural problems. It does not prove that your program is correct. It just provides another set of eyes to help spot problems.

2) jsperf : http://jsperf.com/

jsPerf aims to provide an easy way to create and share test cases, comparing the performance of different JavaScript snippets by running benchmarks.

3) jsfiddle: http://jsfiddle.net/

Test and share JavaScript, CSS, HTML or CoffeeScript online.

4) JavaScript Garden : http://bonsaiden.github.com/JavaScript-Garden/

JavaScript Garden is a growing collection of documentation about the most quirky parts of the JavaScript programming language. It gives advice to avoid common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert JavaScript programmers may encounter on their endeavours into the depths of the language.

Tools





4) JSON Pretty Print: http://jsonprettyprint.com/

Reference:


1) Mozilla Developer Network : https://developer.mozilla.org/en-US/


Performance:


1) Browser Diet : http://browserdiet.com/

2) Yahoo Best Practices for Speeding up your WebSite: https://developer.yahoo.com/performance/rules.html

3) Google Web Development Best Practices: https://developers.google.com/speed/docs/best-practices/rules_intro?hl=sv

4) Why you should always host jQuery on the Google CDN: http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/

Using the SharePoint 2013 Workflow Interop Service in CSOM

In my previous post, I briefly introduced the SharePoint 2013 Workflow Architecture and also showed how to programmatically manage the SharePoint 2013 Workflows via the Workflow Services in the Client Site Object Model (CSOM). I will recommend to read that post before this one.

You can find the previous post here: Managing SharePoint 2013 Workflows with CSOM

As a follow up to that post, in this post I will show how to start a Workflow authored with the SharePoint 2010 Engine.

The Workflow Services in the CSOM contain an InteropService which is a hook in the SharePoint 2010 Windows Workflow Foundation runtime engine.

This code works with SharePoint 2013 On-Premises as well as with SharePoint Online. I have created my sample code against SharePoint Online.

Before you run this code, you will need to create a SharePoint 2010 Workflow (Definition) either via SharePoint Designer 2010/2013 or through Visual Studio 2012/2013 and deploy it to your SharePoint 2013 target site. You can then use this code to start the Workflow

You will need to reference the following Assemblies:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Microsoft.SharePoint.Client.WorkflowServices.dll

1) Start a SharePoint 2010 Site Workflow with CSOM:


using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Workflow;
using Microsoft.SharePoint.Client.WorkflowServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace CSOMWorkflow
{
class Program
{
static void Main(string[] args)
{
//Replace the following values according to your configuration.
//Site details
string siteUrl = "https://mytenant.sharepoint.com/sites/test";
string userName = "user@mytenant.onmicrosoft.com";
string password = "password";
//Name of the SharePoint 2010 Workflow to start.
string workflowName = "SP2010SiteWF";
using (ClientContext clientContext = new ClientContext(siteUrl))
{
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
//Workflow Services Manager which will handle all the workflow interaction.
WorkflowServicesManager wfServicesManager = new WorkflowServicesManager(clientContext, web);
//Will return all Workflow Associations which are running on the SharePoint 2010 Engine
WorkflowAssociationCollection wfAssociations = web.WorkflowAssociations;
//Get the required Workflow Association
WorkflowAssociation wfAssociation = wfAssociations.GetByName(workflowName);
clientContext.Load(wfAssociation);
clientContext.ExecuteQuery();
//Get the instance of the Interop Service which will be used to create an instance of the Workflow
InteropService workflowInteropService = wfServicesManager.GetWorkflowInteropService();
var initiationData = new Dictionary<string, object>();
//Start the Workflow
ClientResult<Guid> resultGuid = workflowInteropService.StartWorkflow(wfAssociation.Name, new Guid(), Guid.Empty, Guid.Empty, initiationData);
clientContext.ExecuteQuery();
}
}
}
}


2) Start a SharePoint 2010 List Workflow with CSOM:


using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Workflow;
using Microsoft.SharePoint.Client.WorkflowServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace CSOMWorkflow
{
class Program
{
static void Main(string[] args)
{
//Replace the following values according to your configuration.
//Site Details
string siteUrl = "https://mytenant.sharepoint.com/sites/test";
string userName = "user@mytenant.onmicrosoft.com";
string password = "password";
//Name of the SharePoint2010 List Workflow
string workflowName = "SP2010DocWF";
//Name of the List to which the Workflow is Associated
string targetListName = "Documents";
//Guid of the List to which the Workflow is Associated
Guid targetListGUID = new Guid("b89e266c-5f20-4b83-9f95-10a42c629e84");
//Guid of the ListItem on which to start the Workflow
Guid targetItemGUID = new Guid("6ab8227b-66a3-4e12-8055-846dcfb53cab");
using (ClientContext clientContext = new ClientContext(siteUrl))
{
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
//Workflow Services Manager which will handle all the workflow interaction.
WorkflowServicesManager wfServicesManager = new WorkflowServicesManager(clientContext, web);
//Will return all Workflow Associations which are running on the SharePoint 2010 Engine
WorkflowAssociationCollection wfAssociations = web.Lists.GetByTitle(targetListName).WorkflowAssociations;
//Get the required Workflow Association
WorkflowAssociation wfAssociation = wfAssociations.GetByName(workflowName);
clientContext.Load(wfAssociation);
clientContext.ExecuteQuery();
//Get the instance of the Interop Service which will be used to create an instance of the Workflow
InteropService workflowInteropService = wfServicesManager.GetWorkflowInteropService();
var initiationData = new Dictionary<string, object>();
//Start the Workflow
ClientResult<Guid> resultGuid = workflowInteropService.StartWorkflow(wfAssociation.Name, new Guid(), targetListGUID , targetItemGUID, initiationData);
clientContext.ExecuteQuery();
}
}
}
}

Managing SharePoint 2013 Workflows with CSOM

As you might have heard many times, the Workflow Architecture in SharePoint 2013 was entirely changed from what it was in SharePoint 2010. Instead of the Workflows running on the SharePoint server, they now have to run on a separate Workflow Manager.

On top of that, only declarative custom Workflow's are allowed to be deployed to the Workflow Manager. If there has to be any custom code, it has to be hosted in an external service and then consumed from the declarative workflow.

The Workflow Manager has certain activities and types which come predefined with it. This is called the Trusted Surface. Workflow Authors can consume these activities in their declarative workflows. A whole list of types and activities available under the trusted surface is here: http://msdn.microsoft.com/en-us/library/jj193509(v=azure.10).aspx and here: http://msdn.microsoft.com/en-us/library/jj193474(v=azure.10).aspx

This architecture is very much inline with Microsoft's strategy to move code execution away from the SharePoint server.

SharePoint 2013 supports two methods of workflow authoring. Authoring Workflows in the SharePoint 2013 engine and also authoring them in the SharePoint 2010 engine. Workflows which are authored in the SharePoint 2010 engine run on the SharePoint server and are allowed to execute code there. That architecture has not been changed and is available for backwards compatibility.

In the SharePoint 2013 Workflow platform, a Workflow definition is a Service Bus Topic and a Workflow Association is a Subscription to the topic. Topics and Subscriptions are used by the Service Bus to decouple message publishers from message subscribers. More about the Workflow Manager and Service Bus Pub/Sub architecture here: http://msdn.microsoft.com/en-us/library/office/jj163181(v=office.15).aspx#bkm_Subscriptions

Microsoft has also very recently added Workflow Management services to the Client Side Object Model (CSOM). The entire range of Workflow services available in the CSOM is published here: http://msdn.microsoft.com/en-us/library/office/dn481315(v=office.15).aspx. In this post, and the following posts, I will show you how to manage workflows with CSOM.

This is code works with SharePoint 2013 On-Premises as well as with SharePoint Online. I have created my sample code against SharePoint Online. Also, this code only works with Workflows which are authored on the SharePoint 2013 Workflow Engine. I will be writing another post on the CSOM Interop Service in which I will show how to start SharePoint 2010 Workflow Engine authored Workflows.

Before you run this code, you will need to create a Workflow (Definition) either via SharePoint Designer 2013 or through Visual Studio 2012/2013 and deploy it to your target site. You can then use this code to dynamically create associations of the Workflow, and also to start those associations.

You will need to reference the following Assemblies:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Microsoft.SharePoint.Client.WorkflowServices.dll


1) Create a new Subscription (Association) from a Workflow Definition with CSOM:


using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WorkflowServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace CSOMWorkflow
{
class Program
{
static void Main(string[] args)
{
//Replace the following values according to your configuration.
//Site details
string siteUrl = "https://mytenant.sharepoint.com/sites/test";
string userName = "user@mytenant.onmicrosoft.com";
string password = "password";
//Name of the SharePoint2013 List Workflow
string workflowName = "SP2013ListWF";
//GUID of list on which to create the subscription (association);
Guid targetListGuid = new Guid("fc50af29-8ae5-4303-bad1-213151818215");
//Name of the new Subscription (association)
string newSubscriptionName = "CSOM Subscription";
//Workflow Lists
string workflowHistoryListID = "5bc8227b-66a3-4e12-8055-846dcfb53cab";
string taskListID = "a75e266c-5f20-4b83-9f95-10a42c629e84";
using (ClientContext clientContext = new ClientContext(siteUrl))
{
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
//Workflow Services Manager which will handle all the workflow interaction.
WorkflowServicesManager wfServicesManager = new WorkflowServicesManager(clientContext, web);
//Deployment Service which holds all the Workflow Definitions deployed to the site
WorkflowDeploymentService wfDeploymentService = wfServicesManager.GetWorkflowDeploymentService();
//Get all the definitions from the Deployment Service, or get a specific definition using the GetDefinition method.
WorkflowDefinitionCollection wfDefinitions = wfDeploymentService.EnumerateDefinitions(false);
clientContext.Load(wfDefinitions, wfDefs => wfDefs.Where(wfd => wfd.DisplayName == workflowName));
clientContext.ExecuteQuery();
WorkflowDefinition wfDefinition = wfDefinitions.First();
//The Subscription service is used to get all the Associations currently on the SPSite
WorkflowSubscriptionService wfSubscriptionService = wfServicesManager.GetWorkflowSubscriptionService();
//The subscription (association)
WorkflowSubscription wfSubscription = new WorkflowSubscription(clientContext);
wfSubscription.DefinitionId = wfDefinition.Id;
wfSubscription.Enabled = true;
wfSubscription.Name = newSubscriptionName;
var startupOptions = new List<string>();
// automatic start
startupOptions.Add("ItemAdded");
startupOptions.Add("ItemUpdated");
// manual start
startupOptions.Add("WorkflowStart");
// set the workflow start settings
wfSubscription.EventTypes = startupOptions;
// set the associated task and history lists
wfSubscription.SetProperty("HistoryListId", workflowHistoryListID);
wfSubscription.SetProperty("TaskListId", taskListID);
//Create the Association
wfSubscriptionService.PublishSubscriptionForList(wfSubscription, targetListGuid);
clientContext.ExecuteQuery();
}
}
}
}

2) Start a SharePoint 2013 Site Workflow with CSOM:


using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WorkflowServices;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace CSOMWorkflow
{
class Program
{
static void Main(string[] args)
{
//Replace the following values according to your configuration.
//Site details
string siteUrl = "https://mytenant.sharepoint.com/sites/test";
string userName = "user@mytenant.onmicrosoft.com";
string password = "password";
//Name of the SharePoint2013 Site Workflow
string workflowName = "SharePoint2013SiteWorkflow";
using (ClientContext clientContext = new ClientContext(siteUrl))
{
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
//Workflow Services Manager which will handle all the workflow interaction.
WorkflowServicesManager wfServicesManager = new WorkflowServicesManager(clientContext, web);
//The Subscription service is used to get all the Associations currently on the SPSite
WorkflowSubscriptionService wfSubscriptionService = wfServicesManager.GetWorkflowSubscriptionService();
//All the subscriptions (associations)
WorkflowSubscriptionCollection wfSubscriptions = wfSubscriptionService.EnumerateSubscriptions();
//Load only the subscription (association) which we want. You can also get a subscription by definition id.
clientContext.Load(wfSubscriptions, wfSubs => wfSubs.Where(wfSub => wfSub.Name == workflowName));
clientContext.ExecuteQuery();
//Get the subscription.
WorkflowSubscription wfSubscription = wfSubscriptions.First();
//The Instance Service is used to start workflows and create instances.
WorkflowInstanceService wfInstanceService = wfServicesManager.GetWorkflowInstanceService();
//Any custom parameters you want to send to the workflow.
var initiationData = new Dictionary<string, object>();
wfInstanceService.StartWorkflow(wfSubscription, initiationData);
clientContext.ExecuteQuery();
}
}
}
}

3) Start a SharePoint 2013 List Workflow with CSOM:


using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WorkflowServices;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace CSOMWorkflow
{
class Program
{
static void Main(string[] args)
{
//Replace the following values according to your configuration.
//Site details
string siteUrl = "https://mytenant.sharepoint.com/sites/test";
string userName = "user@mytenant.onmicrosoft.com";
string password = "password";
//Name of the SharePoint2013 List Workflow
string workflowName = "SP2013ListWF";
//ID of the Item on which to start the workflow.
int itemID = 1;
using (ClientContext clientContext = new ClientContext(siteUrl))
{
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
//Workflow Services Manager which will handle all the workflow interaction.
WorkflowServicesManager wfServicesManager = new WorkflowServicesManager(clientContext, web);
//The Subscription service is used to get all the Associations currently on the SPSite
WorkflowSubscriptionService wfSubscriptionService = wfServicesManager.GetWorkflowSubscriptionService();
//All the subscriptions (associations)
WorkflowSubscriptionCollection wfSubscriptions = wfSubscriptionService.EnumerateSubscriptions();
//Load only the subscription (association) which we want. You can also get a subscription by definition id.
clientContext.Load(wfSubscriptions, wfSubs => wfSubs.Where(wfSub => wfSub.Name == workflowName));
clientContext.ExecuteQuery();
//Get the subscription.
WorkflowSubscription wfSubscription = wfSubscriptions.First();
//The Instance Service is used to start workflows and create instances.
WorkflowInstanceService wfInstanceService = wfServicesManager.GetWorkflowInstanceService();
//Any custom parameters you want to send to the workflow.
var initiationData = new Dictionary<string, object>();
wfInstanceService.StartWorkflowOnListItem(wfSubscription, itemID, initiationData);
clientContext.ExecuteQuery();
}
}
}
}