Wednesday, February 20, 2008

Start a SharePoint workflow using code

Imagine you already have a SharePoint list with thousands of items and now want to associate a custom workflow with the list.
How will you go and run Workflow on all the existing items as Microsoft SharePoint don't provide any option to run workflow on existing items.
The solution: Run the workflow against each list item via the code

First Get the Workflow Guid and then Create a workflow association object. Start the workflow from the site passing the list item and the workflow association object.

To get a workflow Guid:
Go to List Settings- Workflow Setting and click on the workflow. From URL get the targetId value.

Create a Visual Studio 2005 Console project
Add Reference to SharePoint Library
Replace content of program.cs with the following code--


using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Started...");
Console.WriteLine("Read value from config list");
// Read from App.Config file
// Site URL
string SiteName = ConfigurationManager.AppSettings["SiteName"];
// Workflow Guid
string WorkFlowGuid = ConfigurationManager.AppSettings["WorkflowGuid"];
// List Name
string ListName = ConfigurationManager.AppSettings["ListName"];
// Query used to filter the items on which WorkFlow needs to be run
string Query = ConfigurationManager.AppSettings["Query"];
// Get Html Decoded Guid
string decode = ConfigurationManager.AppSettings["DecodeGuid"];
if (decode == "1")
WorkFlowGuid = DecodeString(WorkFlowGuid);


Console.WriteLine("Read site details");
SPSite site = new SPSite(SiteName);
SPWeb web = site.OpenWeb();
SPList list = web.Lists[ListName];

Console.WriteLine("Read workflow details");
SPWorkflowAssociation workflowAssociation = list.WorkflowAssociations[new Guid(WorkFlowGuid)];

Console.WriteLine("Get items");
SPListItemCollection items = null;
if(Query.Length > 0) // filtered
{
SPQuery query = new SPQuery();
query.Query = Query;
items = list.GetItems(query);
}
else
items = list.Items; // all items

Console.WriteLine("Looping items");

foreach (SPListItem item in items)
{
if(item.Workflows.Count == 0)
{
// Start if already not started
site.WorkflowManager.StartWorkflow(item, workflowAssociation,
workflowAssociation.AssociationData, true);
}
}
Console.WriteLine("Done");
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
finally
{
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
}

static string DecodeString(string sStr)
{
string sChars = " ,',!,#,$,%,&,(,),/,:,;,[,\\,],^,`,{,|,},+,<,=,>,-";
string sANSICodes = "+,%27,%21,%23,%24,%25,%26,%28,%29,%2F,%3A,%3B,%5B,%5C,%5D,%5E,%60,%7B,%7C,%7D,%2B,%3C,%3D,%3E,%2D";
string[] aChars = sChars.Split(",".ToCharArray());
string[] aANSICodes = sANSICodes.Split(",".ToCharArray());
for (int i = 0; i <= aChars.GetUpperBound(0); i++)
{
if (sStr.IndexOf(aANSICodes[i]) > -1)
sStr = sStr.Replace(aANSICodes[i], aChars[i]);
}
return sStr;
}
}

********************Config File*********************


*****************************************

The code logic-

Read values from the app.config file
If WorkflowGuid is encoded as in the config file, decode the Guid
Get workflowassociated with this WorkFlowGuid
Based on SharePoint Query, get the items
Loop through the items and if no workflow started for that item. Start the workflow

Monday, February 18, 2008

Singleton Class WinForm\WebForm

If you use static object in ASP.NET application, this works as Application object and is shared across all sessions. To create a user visible properties, we use session objects. A better way of using this is to use Singelton class. This class creates only one object and same object is refeneced again without new creation. The following code could be used to create a common Singleton class for windows and web application.

using System;
using System.Data;
using System.Configuration;
using System.Web;

namespace Common
{
///


/// Summary description for SessionConfig
///

public class StateData
{

#region PROPERTIES
string currentUser;
public string CurrentUser
{
get { return this.currentUser; }
set { this.currentUser = value; }
}
#endregion

private static StateData oInstance;

protected StateData()
{
}


public static StateData Instance
{
get
{
// If called from windows, this would be null. Use Static object then
if (System.Web.HttpContext.Current == null)
{
if (oInstance == null)
{
oInstance = new StateData();
}
return oInstance;
}
if (HttpContext.Current.Session == null || HttpContext.Current.Session["SharedData"] == null)
HttpContext.Current.Session.Add("SharedData", new StateData());


return (StateData)System.Web.HttpContext.Current.Session["SharedData"];
}
}

}
}

Hide\Show Column in Sharepoint Form

You don't need desugner to hide or show a column in Display, Edit and New form of Sharepoint List. You could use Sharepoint Objects to set this programmatically-

Create a console application and Reference SharePoint Library-
The code will be
SPSite site = new SPSite(SiteName);
SPWeb web = site.OpenWeb();
SPList list = web.Lists[ListName]; // Get teh list
// Colname = Column to hide\show
list.Fields[ColName].ShowInEditForm = ShowInEditForm;
list.Fields[ColName].ShowInDisplayForm = ShowInDispForm;
list.Fields[ColName].ShowInNewForm = ShowInNewForm;
list.Fields[ColName].Update();