Friday, December 15, 2006

Sharepoint rollup web parts

I've recently been working with Sharepoint 2007 on a large scale project. A common requirement for many Sharepoint-enabled web portals is to create what is termed as a 'rollup' of data. In a nutshell, this entails the amalgamation of one or more Sharepoint 'Lists' - e.g. Tasks, Shared Documents, etc. But not simply an amalgamation of that data on one level - For if, as is commonly the case, you have set up sub-sites underneath your top level site, then you'll want to collect data from the lists within those sites too. The term associated with this bundling of site and sub-sites' data is known as a rollup.

One of the requirements for the portal I've been working on was to create a rollup webpart of all the Tasks lists across the entire site collection. Using VS.NET, I created the following WebPart-derived class and deployed it to the Sharepoint server.



    1 using System;


    2 using System.Runtime.InteropServices;


    3 using System.Web.UI;


    4 using System.Web.UI.WebControls.WebParts;


    5 using System.Xml.Serialization;


    6 


    7 using Microsoft.SharePoint;


    8 using Microsoft.SharePoint.WebControls;


    9 using Microsoft.SharePoint.WebPartPages;


   10 


   11 using System.Xml;


   12 using System.Xml.Xsl;


   13 using System.IO;


   14 using System.Text;


   15 


   16 using System.Data;


   17 


   18 namespace Custom.WebParts


   19 {


   20     [Guid("9e209402-e946-4070-b869-3faa90a92513")]


   21     public class TasksRollUp : System.Web.UI.WebControls.WebParts.WebPart


   22     {


   23         // Private vars.


   24         private string strCulture = "en-GB";


   25         private string strUserOrGroup = "Context"; // by default, base the results on the user in context.


   26 


   27         // Checkbox private vars.


   28         private bool bStatusNotStarted = true;


   29         private bool bStatusInProgress = true;


   30         private bool bStatusCompleted = true;


   31         private bool bStatusDeferred = true;


   32         private bool bStatusWaitingOnSomeoneElse = true;


   33 


   34 


   35         /// <summary>


   36         /// The main method to write to the UI.


   37         /// </summary>


   38         /// <param name="writer"></param>


   39         protected override void Render(HtmlTextWriter writer)


   40         {


   41             string results = LoadTasks();


   42             writer.Write(results);


   43         }


   44 


   45         /// <summary>


   46         /// Loads 'All My Tasks'.


   47         /// </summary>


   48         private string LoadTasks()


   49         {


   50             // Knock up a SPSiteDataQuery object and detail the CAML query.


   51             bool applyContextOrGroup = (this.UserOrGroup == "") ? false : true;


   52 


   53             string user = "";


   54             if (this.UserOrGroup.ToLower() == "context")


   55                 user = SPContext.Current.Web.CurrentUser.Name;


   56             else


   57                 user = this.UserOrGroup;


   58 


   59             SPSiteDataQuery q = new SPSiteDataQuery();


   60 


   61             if (!applyContextOrGroup)


   62             {


   63                 q.ViewFields = "<FieldRef Name=\"ID\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"Created\" /><FieldRef Name=\"Body\" />";


   64                 q.Lists = "<Lists ServerTemplate=\"107\"/>";


   65                 q.Webs = "<Webs Scope=\"Recursive\"/>";


   66                 q.Query = "<Where><Eq><FieldRef Name=\"ID\"/><Value Type=\"String\">1</Value></Eq></Where>";


   67             }


   68             else if (applyContextOrGroup == true && user == "context")


   69             {


   70                 q.ViewFields = "<FieldRef Name=\"ID\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"Created\" /><FieldRef Name=\"Body\" />";


   71                 q.Lists = "<Lists ServerTemplate=\"107\"/>";


   72                 q.Webs = "<Webs Scope=\"Recursive\"/>";


   73                 q.Query = "<Where><And><Eq><FieldRef Name=\"ID\" /><Value Type=\"Counter\">1</Value></Eq><Eq><FieldRef Name=\"AssignedTo\" /><Value Type=\"User\">" + user + "</Value></Eq></And></Where>";


   74             }


   75             else


   76             {//GROUPS.


   77                 q.ViewFields = "<FieldRef Name=\"ID\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"Created\" /><FieldRef Name=\"Body\" />";


   78                 q.Lists = "<Lists ServerTemplate=\"107\"/>";


   79                 q.Webs = "<Webs Scope=\"Recursive\"/>";


   80                 q.Query = "<Where><Eq><FieldRef Name=\"AssignedTo\" /><Value Type=\"User\">" + user + "</Value></Eq></Where>";


   81             }


   82 


   83             DataTable dt = null;


   84             SPWeb w = SPContext.Current.Web;


   85             // Load ALL 'My' tasks from across ALL sites.


   86             dt = w.GetSiteData(q);


   87 


   88             w = null;


   89 


   90             if (dt.Rows.Count == 0)


   91                 return "No tasks to view on this level.";


   92 


   93             DataSet ds = new DataSet();


   94             ds.Tables.Add(dt);


   95 


   96             string xml = ds.GetXml();


   97 


   98             // Format the data.


   99             xml = System.Text.RegularExpressions.Regex.Replace(xml, "&lt;", "<");


  100             xml = System.Text.RegularExpressions.Regex.Replace(xml, "&gt;", ">");


  101 


  102             // XSL parameter list.


  103             XsltArgumentList oArgList = new XsltArgumentList();


  104 


  105             // Site ID is based on SPContext.


  106 


  107 #if DEBUG


  108             oArgList.AddParam("SiteId", "", "2352352"); // FOR TEST.           


  109 #else


  110             oArgList.AddParam("SiteId", "", SPContext.Current.Site.ID.ToString());


  111 #endif


  112             // Set the culture, based on the setting. (Default to site wide culture setting).


  113             oArgList.AddParam("Culture", "", this.Culture);


  114 


  115             string outHtml = XslTransform(xml, "/", "Shared Documents", "TaskList.xsl", oArgList);


  116             return outHtml;


  117         }


  118 


  119         public CustomDocument GetDocument(string fileName, string pathWeb, string listName)


  120         {


  121             SPSite gSite = null;


  122             SPWeb gWeb = null;


  123             SPList gList;


  124             CustomDocument bdoc = new CustomDocument();


  125             try


  126             {


  127                 // If the Path web is passed in then use it to find the list otherwise use current context               


  128 #if DEBUG


  129                 //FOR TEST.


  130                 SPSite s = new SPSite("http://localhost");


  131                 gSite = s;


  132 #else


  133                 // gSite = SPContext.Current.Site; // Doesn't work. Mais pourquoi?


  134                 SPSite s = new SPSite("http://localhost");


  135                 gSite = s;


  136 #endif


  137                 gWeb = gSite.AllWebs[pathWeb];


  138                 gList = gWeb.Lists[listName];


  139 


  140                 foreach (SPListItem item in gList.Items)


  141                 {


  142                     if (item.Title.ToLower() == fileName.ToLower())


  143                     {


  144                         byte[] xmlfile = item.File.OpenBinary();


  145                         System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();


  146 


  147                         bdoc.Body = enc.GetString(xmlfile);


  148                         bdoc.DocumentID = item.UniqueId.ToString();


  149                         bdoc.list = gList.ID.ToString();


  150                         //bdoc.CheckedOutTo = item.File.CheckedOutBy.ToString();


  151                     }


  152                 }


  153                 return bdoc;


  154             }


  155             catch (Exception ex)


  156             {


  157                 bdoc.Body = ex.Message.ToString();


  158                 return bdoc;


  159             }


  160             finally


  161             {


  162 


  163                 if (gSite != null)


  164                     gSite.Dispose();


  165 


  166                 if (gWeb != null)


  167                     gWeb.Dispose();


  168             }


  169         }


  170 


  171         /// <summary>


  172         /// Perform an XSL transform.


  173         /// </summary>


  174         /// <param name="xml">The raw XML to use</param>


  175         /// <param name="xsl">The XSL document name</param>


  176         /// <param name="sharepointPath">The Sharepoint path</param>


  177         /// <param name="sharepointList">The Sharepoint list name</param>


  178         /// <param name="parameters">A list of XSL parameters</param>


  179         /// <returns></returns>


  180         public string XslTransform(string xml, string sharepointPath, string sharepointList, string xsl, XsltArgumentList parameters)


  181         {


  182             // Get the TaskList.xsl file from Sharepoint.


  183             CustomDocument oDoc = GetDocument(xsl, sharepointPath, sharepointList);


  184 


  185             TextReader trXSL;


  186             trXSL = new StringReader(oDoc.Body);


  187 


  188             // Load up a reader object with the contents of the XSL.


  189             XmlReader xrXSL = XmlReader.Create(trXSL);


  190 


  191             StringBuilder sbHTML = new StringBuilder(); // Used for HTML to be returned.


  192 


  193             // Load up an XMLDocument object with the incoming XML...


  194             XmlDocument xDoc = new XmlDocument();


  195             xDoc.LoadXml(xml);


  196 


  197             // Create an XMLWriter object based on the string builder.


  198             XmlWriter xwHTML = XmlWriter.Create(sbHTML);


  199 


  200             // Perform the conversion.


  201             XslCompiledTransform xsltTransform = new XslCompiledTransform();


  202             xsltTransform.Load(xrXSL);


  203 


  204             try


  205             {


  206                 // Attempt the transform.


  207                 xsltTransform.Transform(xDoc, parameters, xwHTML);


  208             }


  209             catch (IOException ioEx)


  210             {


  211                 throw ioEx;


  212             }


  213             catch (Exception ex)


  214             {


  215                 throw ex;


  216             }


  217             finally


  218             {


  219                 // Write the results to file.


  220                 xwHTML.Flush();


  221                 xwHTML.Close();


  222 


  223                 // Clean up.


  224 


  225                 trXSL.Close();


  226                 trXSL.Dispose();


  227 


  228                 xrXSL.Close();


  229             }


  230 


  231             return sbHTML.ToString();


  232         }


  233 


  234 


  235         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  236         [WebBrowsable(true), Personalizable(true)]


  237         [WebDescription("What is the culture? Choose for the time being from two options: the default 'en-GB' or 'en-US'")]


  238         [WebDisplayName("Active Culture")]


  239         [System.ComponentModel.Category("Custom Settings")]


  240         public string Culture


  241         {


  242             get


  243             {


  244                 return strCulture;


  245             }


  246             set


  247             {


  248                 strCulture = value;


  249             }


  250         }


  251 


  252         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  253         [WebBrowsable(true), Personalizable(true)]


  254         [WebDescription("Base the task list that is generated on the user in context (type 'Context') - e.g. show only tasks assigned to the user in context, or specify a group name, e.g. 'Administrators'")]


  255         [WebDisplayName("Filter by User or Group")]


  256         [System.ComponentModel.Category("Custom Settings")]


  257         public string UserOrGroup


  258         {


  259             get


  260             {


  261                 return strUserOrGroup;


  262             }


  263             set


  264             {


  265                 strUserOrGroup = value;


  266             }


  267         }


  268 


  269         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  270         [WebBrowsable(true), Personalizable(true)]


  271         [WebDescription("Tick to show/hide tasks that have not been started.")]


  272         [WebDisplayName("Not started")]


  273         [System.ComponentModel.Category("Task Status")]


  274         public bool NotStarted


  275         {


  276             get


  277             {


  278                 return bStatusNotStarted;


  279             }


  280             set


  281             {


  282                 bStatusNotStarted = value;


  283             }


  284         }


  285 


  286         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  287         [WebBrowsable(true), Personalizable(true)]


  288         [WebDescription("Tick to show/hide tasks that are in progress.")]


  289         [WebDisplayName("In progress")]


  290         [System.ComponentModel.Category("Task Status")]


  291         public bool InProgress


  292         {


  293             get


  294             {


  295                 return bStatusInProgress;


  296             }


  297             set


  298             {


  299                 bStatusInProgress = value;


  300             }


  301         }


  302 


  303         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  304         [WebBrowsable(true), Personalizable(true)]


  305         [WebDescription("Tick to show/hide tasks that have been completed.")]


  306         [WebDisplayName("Completed")]


  307         [System.ComponentModel.Category("Task Status")]


  308         public bool Completed


  309         {


  310             get


  311             {


  312                 return bStatusCompleted;


  313             }


  314             set


  315             {


  316                 bStatusCompleted = value;


  317             }


  318         }


  319 


  320         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  321         [WebBrowsable(true), Personalizable(true)]


  322         [WebDescription("Tick to show/hide tasks that have been deferred.")]


  323         [WebDisplayName("Deferred")]


  324         [System.ComponentModel.Category("Task Status")]


  325         public bool Deferred


  326         {


  327             get


  328             {


  329                 return bStatusDeferred;


  330             }


  331             set


  332             {


  333                 bStatusDeferred = value;


  334             }


  335         }


  336 


  337         [WebPartStorage(Storage.Shared), System.Xml.Serialization.XmlElement(Namespace = "http://localhost")]


  338         [WebBrowsable(true), Personalizable(true)]


  339         [WebDescription("Tick to show/hide tasks that are waiting on someone else.")]


  340         [WebDisplayName("Waiting on someone else")]


  341         [System.ComponentModel.Category("Task Status")]


  342         public bool WaitingOnSomeoneElse


  343         {


  344             get


  345             {


  346                 return bStatusWaitingOnSomeoneElse;


  347             }


  348             set


  349             {


  350                 bStatusWaitingOnSomeoneElse = value;


  351             }


  352         }


  353     }


  354 


  355     public class CustomDocument


  356     {


  357         public string Body;


  358         public string DocumentID;


  359         public string CheckedOutTo;


  360         public string site;


  361         public string list;


  362     }


  363 }



Thursday, November 23, 2006

A Fairly Painless Way To Combine Dataset Data

foreach (DataRow dr in ds2.Tables[1].Rows)
{
object[] vals = dr.ItemArray;
ds.Tables[1].Rows.Add(vals);
}

ItemArray is key.

Thursday, November 02, 2006

Using Resource Files

Recently, I had a case to use an XML embedded resource file. After adding the following XML file to the solution and setting its 'Build Action' property to 'Embedded Resource'...

<?xml version="1.0" encoding="utf-8" ?>
<Config>
    <VariablefileName>../Projects/RealEstatePostcard/PostCard.xvp</VariablefileName>
    <ProjectFileForVariableEvaluation>../Projects/RealEstatePostcard/PostCard.pf</ProjectFileForVariableEvaluation>
    <JobForVariableEvaluation>PDF_Job</JobForVariableEvaluation>
    <ShowScrollBars>Yes</ShowScrollBars>
    <BevelThickness>1</BevelThickness>
    <BevelThicknessInset>3</BevelThicknessInset>
    <BevelColorInset>lightGray</BevelColorInset>
    <BevelColorTopLeft>lightGray</BevelColorTopLeft>
    <BevelColorBottomRight>darkGray</BevelColorBottomRight>
    <uiConfiguration> PanelPostCardConfig.xml</uiConfiguration>
    <EditImage>Edit Image: Crop and Scale Your Image</EditImage>
    <bitmapUpdateMethod>xor</bitmapUpdateMethod>
</Config>

I grabbed a hold of it and set its contents against relevant public property names within my class. Like so:

private void LoadConfigValues()
        {
            // Create a new XmlDocument object and select the appropriate values.          
           
            // Reference the running assembly.
            Assembly thisAssembly = Assembly.GetExecutingAssembly();
       
            Stream oStrRead = thisAssembly.GetManifestResourceStream("Burrows.PageFlex.WYSIWYG.Config.Configuration.xml");
           

            XmlDocument xDoc = new XmlDocument();

            try
            {               
                xDoc.Load(oStrRead);
            }
            catch (IOException ioEx)
            {
                throw ioEx;
            }
            finally
            {               
                oStrRead.Close();
                oStrRead.Dispose();
            }

            // Loop through doc nodes and assign values to public properties.
            XmlNodeList oNodeList = xDoc.SelectNodes("//Config/*");
            foreach (XmlNode xN in oNodeList)
            {
                switch (xN.Name)
                {
                    case "VariablefileName":
                        this.strVariableFileName = xN.InnerText;
                        break;
                    case "ProjectFileForVariableEvaluation":
                        this.strProjectFileForVariableEvaluation = xN.InnerText;
                        break;
                    case "JobForVariableEvaluation":
                        this.strJobForVariableEvaluation = xN.InnerText;
                        break;
                    case "ShowScrollBars":
                        this.strShowScrollBars = xN.InnerText;
                        break;
                    case "BevelThickness":
                        this.strBevelThickness = xN.InnerText;
                        break;
                    case "BevelThicknessInset":
                        this.strBevelThicknessInset = xN.InnerText;
                        break;
                    case "BevelColorInset":
                        this.strBevelColorInset = xN.InnerText;
                        break;
                    case "BevelColorTopLeft":
                        this.strBevelColorTopLeft = xN.InnerText;
                        break;
                    case "BevelColorBottomRight":
                        this.strBevelColorBottomRight = xN.InnerText;
                        break;
                    case "uiConfiguration":
                        this.strUiConfiguration = xN.InnerText;
                        break;
                    case "EditImage":
                        this.strEditImage = xN.InnerText;
                        break;
                    case "bitmapUpdateMethod":
                        this.strBitmapUpdateMethod = xN.InnerText ;
                        break;
                    default:
                        break;
                };
            }          
        }

Wednesday, October 18, 2006

Don't Underestimate The Power Of The Alt Key

Recently, whilst doing a menacing cut and paste job, I remembered the convenience of using the Alt key when selecting text.

Take the following text, for example:

Fruit                   Crisps
=====                ======       
Strawberries        Salt And Vinegar
Apples                Cheese And Onion
Pears                  Ready Salted
Oranges              Chicken
Pineapples          Prawn Cocktail

Now, if I only want to grab hold of whatever is underneath the heading 'Crisps' then all I need to do is hold down my Alt key, hover over the area just left of the letter C and begin dragging across and down. This will select only that portion of text and will exclude whatever lies under the heading 'Fruit'.

Note that only certain programs support the use of this style of copying and pasting. So far I've successfully employed its use in both Visual Studio (2003 & 2005) and SQL Server (2000 & 2005).

Wednesday, October 04, 2006

How To Kill A Process That Just Won't Die


Recently when developing a Windows service, I had problems terminating something through the admin GUI. There is, fortunately though, a manual way of getting your way, via the command line.

Enum Parsing

I always seem to forget how to parse an enum, so here's the code for doing it in 2.0:

enum ConfigurationType
        {
            Internal,
            WebConfigXml,
            Win32Xml
        };

string strConfigType = System.Configuration.ConfigurationSettings.AppSettings["ConfigurationType"].ToString();
ConfigurationType configType = (ConfigurationType)Enum.Parse(typeof(ConfigurationType), strConfigType);

Thursday, September 21, 2006

The ASP.NET Page Life Cycle

The ASP.NET Page Life Cycle

1. Object intialisation
2. Load Viewstate data
3. LoadPostData processes Postback data
4. Object load
5. Raise PostBack change events
6. Process Client-side Postback Event
7. Prerender the objects
8. Viewstate saved
9. Render to HTML
10. Disposal

http://www.15seconds.com/issue/020102.htm

Wednesday, May 24, 2006

Mod It

No, I'm not talking about altering your automobile, or bending your bike (what?). No, I'm talking about the good old fashioned Mod function of course. It took me a while to realise that the equivalent in C# is...

int result = firstNumber % secondNumber;

Wednesday, May 10, 2006

A Rounding Function That Really Works

public static double RoundDouble(double number,int digits)
{

string Temp;

string Temp2;

int i, j;

double ResultValue;

double Numbertemp;

Temp = Convert.ToString(number);

i = Temp.LastIndexOf(".");

if (((Temp.Length - (i + 1)) <= digits) (i == -1)) return number; Temp2 = Temp.Substring(i + digits + 1, 1); j = Convert.ToInt32(Temp2); Numbertemp = Convert.ToDouble(Temp.Substring(0, i + digits + 1)); if (j == 5) ResultValue = Numbertemp + (1 / (Math.Pow(10,digits))); else ResultValue = Math.Round(number, digits); return ResultValue; } Courtesy of

vedapuri

http://www.codeproject.com/useritems/Solving_rounding_problem.asp

Monday, February 20, 2006

When To Use Static Methods

Use static methods when the state of a class instance does not matter.

http://www.javaworld.com/javaworld/javaqa/2001-11/03-qa-1121-mrhappy.html

Fixes to common .NET problems, as well as information on .NET features and solutions to common problems that are not language-specific.

Fixes to common .NET problems, as well as information on .NET features and solutions to common problems that are not language-specific.

Z