<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bugfree.dk - Ronnie Holm&#039;s blog &#187; SharePoint</title>
	<atom:link href="http://www.bugfree.dk/blog/tag/sharepoint/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bugfree.dk/blog</link>
	<description>Not anti-anything, just pro-quality</description>
	<lastBuildDate>Mon, 28 Nov 2011 07:32:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Importing CSV term sets into SharePoint 2010 using PowerShell</title>
		<link>http://www.bugfree.dk/blog/2011/11/27/importing-csv-term-sets-into-sharepoint-2010-using-powershell/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/27/importing-csv-term-sets-into-sharepoint-2010-using-powershell/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 22:55:00 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1078</guid>
		<description><![CDATA[One of the new features of SharePoint 2010 is the ability to tag content using terms from a term store. The out of the box tooling for importing, exporting, and maintaining term stores is somewhat limited though. That’s why I created a PowerShell script to import term sets into the term store. Term store overview [...]]]></description>
			<content:encoded><![CDATA[<p>One of the new features of SharePoint 2010 is the ability to tag content using terms from a term store. The out of the box tooling for importing, exporting, and maintaining term stores is somewhat limited though. That’s why I created a PowerShell script to import term sets into the term store.</p>
<h4>Term store overview</h4>
<p>SharePoint organizes terms in either a taxonomy or a folksonomy. In a taxonomy, terms are organized hierarchically whereas in a folksonomy the structure is flat. A taxonomy or folksonomy is either global, making it available to all site collections within a web application that’s associated with a Managed Metadata Service, or local, making it available in one site collection only. </p>
<p>Multiple Managed Metadata Services may be associated with a web application or site collection, each service in turn responsible for a single term store. Within one term store, multiple groups may be created, each potentially storing multiple term sets. Finally, a term set may have terms nested up to seven levels deep:</p>
<pre>Managed Metadata Service Application
  TermStore
    Group1
      TermSet1
        Term1
          Term1.2
            Term1.2.3
              Term1.2.3.4
                Term1.2.3.4.5
                  Term1.2.3.4.5.6
                    Term1.2.3.4.5.6.7</pre>
<p>You manage the term store through the browser and its Term Store Management Tool (the _layouts/termstoremanager.aspx application page) or through the SharePoint API. The management tool supports importing term sets only from a <a href="http://technet.microsoft.com/en-us/library/ee424396.aspx">special CSV file format</a>&#160; (_layouts/1033/ImportTermSet.csv holds a sample) with these columns:</p>
<pre>Term Set Name
Term Set Description
LCID
Available for Tagging
Term Description
Level 1 Term
Level 2 Term
...
Level 7 Term</pre>
<p>The CSV file is incomplete in terms of what the term store offers. It doesn’t offer columns for specifying translations and synonyms for terms. But users can use <a href="http://www.wictorwilen.se/">Wictor Wilén</a>&#160;<a href="http://www.wictorwilen.se/Post/Create-SharePoint-2010-Managed-Metadata-with-Excel-2010.aspx">Excel sheet</a> to maintain the basic information. It has the standard columns above and includes macros to simplify saving in the correct format and creating additional term sets.</p>
<p>The question remains: do you maintain compatibility with the existing CSV format so you can import term sets using the browser or a forms-based tool like the <a href="http://termsetimporter.codeplex.com/">CSV Bulk Taxonomy Importer/Exporter</a>? Or do you define your own, possibly XML based format since term sets are hierarchical by nature, with additional columns for translations and synonyms? A non-CSV based format may also be easier to process. If you want to pursue the latter approach, <a href="http://sharepointtales.wordpress.com/">Ben Robb</a> has <a href="http://sharepointtales.wordpress.com/2010/05/06/manipulating-the-terms-store-through-powershell/">created a PowerShell script</a> to import his XML format. </p>
<h4>Importing term sets using PowerShell</h4>
<p>I decided to stick with the CSV file format and create a PowerShell script that would allow me to import a term set using the command-line:</p>
<pre class="prettyprint">function ImportTermSet([Microsoft.SharePoint.Taxonomy.TermStore]$store, [string]$groupName, [PSCustomObject]$termSet) {
  function ImportTerm([Microsoft.SharePoint.Taxonomy.Group]$group,
                      [Microsoft.SharePoint.Taxonomy.TermSet]$set,
                      [Microsoft.SharePoint.Taxonomy.Term]$parent,
                      [string[]]$path) {
    if ($path.Length -eq 0) {
      return
    } elseif ($group -eq $null) {
      $group = $store.Groups | where { $_.Name -eq $path[0] }
      if ($group -eq $null) {
        $group = $store.CreateGroup($path[0])
      }
    } elseif ($set -eq $null) {
      $set = $group.TermSets | where { $_.Name -eq $path[0] }
      if ($set -eq $null) {
        $set = $group.CreateTermSet($path[0])
      }
    } else {
      $node = if ($parent -eq $null) { $set } else { $parent }
      $parent = $node.Terms | where { $_.Name -eq $path[0] }
      if ($parent -eq $null) {
        $parent = $node.CreateTerm($path[0], 1033)
      }
    }

    ImportTerm $group $set $parent $path[1..($path.Length)]
  }

  function RemoveTermGroup([Microsoft.SharePoint.Taxonomy.TermStore]$store, [string]$groupName) {
    $group = $store.Groups | where { $_.Name -eq $groupName }
    if ($group -ne $null) {
      $group.TermSets | foreach { $_.Delete() }
      $group.Delete()
      $store.CommitAll()
    }
  }

  RemoveTermGroup $store $groupName
  $termSetName = $termSet[0]."Term Set Name"
  $termSet | where { $_."Level 1 Term" -ne "" } | foreach {
    $path = @($groupName, $termSetName) + @(for ($i = 1; $i -le 7; $i++) {
    $term = $_."Level $i Term"
      if ($term -eq "") {
        break
      } else {
        $term
      }
    })

    ImportTerm -path $path
  }
}</pre>
<p>The way to use the ImportTermSet function is best illustrated with an example:</p>
<pre class="prettyprint">$session = Get-SPTaxonomySession -Site "http://localhost"
$store = $session.TermStores["Managed Metadata Service"]
$termSet = Import-Csv "C:\Users\Ronnie\Desktop\ImportTermSet.csv"
ImportTermSet $store "MyGroup" $termSet
$store.CommitAll()</pre>
<p>In its current form the script ignores the Term Set Description, LCID, Available for Tagging, and Term Description columns from the CSV file. It would be possible to take these columns into account by passing them to ImportTerm as well. Instead of just removing the head of the list, you’d remove the number of items consumed by the current step before recursing.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F27%2Fimporting-csv-term-sets-into-sharepoint-2010-using-powershell%2F&amp;title=Importing%20CSV%20term%20sets%20into%20SharePoint%202010%20using%20PowerShell" id="wpa2a_2"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/27/importing-csv-term-sets-into-sharepoint-2010-using-powershell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using a generic command-line runner for utility tasks</title>
		<link>http://www.bugfree.dk/blog/2011/11/23/using-a-generic-command-line-runner-for-utility-tasks/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/23/using-a-generic-command-line-runner-for-utility-tasks/#comments</comments>
		<pubDate>Wed, 23 Nov 2011 10:04:00 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1075</guid>
		<description><![CDATA[Most enterprise projects have one or more console applications for utility tasks such as cleaning up or importing data into the database. These utilities tend to be project-specific and small in terms of code size, and instead of several smaller assemblies, it makes sense to combine these into a single assembly. The generic runner would [...]]]></description>
			<content:encoded><![CDATA[<p>Most enterprise projects have one or more console applications for utility tasks such as cleaning up or importing data into the database. These utilities tend to be project-specific and small in terms of code size, and instead of several smaller assemblies, it makes sense to combine these into a single assembly. The generic runner would read the utility, called the command, and arguments from the command-line and use the <a href="http://en.wikipedia.org/wiki/Command_pattern">command pattern</a> to create and execute it.</p>
<p>For the generic runner to work, each command has to fulfill the contract.</p>
<pre class="prettyprint lang-cs">public enum ExitCode {
    Success = 0,
    Failure
};

public interface ICommand {
    string Usage { get; }
    string Description { get; }
    ExitCode Execute(string[] args);
}</pre>
<p>I want the runner to adhere to the <a href="http://en.wikipedia.org/wiki/Open/closed_principle">open/closed principle</a>. For its behavior to be modified without altering its core delegation logic. This requires the use of reflection to retrieve and instantiate a command based on command-line arguments.</p>
<pre class="prettyprint lang-cs">class Program {
    static IEnumerable&lt;ICommand&gt; GetCommands() {
        var iCommand = typeof (ICommand);
        return System.Reflection.Assembly.GetExecutingAssembly().GetTypes().ToList()
            .Where(t =&gt; iCommand.IsAssignableFrom(t) &amp;&amp; t != iCommand)
            .Select(t =&gt; Activator.CreateInstance(t) as ICommand);
    }

    static void DisplayHelp() {
        Console.WriteLine(&quot;Console [Command] [Arg1] [Arg2] [ArgN]\n\n&quot;);
        GetCommands().ToList().ForEach(command =&gt;
            Console.WriteLine(command.Usage + &quot;\n&quot; + command.Description + &quot;\n\n&quot;));
    }

    static int Main(string[] args) {
        if (args.Length == 0) {
            DisplayHelp();
            return (int)ExitCode.Failure;
        }

        var commandName = args[0];
        var command = GetCommands().Where(t =&gt; t.GetType().Name == commandName).SingleOrDefault();
        if (command == null)
            throw new ArgumentException(string.Format(&quot;Command '{0}' not found&quot;, commandName));

        var executeArguments = new List&lt;string&gt;(args);
        executeArguments.RemoveAt(0);

        var exitCode = command.Execute(executeArguments.ToArray());
        return (int)exitCode;
    }
}</pre>
<p>A trivial example of a command that adds two numbers would be the following:</p>
<pre class="prettyprint lang-cs">// $&gt; GenericRunner.exe Calculator 2 3 =&gt; 2 + 3 = 5
public class Calculator : ICommand {
    public string Usage {
        get { return &quot;Calculator [Op1] [Op2]&quot;; }
    }

    public string Description {
        get { return &quot;World's simplest calculator&quot;; }
    }

    public ExitCode Execute(string[] args) {
        try {
            Console.WriteLine(
                string.Format(
                    &quot;{0} + {1} = {2}&quot;,
                    args[0], args[1], int.Parse(args[0]) + int.Parse(args[1])));
            return ExitCode.Success;
        } catch (Exception e) {
            Console.WriteLine(e.ToString());
            return ExitCode.Failure;
        }
    }
}</pre>
<p>Now multiple smaller assemblies can be grouped into one, with a description of all commands automatically being assembled, and without commands interfering (too much) with each other.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F23%2Fusing-a-generic-command-line-runner-for-utility-tasks%2F&amp;title=Using%20a%20generic%20command-line%20runner%20for%20utility%20tasks" id="wpa2a_4"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/23/using-a-generic-command-line-runner-for-utility-tasks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>F# + SharePoint = a list attachment versioning event receiver</title>
		<link>http://www.bugfree.dk/blog/2011/11/21/f-sharepoint-a-list-attachment-versioning-event-receiver/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/21/f-sharepoint-a-list-attachment-versioning-event-receiver/#comments</comments>
		<pubDate>Mon, 21 Nov 2011 07:37:00 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[F#]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1074</guid>
		<description><![CDATA[It’s been a while since I last took a serious look at F#. Back then I did a simple random fractal terrain generator which, even though the algorithm is simple, I found challenging to do. Nevertheless, functional programming is just one of those areas that I keep returning to. This time around I want to [...]]]></description>
			<content:encoded><![CDATA[<p>It’s been a while since I last took a serious look at F#. Back then I did a simple <a href="http://www.bugfree.dk/blog/2009/03/06/generating-2d-random-fractal-terrains-with-f/">random fractal terrain generator</a> which, even though the algorithm is simple, I found challenging to do. Nevertheless, functional programming is just one of those areas that I keep returning to. This time around I want to use the event receiver for <a href="http://www.bugfree.dk/blog/2011/11/17/versioning-attachments-in-a-sharepoint-list-using-snapshotting/">versioning attachments in SharePoint lists</a> to get familiar with object-oriented F#. Of course, translating a C# class to an F# class, the result will look like C# with different syntax and better type inference. The point here is to use classes in F# as a way to expose functionality to other .NET languages. In a real-world F# application the core logic would likely not be object-oriented.</p>
<pre class="prettyprint lang-ml">namespace Dk.Bugfree

open System
open System.Globalization
open Microsoft.SharePoint

type public ListAttachmentVersioningEventReceiver() =
    inherit SPItemEventReceiver()

    member private r.CustomVersion = &quot;CustomVersion&quot;
    member private r.ShadowLibrary = &quot;ShadowLibrary&quot;

    // override ItemAdded : properties:SPItemEventProperties -&gt; unit
    override r.ItemAdded properties =
        base.ItemAdded properties
        r.SetCustomVersionLabel properties.ListItem
        r.CreateSnapshot properties

    // override ItemUpdated : properties:SPItemEventProperties -&gt; unit
    override r.ItemUpdated properties =
        base.ItemUpdated properties
        let item = properties.ListItem

        if r.RollbackHappened item then
            r.RestoreSnapshot properties
            r.SetCustomVersionLabel item
            r.CreateSnapshot properties
        else
            r.CreateSnapshot properties
            r.SetCustomVersionLabel item

    // member private CreateSnapshot : properties:SPItemEventProperties -&gt; unit
    member private r.CreateSnapshot properties =
        use site = properties.OpenWeb()
        let item = properties.ListItem
        let shadowLibrary = site.Lists.[r.ShadowLibrary] :?&gt; SPDocumentLibrary
        let path = String.Format(&quot;Versions/{0}/{1}&quot;, item.ID, r.GetOfficialVersionLabel(item))
        let shadowFolder = r.CreateFolderPath shadowLibrary path

        item.Attachments |&gt; Seq.cast |&gt; Seq.iter (fun fileName -&gt;
            let existingFile = item.ParentList.ParentWeb.GetFile(item.Attachments.UrlPrefix + fileName)
            let newFile = shadowFolder.Files.Add(fileName, existingFile.OpenBinaryStream())
            newFile.Item.Update())

    // member private RollbackHappened : item:SPListItem -&gt; bool
    member private r.RollbackHappened item =
        let culture = CultureInfo.InvariantCulture
        let currentVersion = Single.Parse(r.GetOfficialVersionLabel(item), culture)
        let lastVersion = Single.Parse(r.GetCustomVersionLabel(item), culture)
        currentVersion &gt; lastVersion + 1.0f

    // member private RestoreSnapshot : properties:SPItemEventProperties -&gt; unit
    member private r.RestoreSnapshot properties =
        let item = properties.ListItem
        let restoreVersion = r.GetCustomVersionLabel item
        r.EventFiringEnabled &lt;- false    

        item.Attachments |&gt; Seq.cast |&gt; Seq.map (fun fileName -&gt; unbox&lt;string&gt; fileName) |&gt; Seq.toList
                         |&gt; Seq.iter (fun fileName -&gt; item.Attachments.Delete(fileName))

        use site = properties.OpenWeb()
        let path = String.Format(&quot;Versions/{0}/{1}&quot;, item.ID, restoreVersion)
        let shadowLibrary = site.Lists.[r.ShadowLibrary] :?&gt; SPDocumentLibrary
        let source = r.CreateFolderPath shadowLibrary path

        source.Files |&gt; Seq.cast |&gt; Seq.iter (fun file -&gt;
            let unboxedFile = unbox&lt;SPFile&gt; file
            item.Attachments.Add(unboxedFile.Name, unboxedFile.OpenBinary()))

        item.SystemUpdate false
        r.EventFiringEnabled &lt;- true

    // member private CreateFolderPath : list:SPDocumentLibrary -&gt; path:string -&gt; SPFolder
    member private r.CreateFolderPath list path : SPFolder =
        r.CreateFolderPathRecursive list.RootFolder (path.Split [|'/'|] |&gt; Array.toList)

    // member private CreateFolderPathRecursive : folder:SPFolder -&gt; pathComponents:string list -&gt; SPFolder
    member private r.CreateFolderPathRecursive folder pathComponents =
        match pathComponents with
        | [] -&gt; folder
        | head :: tail -&gt;
            try
                let existingFolder = folder.SubFolders.[head]
                r.CreateFolderPathRecursive existingFolder tail
            with
                :? ArgumentException -&gt;
                    let newFolder = folder.SubFolders.Add head
                    r.CreateFolderPathRecursive newFolder tail

    // member private SetCustomVersionLabel : item:SPListItem -&gt; unit
    member private r.SetCustomVersionLabel item =
        r.EventFiringEnabled &lt;- false
        item.[r.CustomVersion] &lt;- r.GetOfficialVersionLabel item
        item.SystemUpdate false
        r.EventFiringEnabled &lt;- true  

    // member private GetCustomVersionLabel : item:SPListItem -&gt; string
    member private r.GetCustomVersionLabel item =
        item.[r.CustomVersion] :?&gt; string

    // member private GetOfficialVersionLabel : item:SPListItem -&gt; string
    member private r.GetOfficialVersionLabel item =
        item.Versions.[0].VersionLabel</pre>
<p>A couple of things to note about the F# implementation: first, it hardly specifies any types. They’re inferred by the compiler. Where type names do appear, it’s mainly because they’re required to unbox elements of an IEnumerable collection. Secondly, F# has <a href="http://stackoverflow.com/questions/5355334/what-are-the-benefits-of-such-flexible-self-identifiers-in-f">flexible self identifiers</a>. Methods must explicitly specify the name of the this reference in C# and use it when accessing members. Thirdly, arguments to general .NET methods are passed as a tuple value, i.e., as comma-delimited arguments surrounded by parenthesis.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F21%2Ff-sharepoint-a-list-attachment-versioning-event-receiver%2F&amp;title=F%23%20%2B%20SharePoint%20%3D%20a%20list%20attachment%20versioning%20event%20receiver" id="wpa2a_6"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/21/f-sharepoint-a-list-attachment-versioning-event-receiver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adding event receivers to SharePoint lists on the fly</title>
		<link>http://www.bugfree.dk/blog/2011/11/19/adding-event-receivers-to-sharepoint-lists-on-the-fly/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/19/adding-event-receivers-to-sharepoint-lists-on-the-fly/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 21:53:00 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1073</guid>
		<description><![CDATA[In versioning attachments in a SharePoint list using snapshotting, an event receiver was responsible for the heavy lifting. To enable versioning of a list, I could therefore have associated the receiver with a list by adding the usual registration XML to a feature. But versioning is a truly reusable building block that shouldn’t be restricted [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.bugfree.dk/blog/2011/11/17/versioning-attachments-in-a-sharepoint-list-using-snapshotting/">versioning attachments in a SharePoint list using snapshotting</a>, an event receiver was responsible for the heavy lifting. To enable versioning of a list, I could therefore have associated the receiver with a list by adding the usual registration XML to a feature. But versioning is a truly reusable building block that shouldn’t be restricted to lists that are known when the feature is created. A better solution would be to extend the SharePoint list settings page for all lists on a site on which the versioning feature is enabled. The user may then activate or deactivate attachment versioning on the fly.</p>
<p>This would involve adding or removing event receivers from a list as the user enables or disables versioning. The following extension method is one way to accomplish the addition-part in a type-safe manner:</p>
<pre class="prettyprint lang-cs">// definition
public static class SPListExtensions {
    public static void RegisterEventReceiver&lt;TReceiver&gt;(this SPList list,
            SPEventReceiverType receiverType,
            int sequenceNumber) where TReceiver : SPItemEventReceiver {
        var assemblyName = typeof(TReceiver).Assembly.FullName;
        var className = typeof(TReceiver).FullName;

        (from SPEventReceiverDefinition definition in list.EventReceivers
         where definition.Assembly == assemblyName &amp;&amp;
               definition.Class == className &amp;&amp;
               definition.Type == receiverType
         select list.EventReceivers[definition.Id])
        .ToList()
        .ForEach(receiverToDelete =&gt; receiverToDelete.Delete());

        var receiver = list.EventReceivers.Add();
        receiver.Type = receiverType;
        receiver.Assembly = assemblyName;
        receiver.Class = className;
        receiver.SequenceNumber = sequenceNumber;
        receiver.Update();
        list.Update();
    }
}

// use
list.RegisterEventReceiver&lt;ListAttachmentVersioningEventReceiver&gt;(
    SPEventReceiverType.ItemAdded, 10000);
list.RegisterEventReceiver&lt;ListAttachmentVersioningEventReceiver&gt;(
    SPEventReceiverType.ItemUpdated, 10001);</pre>
<p>Under rare circumstances the (assembly, class, type) tuple may not be unique, i.e., the same receiver may be registered multiple times, albeit with different sequence numbers. In practice I never found any use for this functionality, though, which is why I didn’t include the sequence number in the where clause above, causing all registrations matching the tuple to be removed.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F19%2Fadding-event-receivers-to-sharepoint-lists-on-the-fly%2F&amp;title=Adding%20event%20receivers%20to%20SharePoint%20lists%20on%20the%20fly" id="wpa2a_8"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/19/adding-event-receivers-to-sharepoint-lists-on-the-fly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Versioning attachments in a SharePoint list using snapshotting</title>
		<link>http://www.bugfree.dk/blog/2011/11/17/versioning-attachments-in-a-sharepoint-list-using-snapshotting/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/17/versioning-attachments-in-a-sharepoint-list-using-snapshotting/#comments</comments>
		<pubDate>Thu, 17 Nov 2011 09:38:16 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1070</guid>
		<description><![CDATA[(See also the F# implementation and adding event receivers to a list on the fly.) Both SharePoint 2007 and 2010 support versioning for list items but not their attachments. No matter which version of a list item I look at, its attachments will always be the most recent. The attachment support seems to have been [...]]]></description>
			<content:encoded><![CDATA[<p>(See also the <a href="http://www.bugfree.dk/blog/2011/11/21/f-sharepoint-a-list-attachment-versioning-event-receiver/">F# implementation</a> and <a href="http://www.bugfree.dk/blog/2011/11/19/adding-event-receivers-to-sharepoint-lists-on-the-fly/">adding event receivers to a list on the fly</a>.)</p>
<p>Both SharePoint 2007 and 2010 support versioning for list items but not their attachments. No matter which version of a list item I look at, its attachments will always be the most recent. The attachment support seems to have been bolded on as an afterthought, resulting in behavior that’s counter-intuitive for developers as well as end-users. With SharePoint 2007 (and 2010), Microsoft <a href="http://support.microsoft.com/kb/943136">suggests</a> using a document library for proper attachment versioning. But I can’t substitute one with the other, since a list item may hold any number of attachments and an item in a document library may hold just one.</p>
<h4>Existing solution</h4>
<p>I counted on someone else having experienced a similar pain and come up with a workable cure. But except for <a href="http://codeshape.wordpress.com/2010/10/21/versioning-attachments-in-a-sharepoint-list-an-implementation/">Tim Ebenezer</a> the search come up empty. Tim on the other hand has done a great job of seamlessly integrating his attachment versioning feature into SharePoint. When I activate the feature on a site, it adds a versioning menu item to the list settings page for every list on the site. Unfortunately the core versioning logic, storing attachments in a shadow library using an event receiver, isn’t particularly robust. Among other use cases, it doesn’t properly deal with a user first deleting an attachment and then, some versions later, adding an attachment with the same name.</p>
<p>I therefore set out to implement my own solution based on Tim’s ideas, hooking into the synchronous ItemAdding, ItemUpdating, ItemAttachmentAdding, and ItemAttachmentDeleting events and maintaining a shadow library of versions. This approach, however, quickly turned into a painful one. When the synchronous events run, nothing has yet been written to the database – at this stage a new item doesn’t even have its Id set, and merely determining the number of attachments added and how far I’ve come with the processing is tricky.</p>
<p>The next challenge I encountered was that event handlers cannot easily share state across multiple calls because SharePoint creates a new instance of the receiver class for every event handled. Processing multiple attachments require a counter into the array of attachments to keep track of which ones I’d copied to the shadow list. I’d have to resort to some outside-object storage, keeping in mind that the receiver might execute concurrently. But which storage should I use? Session state may have been disabled, and polluting one of the property bags stored in the content database is messy and also not thread-safe.</p>
<p>Overall, with the synchronous approach too much work has to go into tracking the state of the versioning process.</p>
<h4>New solution</h4>
<p>A synchronous solution is very hard to get right because it’s forced to work at the level of individual attachments. SharePoint doesn’t have a synchronous event that fires after all attachments have been processed. After all, why provide such an event when everything has already happened? Thinking instead in terms of the asynchronous events of ItemUpdated and ItemAdded, I have exactly what’s needed to snapshot all attachments in one batch, making versioning a lot simpler. When these events fire the item and its attachments have already been written to the database and I can focus on how to generate the snapshots &#8212; copying attachments back and forth between lists &#8212; and not worry about what the user actual did to the attachments from one version to the next.</p>
<pre class="prettyprint lang-cs">// Prerequisites:
// 1. Create a Document Library named ShadowLibrary on the same site as the list to version
// 2. Add a row named CustomVersion of type string to the list to version
public class ListAttachmentVersioningEventReceiver : SPItemEventReceiver {
    private const string CustomVersion = &quot;CustomVersion&quot;;
    private const string ShadowLibrary = &quot;ShadowLibrary&quot;;

    public override void ItemAdded(SPItemEventProperties properties) {
        base.ItemUpdated(properties);
        SetCustomVersionLabel(properties.ListItem);
        CreateSnapshot(properties);
    }

    public override void ItemUpdated(SPItemEventProperties properties) {
        base.ItemUpdated(properties);

        var item = properties.ListItem;
        if (RollbackHappened(item)) {
            RestoreSnapshot(properties);
            SetCustomVersionLabel(item);
            CreateSnapshot(properties);
        }
        else {
            CreateSnapshot(properties);
            SetCustomVersionLabel(item);
        }
    }

    private void CreateSnapshot(SPItemEventProperties properties) {
        using (var site = properties.OpenWeb()) {
            var item = properties.ListItem;
            var shadowLibrary = site.Lists[ShadowLibrary] as SPDocumentLibrary;
            var path = string.Format(&quot;Versions/{0}/{1}&quot;, item.ID, GetOfficialVersionLabel(item));
            var shadowFolder = CreateFolderPath(shadowLibrary, path);

            foreach (string fileName in item.Attachments) {
                SPFile existingFile = item.ParentList.ParentWeb.GetFile(item.Attachments.UrlPrefix + fileName);
                SPFile newFile = shadowFolder.Files.Add(fileName, existingFile.OpenBinaryStream());
                newFile.Item.Update();
            }
        }
    }

    private bool RollbackHappened(SPListItem item) {
        var culture = CultureInfo.InvariantCulture;
        var currentVersion = float.Parse(GetOfficialVersionLabel(item), culture);
        var lastVersion = float.Parse(GetCustomVersionLabel(item), culture);
        return currentVersion &gt; lastVersion + 1;
    }

    private void RestoreSnapshot(SPItemEventProperties properties) {
        var item = properties.ListItem;
        var restoreVersion = GetCustomVersionLabel(item);
        EventFiringEnabled = false;

        item.Attachments.Cast&lt;string&gt;().ToList().ForEach(attachment =&gt; item.Attachments.Delete(attachment));
        using (var site = properties.OpenWeb()) {
            var path = string.Format(&quot;Versions/{0}/{1}&quot;, item.ID, restoreVersion);
            var shadowLibrary = site.Lists[ShadowLibrary] as SPDocumentLibrary;
            var source = CreateFolderPath(shadowLibrary, path);

            foreach (SPFile file in source.Files)
                item.Attachments.Add(file.Name, file.OpenBinary());
        }

        item.SystemUpdate(false);
        EventFiringEnabled = true;
    }

    // can only get folder creation to work with Document Libraries
    private SPFolder CreateFolderPath(SPDocumentLibrary list, string path) {
        return CreateFolderPathRecursive(list.RootFolder, path.Split('/').ToList());
    }

    private SPFolder CreateFolderPathRecursive(SPFolder folder, IList&lt;string&gt; pathComponents) {
        if (pathComponents.Count == 0)
            return folder;

        SPFolder newFolder;
        try {
            newFolder = folder.SubFolders[pathComponents.First()];
        }
        catch (ArgumentException) {
            newFolder = folder.SubFolders.Add(pathComponents.First());
        }

        pathComponents.RemoveAt(0);
        return CreateFolderPathRecursive(newFolder, pathComponents);
    }

    private void SetCustomVersionLabel(SPListItem item) {
        EventFiringEnabled = false;
        item[CustomVersion] = GetOfficialVersionLabel(item);
        item.SystemUpdate(false);
        EventFiringEnabled = true;
    }

    private string GetCustomVersionLabel(SPItem item) { return item[CustomVersion] as string; }
    private string GetOfficialVersionLabel(SPListItem item) { return item.Versions[0].VersionLabel; }
}</pre>
<p>When a list item is saved, I take a snapshot of the attachments, storing them in a folder structure like {Id}/{VersionNumber}/{Attachments} in the shadow document library. When a list item is restored to a previous version, existing attachments are first deleted before the ones from the snapshot are added back in, creating a new version of the list item.</p>
<p>Restoring previous versions also has a counter-intuitive meaning in SharePoint. Suppose in one version of a list item, I store a key in the item’s property bag, then I’d expect the property bag values to be specific to this version. But behind the scenes restore seems to work by cloning the current version and then copying only the values of the fields from the restore version to the new one. In other words, I can’t use the item’s property bag to store version specific information, such as a version tag to detect when a restore has occurred. I also can&#8217;t use the Modified field because SharePoint sets it to the time of the restore. To carry over version information I have to create and maintain a field of my own. Hence the CustomVersion field on the list to version.</p>
<p>Remember that because the ItemUpdated and ItemAdded execute asynchronously, all the snapshotting logic executes on a background thread, after control has returned to the user. Should an error occur at this point, the user will never see it and the snapshot may be left in an incomplete state. On the other hand, this approach scales well and doesn’t have to be fast because no user is awaiting the result.</p>
<p>Lastly, there’s one place in SharePoint where the versioning abstraction leaks through. It’s in the list item version dialog which displays older versions and enables restore to any previous version. The dialog will always show the most recent attachments.</p>
<h4>Improvements</h4>
<p>I could use the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfile.etag.aspx">ETag</a> property of an SPFile object to implement a more efficient differential snapshotting algorithm that would conserve storage space. Compressing attachments before storing them in the shadow library might also be an option, although then I’d have to promote the ETag value to a shadow library field before compressing.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F17%2Fversioning-attachments-in-a-sharepoint-list-using-snapshotting%2F&amp;title=Versioning%20attachments%20in%20a%20SharePoint%20list%20using%20snapshotting" id="wpa2a_10"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/17/versioning-attachments-in-a-sharepoint-list-using-snapshotting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Handy SharePoint 2010 extension methods for list definitions</title>
		<link>http://www.bugfree.dk/blog/2011/11/15/handy-sharepoint-2010-extension-methods-for-list-definitions/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/15/handy-sharepoint-2010-extension-methods-for-list-definitions/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 05:59:18 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1068</guid>
		<description><![CDATA[A quick word on organizing extension methods: I usually collect them in an Extensions folder, appending Extensions to the name of class being extended and keeping with the one class per file convention. For brevity I’ve left out the using and the namespace part below. SPListCollection extensions In SharePoint 2010 the TryGetList method has been [...]]]></description>
			<content:encoded><![CDATA[<p>A quick word on organizing extension methods: I usually collect them in an Extensions folder, appending Extensions to the name of class being extended and keeping with the one class per file convention. For brevity I’ve left out the using and the namespace part below.</p>
<h4>SPListCollection extensions</h4>
<p>In SharePoint 2010 the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistcollection.trygetlist.aspx">TryGetList</a> method has been added to the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistcollection.aspx">SPListCollection</a> class. The method returns either an <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.aspx">SPList</a> instance matching the display name or null. Oftentimes, however, you want to do a lookup based on the internal name. Here’s an extension method that adheres to the semantics of TryGetList, but using the internal name. It relies on the fact that the RootFolder property of a list is actually its internal name:</p>
<pre class="prettyprint lang-cs">// definition
public static class SPListCollectionExtensions {
    public static SPList TryGetListByInternalName(this SPListCollection lists, string internalName) {
        return (from SPList l in lists
            where l.RootFolder.Name == internalName
            select l).SingleOrDefault();
    }
}

// use
if (site.Lists.TryGetListByInternalName(internalListName) == null)
   // list not found</pre>
<h4>SPFieldCollection extensions</h4>
<p>Using the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfieldcollection.createnewfield.aspx">CreateNewField</a> method of the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfieldcollection.aspx">SPFieldCollection</a> you can add new fields to a list. The particular annoying aspect of this method, however, is that when you want to continue working with its result, oftentimes you have to cast it to one of the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfield.aspx">SPField</a> subclasses. But since the <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfieldtype.aspx">SPFieldType</a>, provided as one of the arguments to CreateNewField, closely relates to the actual SPField return type, an extension method is able to do the casting. This’ll expose mismatches at compile time instead of at runtime.</p>
<p>All it takes is for us to map out the relation between SPField and SPFieldType:</p>
<pre class="prettyprint lang-cs">// definition
public static class SPFieldCollectionExtensions {
    public static TSPField CreateField&lt;TSPField&gt;(this SPFieldCollection fields,
            string internalName, string displayName) where TSPField : SPField {
        var spFieldToFieldType = new Dictionary&lt;Type, SPFieldType&gt; {
            { typeof(SPFieldDateTime), SPFieldType.DateTime },
            { typeof(SPFieldNumber), SPFieldType.Number },
            { typeof(SPFieldUser), SPFieldType.User },
            { typeof(SPFieldBoolean), SPFieldType.Boolean },
            { typeof(SPFieldMultiLineText), SPFieldType.Note },
            { typeof(SPFieldText), SPFieldType.Text }
        };

        var fieldType = spFieldToFieldType[typeof(TSPField)];
        var list = fields.List;
        var field = list.Fields[list.Fields.Add(internalName, fieldType, false)];
        field.Title = displayName;
        field.Update();
        return field as TSPField;
    }
}

// use
l.Fields.CreateField&lt;SPFieldBoolean&gt;(internalName, &quot;displayName&quot;);</pre>
<p>Taking the CreateField extension method one step further, oftentimes you want to set properties besides internal name and display name. For that purpose I’ve defined a CreateField method that accepts an Action&lt;TField&gt;. This allows you to reuse common property settings across fields for brevity and consistency while at the same time maintaining strong typing.</p>
<pre class="prettyprint lang-cs">// definition
public static TSPField CreateField&lt;TSPField&gt;(this SPFieldCollection fields,
        string internalName, string displayName,
        Action&lt;TSPField&gt; setAdditionalProperties) where TSPField : SPField {
    var newField = CreateField&lt;TSPField&gt;(fields, internalName, displayName);
    setAdditionalProperties(newField);
    newField.Update();
    return newField;
}

// use
public static Action&lt;SPFieldMultiLineText&gt; RichTextProperties = f =&gt; {
    f.RichText = true;
    f.RichTextMode = SPRichTextMode.FullHtml;
};

l.Fields.CreateField&lt;SPFieldBoolean&gt;(internalName, &quot;displayName&quot;, f =&gt; f.Required = true);
l.Fields.CreateField(internalName, &quot;displayName&quot;, RichTextProperties);</pre>
<p>With the Comment field, you can leave out the type argument because the compiler infers it based on the type of the Action delegate.</p>
<p>Similar to CreateField, I’ve defined two additional extension methods for creating lookup fields:</p>
<pre class="prettyprint lang-cs">// definition
public static TSPField CreateLookup&lt;TSPField&gt;(this SPFieldCollection fields,
        string lookupListName, string internalName,
        string displayName) where TSPField : SPFieldLookup {
    var currentList = fields.List;
    var lookupList = currentList.ParentWeb.Lists.TryGetListByInternalName(lookupListName);
    var newField = currentList.Fields[currentList.Fields.AddLookup(internalName, lookupList.ID, false)];
    newField.Title = displayName;
    newField.Update();
    return newField as TSPField;
}

public static TSPField CreateLookup&lt;TSPField&gt;(this SPFieldCollection fields,
        string lookupListName, string internalName, string displayName,
        Action&lt;TSPField&gt; setAdditionalProperties) where TSPField : SPFieldLookup {
    var newField = CreateLookup&lt;TSPField&gt;(fields, lookupListName, internalName, displayName);
    setAdditionalProperties(newField);
    newField.Update();
    return newField;
}

// use
l.Fields.CreateLookup&lt;SPFieldLookup&gt;(lookupListName, internalName, displayName, f =&gt; f.AllowMultipleValues = true);</pre>
<p>These extension methods makes using the SharePoint API more type-safe and concise, and defining lists using these methods and the <a href="http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern/">template approach</a> saves me from writing a lot of repetitive code.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F15%2Fhandy-sharepoint-2010-extension-methods-for-list-definitions%2F&amp;title=Handy%20SharePoint%202010%20extension%20methods%20for%20list%20definitions" id="wpa2a_12"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/15/handy-sharepoint-2010-extension-methods-for-list-definitions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A table-driven approach to creating SharePoint sites with PowerShell</title>
		<link>http://www.bugfree.dk/blog/2011/11/13/a-table-driven-approach-to-creating-sharepoint-sites-with-powershell/</link>
		<comments>http://www.bugfree.dk/blog/2011/11/13/a-table-driven-approach-to-creating-sharepoint-sites-with-powershell/#comments</comments>
		<pubDate>Sun, 13 Nov 2011 15:31:29 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Powershell]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1069</guid>
		<description><![CDATA[While cleaning up some PowerShell installations scripts that I wrote some time ago, I come across the following piece of code (modified slightly for anonymity) for creating a hierarchy of SharePoint sites and setting the locale for a subset of the sites. It works but it sure doesn’t adhere to the DRY principle. New-SPWeb -url [...]]]></description>
			<content:encoded><![CDATA[<p>While cleaning up some PowerShell installations scripts that I wrote some time ago, I come across the following piece of code (modified slightly for anonymity) for creating a hierarchy of SharePoint sites and setting the locale for a subset of the sites. It works but it sure doesn’t adhere to the DRY principle.</p>
<pre class="prettyprint">New-SPWeb -url $base_url -addtoquicklaunch -template "STS#1" -name "Base"
New-SPWeb -url $base_url/Dk -addtoquicklaunch -template "STS#1" -name "Dk"
New-SPWeb -url $base_url/Uk -addtoquicklaunch -template "STS#1" -name "Uk"
New-SPWeb -url $base_url/Dk/BusinessUnit1 -addtoquicklaunch -template "STS#1" -name "BusinessUnit1"
New-SPWeb -url $base_url/Dk/BusinessUnit2 -addtoquicklaunch -template "STS#1" -name "BusinessUnit2"
New-SPWeb -url $base_url/Uk/BusinessUnit1 -addtoquicklaunch -template "STS#1" -name "BusinessUnit1"
New-SPWeb -url $base_url/Uk/BusinessUnit2 -addtoquicklaunch -template "STS#1" -name "BusinessUnit2"

$dk = Get-SPWeb $base_url/Dk
$dkBusinessUnit1 = Get-SPWeb $base_url/Dk/BusinessUnit1
$dkBusinessUnit2 = Get-SPWeb $base_url/Dk/BusinessUnit2

$locale = [System.Globalization.CultureInfo]::CreateSpecificCulture("da-DK")
$dk.Locale = $locale
$dk.Update()

$dkBusinessUnit1.Locale = $locale
$dkBusinessUnit1.Update()

$dkBusinessUnit2.Locale = $locale
$dkBusinessUnit2.Update()</pre>
<p>How can we reduce this repetition? Well, it repeats because we’ve made the common mistake of mixing logic with data. One way to separate the two is using a table-driven approach, i.e., extract the varying parts, the data, into a table and rewrite the logic so it’s parameterized by the table. After some trial and error with PowerShell here’s the code I ended up with:</p>
<pre class="prettyprint">$sites = @( @("", "Base"),
            @("Dk", "Dk", "da-DK"),
            @("Uk", "Uk"),
            @("Dk/BusinessUnit1", "BusinessUnit1", "da-DK"),
            @("Dk/BusinessUnit2", "BusinessUnit2", "da-DK"),
            @("Uk/BusinessUnit1", "BusinessUnit1"),
            @("Uk/BusinessUnit2", "BusinessUnit2") )

$sites | foreach {
  $url, $title, $culture = $_
  $newSite = New-SPWeb -url "$base_url/$url" -addtoquicklaunch -template "STS#1" -name $title

  if ($culture -ne "") {
    $locale = [System.Globalization.CultureInfo]::CreateSpecificCulture($culture)
    $newSite.Locale = $locale
    $newSite.Update()
  }
}</pre>
<p>So far so good. The un-installation part of the script, however, follows the same pattern of repetition:</p>
<pre class="prettyprint">Remove-SPWeb -identity $base_url/Uk/BusinessUnit2 -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url/Uk/BusinessUnit1 -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url/Dk/BusinessUnit2 -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url/Dk/BusinessUnit1 -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url/Dk -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url/Uk -confirm:$false -ErrorAction SilentlyContinue
Remove-SPWeb -identity $base_url -confirm:$false</pre>
<p>But now that we have the table of sites at hand, we can easily make the site removal table-driven as well:</p>
<pre class="prettyprint">function Reverse($array) {
  $clone = $array.Clone()
  [Array]::Reverse($clone)
  $clone
}

Reverse($sites) | foreach {
  $url = $_[0]
  Remove-SPWeb -identity "$base_url/$url" -confirm:$false -ErrorAction SilentlyContinue
}</pre>
<p>I’m sure the code could be written more elegantly, but given my working knowledge of PowerShell I’m satisfied with the result. I especially like the functional programming style.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2011%2F11%2F13%2Fa-table-driven-approach-to-creating-sharepoint-sites-with-powershell%2F&amp;title=A%20table-driven%20approach%20to%20creating%20SharePoint%20sites%20with%20PowerShell" id="wpa2a_14"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2011/11/13/a-table-driven-approach-to-creating-sharepoint-sites-with-powershell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Essential requirements for a developer automation tool</title>
		<link>http://www.bugfree.dk/blog/2010/09/26/essential-requirements-for-a-developer-automation-tool/</link>
		<comments>http://www.bugfree.dk/blog/2010/09/26/essential-requirements-for-a-developer-automation-tool/#comments</comments>
		<pubDate>Sun, 26 Sep 2010 11:19:26 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Tool]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1058</guid>
		<description><![CDATA[Developer automation is a subject that I&#8217;ve always felt passionate about. Unit testing may be the most common example, but other tasks may include check-out of source code, build, deploy, setup, and warm-up of an application. I may even want one system rule them all and have the same automation drive continuous integration. Whatever the [...]]]></description>
			<content:encoded><![CDATA[<p>Developer automation is a subject that I&#8217;ve always felt passionate about. Unit testing may be the most common example, but other tasks may include check-out of source code, build, deploy, setup, and warm-up of an application. I may even want <a href="http://simpleprogrammer.com/2010/09/03/one-build-to-rule-them-all">one system rule them all</a> and have the same automation drive <a href="http://martinfowler.com/articles/continuousIntegration.html">continuous integration</a>. Whatever the use, to fully reap the benefits of automation, a developer should master at least one automation tool the same way he masters other developer tools. This and later posts capture my experiences with a few such automation tools centered around Windows and .NET, starting with why the ubiquitous <a href="http://en.wikipedia.org/wiki/Batch_files">batch file</a> is best avoided and how to characterize better solutions in terms of it.</p>
<p>Although Visual Studio, in tandem with the <a href="http://en.wikipedia.org/wiki/Msbuild">MSBuild engine</a>, generally takes good care of compilation, I rarely want to rely on it solely. Instead, I’d prefer that any developer task be easily run from the command-line. This ensures that no magic is going on, that the task is kept simple and flexibility, and that it doesn’t rely on Visual Studio to work. The challenge, however, is which of the many tools available to pick. It must be one that’s flexible enough to meet most requirements with relative ease or the automation will likely not be a valid documentation medium in itself.</p>
<h4>Why not to use Windows batch files</h4>
<p>As a general example, consider the deployment of a <a href="http://www.bugfree.dk/blog/2010/03/31/getting-started-with-sharepoint-presentation">SharePoint 2007 solution</a>. With SharePoint a good deal more than compiling is needed to bring new functionality into a SharePoint installation. Whereas Visual Studio and MSBuild may still compile the code and <a href="http://wspbuilder.codeplex.com">WSPBuilder</a> create the WSP installation package, both from within Visual Studio and from the command-line, getting everything setup cries for automation, even locally. A common approach (possibly inspired by <a href="http://www.amazon.com/Microsoft-Windows-SharePoint-Services-Developer/dp/0735623201/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1285960936&amp;sr=8-1">popular</a> SharePoint 2007 literature) is that of the batch file applying various operations to a WSP. For the sake of brevity, I&#8217;ve kept the example short, but imagine extending it with a check-out source code task, a compilation task, a WSPBuilder task, and a feature deactivation and activation task, and possibly a warm-up task. Add to this a master script that orchestrate the whole thing. In the end, I’d end up with scripts that become increasingly harder to maintain as they grow in number and size.</p>
<pre class="prettyprint lang-sh">    @set STSADM=&quot;c:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm&quot;

    if &quot;%1&quot; == &quot;uninstall&quot; goto uninstall
    if &quot;%1&quot; == &quot;install&quot; goto install
    if &quot;%1&quot; == &quot;&quot; goto reinstall

    :uninstall
        %STSADM% -o retractsolution -name Foo.wsp -immediate
        %STSADM% -o execadmsvcjobs
        %STSADM% -o deletesolution -name Foo.wsp -override
        goto end

    :install
        %STSADM% -o addsolution -filename Foo.wsp
        %STSADM% -o deploysolution -name Foo.wsp -immediate -allowGacDeployment -force
        %STSADM% -o execadmsvcjobs
        goto end

    :reinstall
        call Foo uninstall
        call Foo install
        goto end

    :end</pre>
<p>Still, because of the ubiquitous nature of command.com and cmd.exe, the batch file interpreters, batch files are everywhere. Regardless that the technology is a left-over from the days of MS DOS and haven&#8217;t evolved much since. Not only are the branching and looping constructs limited, so are the <a href="http://technet.microsoft.com/en-us/library/dd560674(WS.10).aspx">available commands</a>. Suppose I want to find out if a command was indeed successful. This turns out to be really hard when all I have to work with is the <a href="http://en.wikipedia.org/wiki/Errorlevel">errorlevel</a> of the most recently executed command. Assuming the command adheres to the errorlevel convention, for the script to fail as early and as close to the real error as possible, I’d have to inspect the property after each command, causing the batch file to grow quite verbose. Sadly, batch files lack the equivalent of <a href="http://www.davidpashley.com/articles/writing-robust-shell-scripts.html#id2399158">set -o errexit</a> of <a href="http://en.wikipedia.org/wiki/Bash_(Unix_shell)">Bash</a>, where the interpreter checks for success after each command and aborts immediately on error. Relying solely on the errorlevel is oftentimes insufficient anyway. To determine success, I’d typically have to parse actual command output or inspect some system property by downloading additional commands or building my own.</p>
<h4>Essential vs. incidental requirements</h4>
<p>Unless I plan to sit idle and stare at the screen and be a human error detector while the batch file run, I think it’s safe to say that it’s mostly unsuitable for developer automation. Hence in late 2005 I <a href="http://www.bugfree.dk/blog/2006/01/04/being-a-functional-pythonian">rolled my own automation tool in Python</a>. With Python or Ruby or a similar dynamic language acting as the glue that ties everything together, almost any task can be automated in a robust way. Of course, I could also automate with a static language like C# (it&#8217;s surprisingly common). But for script-like tasks, I don’t particularly fancy the long cycle of editing source code in Visual Studio, compiling it, deploying it, and having a hard time debugging it in environment without Visual Studio. A dynamic language, on the other hand, short-circuits the development cycle and allows for interactive programming through a <a href="http://en.wikipedia.org/wiki/REPL">REPL</a>.</p>
<p>With a dynamic language that interacts with .NET, such as <a href="http://en.wikipedia.org/wiki/Ironpython">IronPython</a>, <a href="http://en.wikipedia.org/wiki/IronRuby">IronRuby</a>, or <a href="http://en.wikipedia.org/wiki/Powershell">Powershell</a>, possibly with supporting DSLs like <a href="http://www.blueskyonmars.com/projects/paver">Paver</a>, <a href="http://en.wikipedia.org/wiki/Rake_(software)">Rake</a>, or <a href="http://en.wikipedia.org/wiki/Psake">psake</a> on top, the need for writing custom commands to interact with the operating system or the application almost vanishes. The question, then, is which of the dynamic languages to go with when at their technical core they’re so much alike. Besides sharing the concept of a REPL, the notion of a tuple, a list, a map, and operations on each are baked into their syntax, making code quite terse. It even makes it convenient to express any configuration in the language itself and not in XML where I’d first have to come up with a schema, and then create an instance of it before parsing it. On Windows, however, Powershell is gradually becoming the next ubiquitous interpreter, with applications shipping with cmdlets, whereas IronPython or IronRuby is a separate download.</p>
<h4>Conclusion</h4>
<p>No matter the tool, what I end up doing is defining tasks, form dependencies between tasks, and have the tool execute tasks in an order that satisfies their dependencies. As the tool traverses the dependency graph and executes tasks, it’s up to each task to detect success, and up to the tool to report on progress. A good tool is therefore characterized by the ease with which I can express these things, the available language constructs, the ease of debugging, and the tool’s ability to converse in foreign languages.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F09%2F26%2Fessential-requirements-for-a-developer-automation-tool%2F&amp;title=Essential%20requirements%20for%20a%20developer%20automation%20tool" id="wpa2a_16"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/09/26/essential-requirements-for-a-developer-automation-tool/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The given-expect testing pattern</title>
		<link>http://www.bugfree.dk/blog/2010/04/25/the-given-expect-testing-pattern/</link>
		<comments>http://www.bugfree.dk/blog/2010/04/25/the-given-expect-testing-pattern/#comments</comments>
		<pubDate>Sun, 25 Apr 2010 20:31:58 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1047</guid>
		<description><![CDATA[I was watching Brett Schuchert’s TDD screencast on implementing the shunting yard algorithm in C#. In it Brett builds up his tests in a style I hadn’t come across before. Each test is expressed as a given-expect statement. A pattern that is particularly useful in situations in which a class has a main method that [...]]]></description>
			<content:encoded><![CDATA[<p>I was watching <a href="http://schuchert.wikispaces.com">Brett Schuchert</a>’s TDD <a href="http://vimeo.com/album/210446">screencast</a> on implementing the <a href="http://en.wikipedia.org/wiki/Shunting-yard_algorithm">shunting yard algorithm</a> in C#. In it Brett builds up his tests in a style I hadn’t come across before. Each test is expressed as a given-expect statement. A pattern that is particularly useful in situations in which a class has a main method that accepts an open-ended number of dissimilar inputs.</p>
<p>I found the given-expect pattern useful in testing a piece of code that I was working on this week. I was refactoring and adding tests around an ASP.NET control adapter that makes SharePoint 2007 pages more XHTML compliant. I wanted to reuse the transformations outside the control adapter and hence ended up moving the transformation logic to a new class. It accepts possibly malformed HTML and relies on heuristics of the <a href="http://htmlagilitypack.codeplex.com">HTML Agility Pack</a> to build a DOM off of it. I can then query the DOM, looking for known violations, and patch them before returning XHTML to the caller.</p>
<pre class="prettyprint lang-cs">    public class HtmlToXHtmlTransformer {
        private readonly HtmlDocument _document;

        public HtmlToXHtmlTransformer(string html) {
            _document = new HtmlDocument();
            _document.DetectEncoding(new StringReader(html));
            _document.LoadHtml(html);
        }

        private void Transform(string xpath, Action&lt;HtmlNode&gt; nodeMatch) {
            var nodes = _document.DocumentNode.SelectNodes(xpath);
            if (nodes != null)
                foreach (var node in nodes)
                    nodeMatch.Invoke(node);
        }

        private void FixDuplicateBorderAttributeOnSPGridViewControl() {
            Transform(&quot;//table[count(@border)=2]&quot;, node =&gt; node.Attributes.Remove(&quot;border&quot;));
        }

        public string Transform() {
            FixDuplicateBorderAttributeOnSPGridViewControl();
            _document.OptionWriteEmptyNodes = true;
            return _document.DocumentNode.WriteTo();
        }
    }</pre>
<p>The complete HtmlToXHtmlTransformer collects a dozen transformations. Its Transform method is what we want to call with various HTML fragments to verify that they come out as XHTML. For this purpose, we might do the tests as <a href="http://msdn.microsoft.com/en-us/library/ms182527.aspx">Visual Studio data-driven tests</a> that read their input and output from a text file. But in most cases I prefer traditional tests, so I can describe the purpose of a test with a descriptive method name and possibly a comment.</p>
<pre class="prettyprint lang-cs">
    [TestClass]
    public class HtmlToXHtmlTransformerTest {
        private string _result;

        [TestMethod]
        public void Must_selfclose_nodes_when_allowed() {
            Given(&quot;&lt;br&gt;&quot;);
            Expect(&quot;&lt;br /&gt;&quot;);
        }

        [TestMethod]
        public void Must_remove_duplicate_border_on_SPGridView_control {
            Given(@&quot;&lt;table border=&quot;&quot;0&quot;&quot; border=&quot;&quot;0&quot;&quot;&gt;&lt;/table&gt;&quot;);
            Expect(@&quot;&lt;table border=&quot;&quot;0&quot;&quot;&gt;&lt;/table&gt;&quot;);
        }

        private void Expect(string xhtml) {
            Assert.AreEqual(xhtml, _result);
        }

        private void Given(string html) {
            var transformer = new HtmlToXHtmlTransformer(html);
            _result = transformer.Transform();
        }
    }</pre>
<p>I particularly like the clarity of the given-expect pattern and find that for a reasonable number of tests it’s a viable alternative to data-driven test. I do, however, recognize the value of data-driven tests in situations where a non-developer wants to test a class. Though at the unit test level I’ve never experienced this. It’s more characteristic of <a href="http://en.wikipedia.org/wiki/FitNesse">FitNesse for acceptance testing</a>. However you unit test, just make sure your tests run with a minimum of effort on your part and that they run fast.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F04%2F25%2Fthe-given-expect-testing-pattern%2F&amp;title=The%20given-expect%20testing%20pattern" id="wpa2a_18"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/04/25/the-given-expect-testing-pattern/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SharePoint Saturday EMEA virtual conference</title>
		<link>http://www.bugfree.dk/blog/2010/04/04/sharepoint-saturday-emea-virtual-conference/</link>
		<comments>http://www.bugfree.dk/blog/2010/04/04/sharepoint-saturday-emea-virtual-conference/#comments</comments>
		<pubDate>Sun, 04 Apr 2010 18:08:00 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Conference]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1042</guid>
		<description><![CDATA[Back in January, I attended the one-day virtual SharePoint Saturday EMEA conference. It was my first virtual conference so I was excited to see how it would work out. Presenting through Office Live Meeting and interacting with the audience through text-only is definitely a challenge compared to live presentations. But I’d say it went well [...]]]></description>
			<content:encoded><![CDATA[<p>Back in January, I attended the one-day virtual <a href="http://www.sharepointsaturday.org/emea/default.aspx">SharePoint Saturday EMEA conference</a>. It was my first virtual conference so I was excited to see how it would work out. Presenting through Office Live Meeting and interacting with the audience through text-only is definitely a challenge compared to live presentations. But I’d say it went well with 50-60 attendees at each of the three parallel tracks.</p>
<p>Here’re the talks that I attended, all <a href="http://www.endusersharepoint.com/2010/02/19/sharepoint-saturday-emea-20-hours-of-recordings-available">recorded and available with slides</a>.</p>
<h4>SharePoint 2010 Planning and Best Practice Approaches to Upgrade</h4>
<p>Upgrading to SharePoint 2010, you should first establish a copy of your existing environment on the latest patch level. Then run the stsadm command with the new PreUpgradeChecker option. Make sure your environment has no unused features, site templates, and so on, and identify everything that has changed from out-of-the-box by running a tool like <a href="http://winmerge.org">WinMerge</a> on the 12 hive. Also, assert that no pages has been ghosted, and don’t attempt to upgrade your SharePoint 2007 master page. Start with the 2010 ones and add in your 2007 modifications. SharePoint 2010 ships with both 2007 and 2010 master pages, but SharePoint 2007 and 2010 isn’t binary compatible. </p>
<p>Make sure all <a href="http://blogs.msdn.com/sharepoint/archive/2009/05/07/announcing-sharepoint-server-2010-preliminary-system-requirements.aspx">hardware requirements</a> are satisfied: 8 GB RAM at the minimum on the Windows 2008 servers running SharePoint and MS SQL Server. On the client you need Internet Explorer 7 or 8 or Firefox 3.x to author content. Internet Explorer 6 isn’t supported. Not even with a degraded reader experience. The <a href="http://msdn.microsoft.com/en-us/library/ee554869%28office.14%29.aspx">SharePoint 2010 development environment</a> should be setup with Visual Studio 2010 on Windows Vista or Windows 7 in order to compile, debug, build, and deploy right out of Visual Studio 2010. </p>
<h4>Understanding, using, and customizing PowerShell for a SharePoint 2010 Environment</h4>
<p>This talk started with some PowerShell history and basics. PowerShell is made up of a shell that executes commands and an integrated scripting environment for development. .NET compiled code, called cmdlets, are the executable units combined using the PowerShell pipeline. The PowerShell language itself is dynamic and loosely typed, so being able to express yourself tops performance. Scripts may be compiled and deployed as a SnapIn, consisting of compiled DLLs and registry updates, or as a module using xcopy deployment.</p>
<p>SharePoint 2010 ships with 650 cmdlets, and its own base class for writing additional SharePoint cmdlets.</p>
<h4>Design and Manage Site Collections in SharePoint 2010</h4>
<p>By default every single site collection within a web application goes into one rapidly growing database (think about users migrating from file shares to site collections). Such a large database takes time to backup and restore. Hence, with SharePoint 2010, consider partitioning site collections into their own databases from the beginning. After a database is created, map it to one and only one site collection. Then, instead of putting a size limit on the web application, put it on the site collection itself.</p>
<p>In SharePoint 2007 you had to create multiple Shared Service Providers (SSP) if site collections had different needs or you didn’t want a site collection to access parts of an existing SSP. With SharePoint 2010, application services can now be shared between site collections.</p>
<p>With sandbox solutions, the solution is deployed to the database hosting the site, rather than to front-end servers. This makes it easier to deploy code, but the code is limited in what it can do, and you may have to set resource quotas across the site collection.</p>
<h4>SharePoint 2010, Getting Ready</h4>
<p>This talk provided an overview of SharePoint 2010. WSS 3.0 becomes SharePoint Foundation 2010 and MOSS 2007 becomes SharePoint Server 2010. Business Connectivity Services (BCS) are no longer part of the server edition, but has been moved to Foundation. A lot more services have been added, like state service, usage and health service, and Visio graphics service. Generally, with all the improvements to deployment and upgrade with PowerShell and the addition of multi-tenancy for the SSP, SharePoint 2010 is better in a hosting scenario. </p>
<p>The web user interface has been made more Office-like with the addition of the ribbon and the use of AJAX. In document libraries you can create document sets as a way to relate documents to each other and have versioning and workflow follow every document in the set. Through the BCS, you can expose external data as native SharePoint lists with full CRUD capabilities.</p>
<h4>SharePoint 2010 Development Tips and Tricks</h4>
<p>The focus of the first part this talk is on the SharePoint 2010 Foundation features. Instead of developing against the web services or the object model, you can use the new managed client object model. This way, you can work against SharePoint from .NET code, from a Silverlight application, or from JavaScript. Behind the scenes, the client object model works against a WCF service running on the SharePoint server, which talks to the server object model on the server, and returns JSON to the client. </p>
<p>The second part of this talk is about sandbox solutions. This feature provides site collection users with the ability to upload and deploy WSPs. Finally, the third part of the talk is about the fluid integration model, which solves the problem of accessing cross-domain resources, e.g., having a Silverlight application access information on a SharePoint server on a different domain. </p>
<h4>Installing and Configuring SharePoint Server 2010 in a Virtual Environment</h4>
<p>This talk recommends that everyone read the MS whitepaper on <a href="http://download.microsoft.com/download/D/A/8/DA82C84A-1C3F-418A-BCC7-8A38CBBC1935/Virtualization_of_SharePoint_Products_and_Technologies_White_Paper_-_final1.docx">Virtualization of Microsoft SharePoint Products and Technologies</a>. Configuring a development environment, the dilemma is weather to create one virtual machine hosting everything or one virtual machine for the MS SQL Server, the Active Directory, and the SharePoint server each. The presenter suggests a middle ground. Still, it’s important to create a number of service accounts and use them in your development environment rather than running everything as administrator.</p>
<p>The SharePoint 2010 installer comes with a prerequisite installer that goes onto the web and downloads required software. After that, you can run the SharePoint server installer. Here you can choose between Standalone and Server farm, but always pick server farm. Standalone should only be used for demo purposes.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F04%2F04%2Fsharepoint-saturday-emea-virtual-conference%2F&amp;title=SharePoint%20Saturday%20EMEA%20virtual%20conference" id="wpa2a_20"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/04/04/sharepoint-saturday-emea-virtual-conference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting started with SharePoint presentation</title>
		<link>http://www.bugfree.dk/blog/2010/03/31/getting-started-with-sharepoint-presentation/</link>
		<comments>http://www.bugfree.dk/blog/2010/03/31/getting-started-with-sharepoint-presentation/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 11:31:05 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[Presentation]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2010/03/31/getting-started-with-sharepoint-development/</guid>
		<description><![CDATA[Download slides from the presentation. Last week at work I did a 45 minutes presentation on how to get started with SharePoint development. Instead of the usual presentation on the technical merits of SharePoint, my focus was more on the change in mindset required coming from ASP.NET. For even though ASP.NET is a cornerstone of [...]]]></description>
			<content:encoded><![CDATA[<p>Download <a href="http://www.bugfree.dk/blog/wp-content/uploads/2010/03/GettingStartedWithSharePoint.pdf">slides</a> from the presentation.</p>
<p>Last week at work I did a 45 minutes presentation on how to get started with SharePoint development. Instead of the usual presentation on the technical merits of SharePoint, my focus was more on the change in mindset required coming from ASP.NET. For even though ASP.NET is a cornerstone of SharePoint, SharePoint is so much more. Not to mention different.</p>
<h4>History makes a difference</h4>
<p>SharePoint is a <a href="http://blogs.msdn.com/joelo/archive/2007/12/28/7-years-of-sharepoint-a-history-lesson.aspx">long-evolving</a> product, dating back to <a href="http://www.joiningdots.net/blog/2006/08/sharepoint-history.html">the late nineties</a>. From its <a href="http://blogs.msdn.com/sharepoint/archive/2009/10/05/sharepoint-history.aspx">inception and up till now</a> new technologies have replaced old ones, APIs have emerged and died, product teams have merged, and Microsoft have bought and integrated other companies’ products into SharePoint. At the same time SharePoint has become the fastest growing server product in Microsoft history. All of this inevitably leaves its marks on the APIs, which aren’t as consistent and defect free as we’re used to with the .NET framework.</p>
<h4>Provisioning is the magic sauce</h4>
<p>What truly makes SharePoint development different from ASP.NET is the notion of provisioning. With ASP.NET you create a bunch of ASPX files, organize them in a static file structure, and deploy them to a server. With SharePoint, the structure emerges over time as SharePoint or the user creates instances of templates: sites from site templates, lists from list templates, pages from page templates, and so forth. From a developer’s perspective the challenge isn’t the instance creation in itself. It’s that SharePoint encourages users to not only dynamically evolve the structure, but also to modify the instances, severing their definition from the template. While it empowers users, it also makes it challenging to programmatically evolve the structure.</p>
<p>Developing with SharePoint is about creating templates and components for SharePoint or the user to compose a site of. To make this composition work, SharePoint imposes constraints on what can be done and how. While any constraint may at times be perceived as a hindrance, accepting it is what guarantees that a components will play nicely with others. These pieces of functionality are then packaged as features and added to a WSP installation file for deployment to SharePoint. Features may then be activated, making their functionality available to a site. Or deactivated and the WSP uninstalled.</p>
<h4>Why learn SharePoint</h4>
<p>By the end of the day, no doubt SharePoint is more challenging to work with than ASP.NET. Not acknowledging its history makes many ASP.NET developers so frustrated that they’ll never again want to work with SharePoint. Coming from ASP.NET I can understand why. At times SharePoint isn’t as smooth and evolved as ASP.NET. But knowing what to expect takes the worst of the frustration. And once you learn to leverage the power of SharePoint, you can build applications without writing a lot of plumping code. To a large extend the architecture is given, leaving you with the opportunity to fill in the blanks.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F03%2F31%2Fgetting-started-with-sharepoint-presentation%2F&amp;title=Getting%20started%20with%20SharePoint%20presentation" id="wpa2a_22"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/03/31/getting-started-with-sharepoint-presentation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SharePoint list access using the Repository pattern</title>
		<link>http://www.bugfree.dk/blog/2010/01/18/sharepoint-list-access-using-the-repository-pattern/</link>
		<comments>http://www.bugfree.dk/blog/2010/01/18/sharepoint-list-access-using-the-repository-pattern/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 20:11:58 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Pattern]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1040</guid>
		<description><![CDATA[(Download code here. See related post on SharePoint list definition using the Template pattern) Maybe it’s that the SharePoint API is hard to use. Maybe it’s that coding against SharePoint is about making smaller additions here and there. Maybe it’s that the Patterns &#38; Practices SharePoint Guidance isn’t widely known. Whatever the reason, developing for [...]]]></description>
			<content:encoded><![CDATA[<p>(Download code <a href="http://www.bugfree.dk/blog/wp-content/uploads/2010/01/SharePointTemplatePatternRepositoryPattern.zip">here</a>. See related post on <a href="http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern/">SharePoint list definition using the Template pattern</a>)</p>
<p>Maybe it’s that the SharePoint API is hard to use. Maybe it’s that coding against SharePoint is about making smaller additions here and there. Maybe it’s that the <a href="http://spg.codeplex.com">Patterns &amp; Practices SharePoint Guidance</a> isn’t widely known. Whatever the reason, developing for SharePoint requires equal attention to the separation of presentation, business, and data access code. Hence, starting with data access, we may want to create a repository and route queries through it (the SharePoint Guidance outlines a <a href="http://msdn.microsoft.com/en-us/library/ee413961.aspx">more sophisticated</a> implementation than the one below):</p>
<pre class="prettyprint lang-cs">    [TestClass]
    public class EmployeesRepositoryTest {
        private SPSite _siteCollection;
        private SPWeb _site;
        private EmployeesRepository _repository;

        private readonly Employee _duffyDuck = new Employee {
            Id = 1000, Name = &quot;Duffy Duck&quot;, HireDate = new DateTime(2009, 12, 1),
            Remarks = &quot;Looks like a duck, quacks like a duck, probably is a duck&quot;
        };
        private readonly Employee _porkyPig = new Employee {
            Id = 1001, Name = &quot;Porky Pig&quot;, HireDate = new DateTime(2010, 2, 1)
        };
        private readonly Employee _sylvesterTheCat = new Employee {
            Id = 1002, Name = &quot;Sylvester the Cat&quot;, HireDate = new DateTime(2010, 3, 1)
        };
        private readonly Employee _bugsBunny = new Employee {
            Id = 1100, Name = &quot;Bugs Bunny&quot;, HireDate = new DateTime(2010, 1, 1)
        };

        public void AddEmployees() {
            _repository.AddEmployee(_site, _duffyDuck);
            _repository.AddEmployee(_site, _porkyPig);
            _repository.AddEmployee(_site, _sylvesterTheCat);
        }

        public void ClearEmployees() {
            var definition = new EmployeesDefinition();
            var employees = _site.Lists[definition.ListName];
            while (employees.Items.Count &gt; 0)
                employees.Items.Delete(0);
        }

        [TestInitialize]
        public void Initialize() {
            _siteCollection = new SPSite(&quot;http://localhost&quot;);
            _site = _siteCollection.OpenWeb(&quot;/&quot;);
            _repository = new EmployeesRepository();
            ClearEmployees();
            AddEmployees();
        }

        [TestCleanup]
        public void Cleanup() {
            _site.Dispose();
            _siteCollection.Dispose();
        }

        [TestMethod]
        public void AddEmployee_should_add_valid_employee() {
            _repository.AddEmployee(_site, _bugsBunny);
            var e = _repository.GetEmployeeById(_site, _bugsBunny.Id);
            Assert.AreEqual(_bugsBunny.Id, e.Id);
            Assert.AreEqual(_bugsBunny.Name, e.Name);
            Assert.AreEqual(_bugsBunny.HireDate, e.HireDate);
            Assert.AreEqual(_bugsBunny.Remarks, e.Remarks);
        }

        [TestMethod]
        public void GetEmployeesHiredBetween_should_return_2010_hires() {
            var from = new DateTime(2010, 1, 1);
            var to = new DateTime(2010, 12, 31);
            var employees = _repository.GetEmployeesHiredBetween(_site, from, to);
            Assert.AreEqual(2, employees.Count);
            Assert.AreEqual(_porkyPig.Id, employees[0].Id);
            Assert.AreEqual(_sylvesterTheCat.Id, employees[1].Id);
        }
    }</pre>
<p>In the words of Martin Fowler, here’s the <a href="http://martinfowler.com/eaaCatalog/repository.html">essence of the Repository pattern</a>:</p>
<blockquote>
<p>A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer.</p>
</blockquote>
<p>In SharePoint terms, business logic should query a repository which in turn queries a SharePoint list. Within the repository, the weakly typed items returned are then mapped to strongly typed <a href="http://en.wikipedia.org/wiki/Data_Transfer_Object">data transfer objects</a>, which are returned to the business layer.</p>
<p><img src="http://i.msdn.microsoft.com/Ee413961.a3b014d3-7677-4e99-886e-fd3432a8f914(en-us,MSDN.10).png" width="591" height="50" /></p>
<p>With this approach to data access comes a number of advantages: (1) duplicate data access code is eliminated. Only within the repository do we setup the query and transform the weakly typed <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistitemcollection.aspx">SPListItemCollection</a> into strongly typed data transfer objects. (2) The list definition classes introduced in <a href="http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern">SharePoint list definition using the Template pattern</a> may be used to construct CAML queries from strongly typed field names. Lastly, (3) accessing data through a repository makes it easier to mock the data access part of the application and to integration test that part.</p>
<p>The code below is a simple, yet usable, implementation of the Repository pattern. The idea is to have all repositories inherit from a common base class. Its purpose is to wrap the querying of a list and to <a href="http://www.bugfree.dk/blog/2009/07/22/basic-logging-guidelines">log what’s going on</a>. Because it’s a base class, it shouldn’t know how to transform the weakly typed result into strongly data transfer objects or which CRUD operations a particular repository supports:</p>
<pre class="prettyprint lang-cs">    public abstract class ListRepository {
        protected ListDefinition Definition { get; set; }
        protected SPListItemCollection Result { get; set; }

        protected void Query(SPWeb site, string caml) {
            AssertValidSite(site);
            AssertValidCaml(caml);
            AssertListExistence(site);
            AssertListDefinitionSetBySubclass();

            var watch = new Stopwatch();
            var list = site.Lists[Definition.ListName];
            var query = new SPQuery {Query = caml};
            Debug.WriteLine(
                string.Format(&quot;About to run query against list '{0}': {1}&quot;, list, caml));
            watch.Start();
            Result = list.GetItems(query);
            watch.Stop();
            Debug.WriteLine(
                string.Format(&quot;Query against '{0}' returned {1} rows in {2} ms&quot;,
                              list, Result.Count, watch.ElapsedMilliseconds));
        }

        protected void AssertListExistence(SPWeb site) {
            if (!ListDefinition.ListExists(site, Definition.ListName))
                throw new ArgumentException(
                    string.Format(&quot;No '{0}' list on site '{1}'&quot;, Definition.ListName, site.Url));
        }

        protected void AssertListDefinitionSetBySubclass() {
            if (Definition == null)
                throw new NullReferenceException(
                    string.Format(
                        &quot;Sublcass must set Definition property prior querying '{0}' list&quot;,
                        Definition.ListName));
        }

        protected void AssertValidCaml(string query) {
            if (string.IsNullOrEmpty(query))
                throw new NullReferenceException(&quot;Query must not be null or empty&quot;);
        }

        protected void AssertValidSite(SPWeb site) {
            if (site == null)
                throw new NullReferenceException(&quot;Site must not be null&quot;);
        }
    }</pre>
<p>Each ListRepository connects to a corresponding ListDefinition, holding the name of the list to query and its strongly typed field names. It’s the responsibility of a concrete repository to set the Definition property prior to doing any querying. After running a query, the Result property holds the weakly typed result, which a concrete repository can then transform into data transfer objects to be passed to the business layer.</p>
<p>As an example, add to the concrete EmployeeRepository any CRUD method you see necessary to fulfill the business requirements:</p>
<pre class="prettyprint lang-cs">    public class EmployeesRepository : ListRepository {
        public EmployeesRepository() {
            Definition = new EmployeesDefinition();
        }

        public void AddEmployee(SPWeb site, Employee e) {
            var list = site.Lists[Definition.ListName];
            var item = list.Items.Add();
            item[EmployeesDefinition.EmployeeId] = e.Id;
            item[EmployeesDefinition.Name] = e.Name;
            item[EmployeesDefinition.HireDate] = e.HireDate;
            item[EmployeesDefinition.Remarks] = e.Remarks;
            item.Update();
        }

        public Employee GetEmployeeById(SPWeb site, int id) {
            var caml =
                string.Format(@&quot;
                      &lt;Where&gt;
                        &lt;Eq&gt;
                          &lt;FieldRef Name=&quot;&quot;{0}&quot;&quot; /&gt;
                          &lt;Value Type=&quot;&quot;Integer&quot;&quot;&gt;{1}&lt;/Value&gt;
                        &lt;/Eq&gt;
                      &lt;/Where&gt;&quot;,
                    EmployeesDefinition.EmployeeId, id);
            Query(site, caml);

            IList&lt;Employee&gt; employees = Map(Result);
            if (employees.Count == 0)
                throw new ArgumentException(string.Format(&quot;No employee with id = {0} exists&quot;, id));
            return employees[0];
        }

        public ReadOnlyCollection&lt;Employee&gt; GetEmployeesHiredBetween(SPWeb site, DateTime from, DateTime to) {
            var caml =
                string.Format(@&quot;
                      &lt;Where&gt;
                        &lt;And&gt;
                            &lt;Geq&gt;
                              &lt;FieldRef Name=&quot;&quot;{0}&quot;&quot; /&gt;
                              &lt;Value IncludeTimeValue=&quot;&quot;TRUE&quot;&quot; Type=&quot;&quot;DateTime&quot;&quot;&gt;{1}&lt;/Value&gt;
                            &lt;/Geq&gt;
                            &lt;Leq&gt;
                              &lt;FieldRef Name=&quot;&quot;{0}&quot;&quot; /&gt;
                              &lt;Value IncludeTimeValue=&quot;&quot;TRUE&quot;&quot; Type=&quot;&quot;DateTime&quot;&quot;&gt;{2}&lt;/Value&gt;
                            &lt;/Leq&gt;
                        &lt;/And&gt;
                      &lt;/Where&gt;&quot;,
                    EmployeesDefinition.HireDate,
                    SPUtility.CreateISO8601DateTimeFromSystemDateTime(from),
                    SPUtility.CreateISO8601DateTimeFromSystemDateTime(to));
            Query(site, caml);
            return new ReadOnlyCollection&lt;Employee&gt;(Map(Result));
        }

        protected IList&lt;Employee&gt; Map(SPListItemCollection items) {
            var employees = new List&lt;Employee&gt;();
            foreach (SPItem item in items) {
                var e = new Employee {
                                Id = (int)item[EmployeesDefinition.EmployeeId],
                                Name = (string)item[EmployeesDefinition.Name],
                                HireDate = (DateTime)item[EmployeesDefinition.HireDate],
                                Remarks = (string)item[EmployeesDefinition.Remarks]
                            };
                employees.Add(e);
            }
            return employees;
        }
    }</pre>
<p>Calling the GetEmployeeById or GetEmployeesHiredBetween methods, the caller is required to pass in an SPWeb instance pointing to the the site holding the list to query. Outside the SharePoint context, you have to manually create this instance, like with the integration tests above. But within the SharePoint context, callers are likely to just pass in SPContext.Current.Web.</p>
<p>The above repository implementation deliberately ignores any issue of caching. If you find the need for it, however, you can replace <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.getitems.aspx">SPList.GetItem</a> with <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.navigation.portalsitemapprovider.getcachedlistitemsbyquery.aspx">PortalSiteMapProvider.GetCachedListItemsByQuery</a>. The advantage of <a href="http://blogs.msdn.com/ecm/archive/2007/05/23/increased-performance-for-moss-apps-using-the-portalsitemapprovider.aspx">using the PortalSiteMapProvider</a> over Asp.Net caching of the result is that the provider takes care of invalidating cache entries when items are modified. The disadvantage is that the provider is part of the SharePoint publishing API, which isn’t part of WSS 3.0. In addition, it’s only available from code running within SharePoint, and likely requires cache settings to be tweaked.</p>
<ol></ol>
<ol></ol>
<p>Another, non-trivial, improvement would include the use of the <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html">Unit of Work</a> pattern. A commonly used pattern in ORMs because it offers a way to “keep track of everything you do during a business transaction that can affect the database. When you&#8217;re done, it figures out everything that needs to be done to alter the database as a result of your work&quot;. Like with the <a href="http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.aspx">DataContext</a> class in LINQ to SQL or the <a href="http://msdn.microsoft.com/en-us/library/system.data.dataset.aspx">DataSet</a> class in ADO.NET, it could add transaction support to SharePoint lists.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F01%2F18%2Fsharepoint-list-access-using-the-repository-pattern%2F&amp;title=SharePoint%20list%20access%20using%20the%20Repository%20pattern" id="wpa2a_24"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/01/18/sharepoint-list-access-using-the-repository-pattern/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SharePoint list definition using the Template pattern</title>
		<link>http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern/</link>
		<comments>http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 15:25:45 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Pattern]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/?p=1037</guid>
		<description><![CDATA[(Download code here. See related post on SharePoint list access using the Repository pattern) Books on SharePoint often show how to create lists from code by calling the SharePoint API from directly within a feature receiver. This receiver would then contain in-place string literals for column names, create the columns, update the default view, and [...]]]></description>
			<content:encoded><![CDATA[<p>(Download code <a href="http://www.bugfree.dk/blog/wp-content/uploads/2010/01/SharePointTemplatePatternRepositoryPattern.zip">here</a>. See related post on <a href="http://www.bugfree.dk/blog/2010/01/18/sharepoint-list-access-using-the-repository-pattern/">SharePoint list access using the Repository pattern</a>)</p>
<p>Books on SharePoint often show how to create lists from code by calling the SharePoint API from directly within a feature receiver. This receiver would then contain in-place string literals for column names, create the columns, update the default view, and so on. While such an approach provides for an nice demonstration of the SharePoint API, it tends to carry over into production code.</p>
<p>My take on feature receivers, however, is that they should contain the least possible amount of code. Staying true to object-orientation and separation of concerns, list definition and creation should instead consist of a common set of classes and methods to be called from the receiver:</p>
<pre class="prettyprint lang-cs">    public override void FeatureActivated(SPFeatureReceiverProperties p) {
        using (var site = p.Feature.Parent as SPWeb) {
            var employees = new EmployeesDefinition();
            if (!ListDefinition.ListExists(site, employees.ListName))
                employees.CreateOnSite(site);
        }
    }</pre>
<p>The first area to improve on is that of string literal field names getting duplicated across the code base. String literals make it impossible for the compiler to enforce a consistent naming of columns. As column names are used in defining the list, in <a href="http://www.bugfree.dk/blog/2008/07/03/code-based-dynamic-caml-query-composition">forming CAML queries</a> against it, and in accessing the result, misspelled column names is a common source of runtime errors. The second area to improve on is that of duplication of code for doing common list operations, like checking for the existence of the list or removing its title column. Lastly, we want to get rid of duplicate control logic, i.e., verifying preconditions and calling the same series of methods with every list definition.</p>
<p>One approach to improving on these areas is to start by defining a base class for list definitions. The base class combines helper methods, working on lists, with the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template pattern</a> for defining the common steps of list creation:</p>
<pre class="prettyprint lang-cs">    public abstract class ListDefinition {
        public string ListName;
        public string ListDescription;
        protected SPList List;

        public void CreateOnSite(SPWeb site) {
            if (string.IsNullOrEmpty(ListName))
                throw new ArgumentException(&quot;Expected not null or not empty list name member&quot;);
            if (site == null) throw new NullReferenceException(&quot;Expected valid site&quot;);
            CreateList(site);
            if (List == null) throw new NullReferenceException(&quot;Expected list member not null&quot;);
            CreateFields(List);
            UpdateDefaultView(List);
            SetAdditionalProperties(List);
        }

        protected abstract void CreateList(SPWeb site);
        protected virtual void CreateFields(SPList l) {}
        protected virtual void UpdateDefaultView(SPList l) {}
        protected virtual void SetAdditionalProperties(SPList l) {}

        public static void HideAndMakeTitleFieldNotRequiredOnItemNewAndEditPage(SPList l) {
            var title = l.Fields.GetField(&quot;Title&quot;);
            title.Required = false;
            title.Hidden = true;
            title.Update();
        }

        public static bool ListExists(SPWeb site, string listName) {
            if (string.IsNullOrEmpty(listName))
                throw new ArgumentException(&quot;ListNameMustNotBeNullOrEmpty&quot;, listName);
            SPList list = null;
            try {
                list = site.Lists[listName];
            }
            catch (ArgumentException) {
                // list not found
            }
            return list != null ? true : false;
        }
    }</pre>
<p>At the core of the Template pattern is the template method. It defines the steps of an algorithm through a series of method calls. Each either abstract or virtual depending on if the step is mandatory or voluntary in the algorithm. Subclasses then specify the behavior of individual steps by implementing or overriding methods. In case of the ListDefinition class, CreateOnSite is our template method. It ensures that context, in the form of an <a href="http://msdn.microsoft.com/en-us/library/dd587308%28office.11%29.aspx">SPList</a> instance, is passed along to each step in the algorithm.</p>
<p>Each subclass defines the specific characteristics of a list. It defines constants for column names and their data types, the views and which column to index, and so on. This makes for a concise, easy to read, and consistent list definition:</p>
<pre class="prettyprint lang-cs">    public class EmployeesDefinition : ListDefinition {
        public const string EmployeeId = &quot;EmployeeId&quot;;
        public const string Name = &quot;Name&quot;;
        public const string HireDate = &quot;HireDate&quot;;
        public const string Remarks = &quot;Remarks&quot;;

        public EmployeesDefinition() {
            ListName = &quot;AcmeEmployees&quot;;
            ListDescription = &quot;Employees at Acme Corp.&quot;;
        }

        protected override void CreateList(SPWeb site) {
            var guid = site.Lists.Add(ListName, ListDescription, SPListTemplateType.GenericList);
            List = site.Lists[guid];
        }

        protected override void CreateFields(SPList l) {
            l.Fields.Add(EmployeeId, SPFieldType.Integer, true);
            l.Fields.Add(Name, SPFieldType.Text, true);
            l.Fields.Add(HireDate, SPFieldType.DateTime, true);
            var remarks = (SPFieldMultiLineText) l.Fields[l.Fields.Add(Remarks, SPFieldType.Note, false)];
            remarks.RichText = true;
            remarks.RichTextMode = SPRichTextMode.FullHtml;
            remarks.Update();
            l.Update();
        }

        protected override void UpdateDefaultView(SPList l) {
            var v = l.DefaultView;
            v.ViewFields.Delete(&quot;LinkTitle&quot;);
            v.ViewFields.Add(EmployeeId);
            v.ViewFields.Add(Name);
            v.ViewFields.Add(HireDate);
            v.ViewFields.Add(Remarks);
            v.Update();
        }

        protected override void SetAdditionalProperties(SPList l) {
            HideAndMakeTitleFieldNotRequiredOnItemNewAndEditPage(l);
            l.Fields[HireDate].Indexed = true;
            l.Update();
        }
    }</pre>
<p>Since the string literals have now become public constants, we get IntelliSense and compile-time checking referencing them. In addition, by defining common operations on the base class and using the Template pattern, we reduce the amount of code that would otherwise have to go into each definition. Finally, the base class asserts, on behalf of all subclasses, that the list name is set before attempting to create the list and that the SPList field is set after calling the CreateList method.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2010%2F01%2F11%2Fsharepoint-list-definition-using-the-template-pattern%2F&amp;title=SharePoint%20list%20definition%20using%20the%20Template%20pattern" id="wpa2a_26"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2010/01/11/sharepoint-list-definition-using-the-template-pattern/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using VS linked files for strong naming assemblies</title>
		<link>http://www.bugfree.dk/blog/2009/02/17/using-vs-linked-files-for-strong-naming-assemblies/</link>
		<comments>http://www.bugfree.dk/blog/2009/02/17/using-vs-linked-files-for-strong-naming-assemblies/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 21:43:39 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Tip]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2009/02/17/using-vs-linked-files-for-strong-naming-assemblies/</guid>
		<description><![CDATA[Visual Studio has the ability to add a file as a link, making other parts of Visual Studio believe the file is actually located where it&#8217;s added. One useful application of the link feature is for signing assemblies by way of a key file. Signing an assembly using a digital signature may serve one or [...]]]></description>
			<content:encoded><![CDATA[<p>Visual Studio has the ability to add a file as a link, making other parts of Visual Studio believe the file is actually located where it&#8217;s added. One useful application of the link feature is for signing assemblies by way of a key file. Signing an assembly using a digital signature may serve one or more purposes: It&#8217;s a precondition for deploying an assembly to the Global Assembly Cache (GAC), sharing an assembly among applications, and making <a href="http://msdn.microsoft.com/en-us/library/fdhkd3a5.aspx">side-by-side execution</a> possible. Also, signing an assembly is useful for asserting its integrity, GAC deployed or otherwise.
</p>
<p>The reason for bringing up the linked file feature in conjunction with assembly signing is that to me the feature seems particularly well-suited for linking one and only key file into multiple Visual Studio projects. Yet people seem to be unaware of the feature and so common approaches to signing is to either create a new key file for each assembly &#8212; most likely because Visual Studio makes it so easy to create a new key file from the Project Settings dialog &#8212; or signing assemblies by creating one key file and then copy/paste it to other projects in the solution.
</p>
<p>Below is an example from the GAC showcasing how assemblies related to <a href="http://research.microsoft.com/en-us/projects/pex/">Pex</a> naturally go together and are therefore signed using the same key (they share 76a274db078248c8, their public key token). The same goes for  assemblies relating to other Microsoft products, such as the ones comprising a particular version of the .Net framework (because of the side-by-side execution, different versions of .Net framework assemblies are signed using different keys). So why not apply the same principle to what you deploy to the GAC?</p>
<p><img src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/example-of-public-key-from-the-gac.png" /></p>
<p>While using the same key (copy or not) makes it possible to differentiate your assemblies from everyone else and for your <a href="http://en.csharp-online.net/.NET_CLR_Components%E2%80%94Assembly_Names">four-part assembly name</a> in web.config and spread around the code to be uniform &#8212; SharePoint developers often need to provide the four-part name for their assemblies to other parts of the solution &#8212; copying the key around is still a violation of the <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY principle</a> and as such is indicative of a <a href="http://martinfowler.com/bliki/CodeSmell.html">code smell</a>. More importantly, using the link feature of Visual Studio, there&#8217;s no reason to keep the bad smell around.
</p>
<p>Assuming you&#8217;ve already created a solution (in Visual Studio 2008) and added a project to it, the way to share a key file is to first create one by right clicking a project in Solution Explorer and selecting Properties. Now click the Signing tab and check the Sign the assembly check box. The dropdown lets you create a new key file by selecting New and filling out the information in the Create Name Key window. Alternatively, a key file is created using <a href="http://msdn.microsoft.com/en-us/library/k5b5tt23.aspx">sn.exe</a>, the strong name utility that comes with the <a href="http://blogs.msdn.com/windowssdk/archive/2008/09/25/winsdk-in-vs2008-sp1-patch-what-changed.aspx">Microsoft Windows SDK</a>. On my machine, sn.exe is located in C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin and is invoked like so:
</p>
<pre>
    > sn -k MySharedKeyPair.snk
</pre>
</p>
<p>How the key file is created isn&#8217;t particularly relevant to the rest of this post. Just make sure to place the key file in a common location, e.g., the top-level directory holding the Visual Studio solution file. Now go to Solution Explorer, right click on your project, and select Add existing Item. Then locate the key file within the solution directory and make sure to click the arrow on the Add button and select Add as Link. Note how the file is added to the project and marked by an arrow indicating it&#8217;s a link:</p>
<p style="margin: 0px; padding: 0px;">
<img style="float:left;" src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/add-existing-item-as-link.png" />&nbsp;&nbsp;&nbsp;<img style="float:" src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/linked-file-in-solution-explorer.png" />
</p>
<p>Returning to the Signing tab and selecting the dropdown, it now includes the linked key file. Don&#8217;t mind the absolute path; once you select MySharedKeyPair.snk, Visual Studio converts the path to a relative one (close and reopen the Signing tab and see for yourself). Also note that if you select Browse, the key file you select is copied to the project folder and added to the project as a regular file.</p>
<p><img src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/select-linked-file-in-signing-tab-of-project-properties.png" /></p>
<p>Another way to associate a key file with an assembly is through the <a href="http://msdn.microsoft.com/en-us/library/system.reflection.assemblykeyfileattribute.aspx">AssemblyKeyFile</a> attribute. The attribute instructs the compiler of where to look for the key file and, although not used by the runtime, the attribute is included in the assembly along with any other attribute for everyone to see.</p>
<p><img src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/key-file-attribute-in-assembly-info.png" /></p>
<p>Using AssemblyKeyFile is probably the simplest approach to sharing a key file between projects, but now compiling the assembly results in a compiler warning as displayed above. The <a href="http://msdn.microsoft.com/en-us/library/xh3fc3x0(VS.80).aspx">use of the AssemblyKeyFile attribute has been deprecated</a> by Microsoft because it may lead to you inadvertently disclosing sensitive information through the embedded path and because working with a relative path may confuse users and the build system (the relative path is retained in the assembly, though). However, it appears AssemblyKeyFile is still the preferred way for MS to sign their assemblies. Inspecting a couple of .Net 3.5 assemblies with Reflector, here&#8217;s what their AssemblyKeyFile looks like:
</p>
<pre class="prettyprint lang-cs">
    [assembly: AssemblyKeyFile(@"f:\\dd\\tools\\devdiv\\EcmaPublicKey.snk")]
    [assembly: AssemblyKeyFile(@"f:\\dd\\tools\\devdiv\\35MSSharedLib1024.snk")]
    [assembly: AssemblyKeyFile(@"f:\\dd\\tools\\devdiv\\FinalPublicKey.snk")]
    …
</pre>
<p>To come full circle, the question of how Visual Studio, or rather MSBuild, actually signs an assembly using the information provided in the Properties dialog (real file or link) remains to be answered. Since a Visual Studio project file acts as input to MSBuild, we can see what&#8217;s going on under the hood of MSBuild by invoking a compile from the command line. On my machine <a href="http://msdn.microsoft.com/en-us/library/ms164311.aspx">msbuild.exe</a> is located in C:\Windows\Microsoft.NET\Framework\v3.5 and assuming you have a console window open with its current directory set to the directory of your project file, msbuild is invoked like so:
</p>
<pre>
    > msbuild /verbosity:diagnostic &gt; log.txt
</pre>
</p>
<p>Bring up log.txt in your favorite editor and eventually you&#8217;ll come across where <a href="http://msdn.microsoft.com/en-us/library/78f4aasd.aspx">csc.exe</a>, the C# compiler, is invoked:</p>
<p><img src="http://www.bugfree.dk/blog/wp-content/uploads/2009/02/key-file-and-msbuild.png" /></p>
<p>As you might have guessed, MSBuild carries over the location of the key file by passing the /keyfile argument to csc.exe.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2009%2F02%2F17%2Fusing-vs-linked-files-for-strong-naming-assemblies%2F&amp;title=Using%20VS%20linked%20files%20for%20strong%20naming%20assemblies" id="wpa2a_28"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2009/02/17/using-vs-linked-files-for-strong-naming-assemblies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An example of unit testing using TypeMock</title>
		<link>http://www.bugfree.dk/blog/2009/02/11/an-example-of-unit-testing-using-typemock/</link>
		<comments>http://www.bugfree.dk/blog/2009/02/11/an-example-of-unit-testing-using-typemock/#comments</comments>
		<pubDate>Wed, 11 Feb 2009 04:00:07 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Mocking]]></category>
		<category><![CDATA[Quality]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2009/02/11/an-example-of-unit-testing-using-typemock/</guid>
		<description><![CDATA[This post details my first use of TypeMock, a commercial mocking framework, for testing a web part that displays a dropdown bound to a LINQ query. Based on the item selected, the web part then displays a result bound to another LINQ query. For the purpose of becoming familiar with TypeMock, though, the focus of [...]]]></description>
			<content:encoded><![CDATA[<p>This post details my first use of <a href="http://www.typemock.com">TypeMock</a>, a commercial mocking framework, for testing a web part that displays a dropdown bound to a LINQ query. Based on the item selected, the web part then displays a result bound to another LINQ query. For the purpose of becoming familiar with TypeMock, though, the focus of this post is on testing the code that initializes the LINQ data context. It does so by reading a connection string from a configuration file and passing it to the data context.
</p>
<p>In order to test code whose branching behavior depends on a value read from a configuration file, the test should provide various inputs and assert that the code under test acts accordingly. In addition, the test should run in milliseconds to encourage frequent runs and it should be self-contained, meaning no setup should be required before running the test. These requirements are best met with the web part running in a controlled environment. Yet, as far as the code under test goes, it should behave as if part of an Asp.Net page.
</p>
<p>For the sake of brevity, here&#8217;s my web part with the code to initialize the data context:</p>
<pre class="prettyprint lang-cs">
    public class MyWebPart : WebPart {
        MyDataContext _db;    /* LINQ database context */
        string _error;        /* Early stage error message */    	

        public MyWebPart() {
            Initialize();
        }

        private void Initialize() {
            string c = GetMyConnectionString();
            if (c == null)
                 _error = "Unable to do something";
            else
                _db = new MyDataContext(c);
        }

        private string GetMyConnectionString() {
            System.Configuration.ConnectionStringSettings c =
                System.Configuration.ConfigurationManager.
                    ConnectionStrings["MyConnection"];
            return c == null ? null : c.ConnectionString;
        }

        protected override void Render(HtmlTextWriter w) {
            // display error message if set
        }
    }
</pre>
<p>Notice how the constructor calls out to an Initialize method. Otherwise code within the constructor would fire before I&#8217;d have a chance to setup a controlled environment around the web part and I wouldn&#8217;t be able to test it. Turning the attention to Initialize itself, it’s made up of only a simple if statement. The idea is that if I can&#8217;t mock something as simple as reading a value from a configuration file, most likely I can&#8217;t mock something more involved either. On the other hand, for a developer already familiar with TypeMock and test first development, the code above may be born of the need to satisfy a failing test.
</p>
<p>I want to test Initialize by controlling how GetMyConnectionString gets to return the connection string. While running in an Asp.Net context, GetMyConnectionString would attempt to read the string from web.config. Within my controlled environment, however, I want to inject into the web part an alternate implementation that returns a value of my choosing. That way I can control the path through Initialize and inspecting the state of the  _error or _db fields, I&#8217;m able to determine if the code behaved as intended.
</p>
<p>Using the method chaining DSL of TypeMock, the test takes on this form (of course, having more tests, I&#8217;d move shared code into helper methods decreasing the test to code ratio):
</p>
<pre class="prettyprint lang-cs">
    [TestClass, ClearMocks]
    public class MyWebPartTest {
        [TestMethod, Isolated, VerifyMocks]
        public void Should_set_error_message_when_no_
                    connection_string_is_configured() {
            // arrange
            MyWebPart fake = Isolate.Fake.Instance&lt;MyWebPart&gt;();
            Isolate.NonPublic.WhenCalled(fake,
                "Initialize").CallOriginal();
            Isolate.NonPublic.WhenCalled(fake,
                "GetMyConnectionString").WillReturn(null);
            PrivateObject handle = new PrivateObject(fake);

            // act
            handle.Invoke("Initialize", null); 

            // assert
            Isolate.Verify.NonPublic.WasCalled(fake,
                "GetMyConnectionString");
            string error = (string)handle.GetField("_error");
            MyDataContext ctx = (MyDataContext)handle.GetField("_db");
            Assert.AreEqual("Unable to do something", error);
            Assert.AreEqual(null, ctx);
        }
    }
</pre>
<p>There&#8217;re three parts to tests using TypeMock: (1) the arrange part sets up expectations of what’s going to happen when a method, a property, or some other part of the code under test is invoked; (2) the act part carries out the actual interaction with the object under test, turning to <a href="http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.privateobject.aspx">PrivateObject</a> to invoke the Initialize method; and finally (3) the assert part verifies that what was supposed to happen did happen. Worth noting is that this test asserts both state and behavior, i.e., as part of executing the code under test, _error or _db should&#8217;ve been set to an appropriate state and GetMyConnectionString should’ve been called once and only once.
</p>
<p>This concludes my example, which I believe illustrates the basics of testing and mocking using MS Test and TypeMock. Comparing and contrasting TypeMock to <a href="http://weblogs.asp.net/rosherove/archive/2007/04/26/choosing-a-mock-object-framework.aspx">other popular mocking frameworks</a>, TypeMock has the distinct feature that it can mock almost anything, with or without using interfaces. <a href="http://www.mockobjects.com/2007/03/stop-designing-for-testability.html">Some</a> argue that not enforcing the use of interfaces is also the disadvantage of TypeMock, because for code to be truly testable, it should be modularized using the <a href="http://en.wikipedia.org/wiki/Inversion_of_control">Inversion of Control principle</a>. However, with legacy code, such as the .Net framework or the SharePoint API, to me TypeMock appears to bridge the two worlds nicely, leaving the developer in charge.</p>
<p>To learn more about the basic concepts of mocking, Inversion of Control, and Dependency Injection (containers), I&#8217;d recommend listening to a couple of <a href="http://altnetpodcast.com">Alt.Net podcasts</a>: <a href="http://altnetpodcast.com/episodes/5-di-and-ioc">Dependency Injection and Inversion of Control</a> and <a href="http://altnetpodcast.com/episodes/6-more-di-and-ioc">More Dependency Injection and Inversion of Control</a>.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2009%2F02%2F11%2Fan-example-of-unit-testing-using-typemock%2F&amp;title=An%20example%20of%20unit%20testing%20using%20TypeMock" id="wpa2a_30"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2009/02/11/an-example-of-unit-testing-using-typemock/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Asp.Net error handling by HttpModule</title>
		<link>http://www.bugfree.dk/blog/2008/08/30/aspnet-error-handling-by-httpmodule/</link>
		<comments>http://www.bugfree.dk/blog/2008/08/30/aspnet-error-handling-by-httpmodule/#comments</comments>
		<pubDate>Sat, 30 Aug 2008 21:58:29 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Quality]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2008/08/30/aspnet-error-handling-by-httpmodule/</guid>
		<description><![CDATA[Download EmailingExceptionModule-1.0.zip. In any real-world application, unhalted exceptions are an unavoidable fact of life. Such exceptions should occur relatively infrequently, but when they do some kind of supporting infrastructure better be in place to capture the when and why of the exceptions. As a developer, you should have the ability to perform a postmortem analysis [...]]]></description>
			<content:encoded><![CDATA[<p>Download <a href="/software/EmailingExceptionModule-1.0.zip">EmailingExceptionModule-1.0.zip</a>.</p>
<p>In any real-world application, unhalted exceptions are an unavoidable fact of life. Such exceptions should occur relatively infrequently, but when they do some kind of supporting infrastructure better be in place to capture the when and why of the exceptions. As a developer, you should have the ability to perform a postmortem analysis on what went wrong and learn from it. Paramount to such analysis is capturing and logging sufficient information at the point of failure.</p>
<p>What this post covers is the thoughts and development of an Asp.Net HttpModule that captures and emails such unhalted exception information to a designated email address.
</p>
<p>To be clear, the goal of the EmailingExceptionModule isn&#8217;t to prevent unhalted exception from occurring per se. Within code, a developer may not know how to handle an exception, and so the exception should rightfully propagate the call stack. In case no caller steps in and handles the exception, the best choice is most likely to terminate the application. It&#8217;s almost always better to be upfront with the user than conceal the possibly inconsistent state of the application.
</p>
<p>So when does the EmailingExceptionModule come in handy then? One scenario is that of <a href="http://msdn.microsoft.com/en-us/vcsharp/aa336812.aspx">C# unchecked exceptions</a>, where the compiler doesn&#8217;t force the caller to catch all types of exceptions thrown by the callee. Unchecked exceptions may materialize as type cast or null reference exceptions when accessing variables. What unchecked exceptions boil down to is that, given the <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of some methods, it&#8217;s impractical to manually work through every conceivable path of execution ahead of time. Another scenario is problems with the runtime environment, such as out of disk space or database server down. Nonetheless, some map of the path to failure is helpful in preventing others going down that same path.</p>
<p><img src="http://www.bugfree.dk/blog/wp-content/uploads/2008/08/emailexceptionmoduleexample.png" /><br />
(Summary part of example email. Click <a href="http://www.bugfree.dk/blog/wp-content/uploads/2008/08/emailexceptionmoduleexample.html" target="_blank">here</a> for complete output.)</p>
<p>With web applications, we can take advantage of the application running in a centralized environment. In the spirit of Microsoft&#8217;s <a href="http://en.wikipedia.org/wiki/Dr._Watson_(debugger)">Doctor Watson</a> technology, we can register our own web application error handler and hook it into the Http request pipeline, and have the application execute our code on unhalted exceptions. In practice, such an error handler is implemented either through the Application_Error method of an application&#8217;s <a href="http://en.wikipedia.org/wiki/Global.asax">Global.asax</a> or by loading an <a href="http://msdn.microsoft.com/en-us/library/bb398986.aspx">HttpModule</a> into the application.
</p>
<p>Hinted by the title, I went for the HttpModule. The reason may best be understood by taking a peak behind the .Net curtains: Global.asax is a filename hardwired into the framework so that whenever an application is first hit, the framework asks HttpApplicationFactory, an internal <a href="http://www.ondotnet.com/pub/a/dotnet/2003/08/11/factorypattern.html">factory</a> class, for an <a href="http://msdn.microsoft.com/en-us/library/system.web.httpapplication.aspx">HttpApplication</a> representing the application (there&#8217;s a unique one for each virtual application). As part of manufacturing the HttpApplication, the factory locates the application&#8217;s Global.asax, compiles it into a dynamically generated DLL, loads the DLL, and reflects over the Global.asax class looking for methods adhering to the convention of modulename_eventname. Methods found, such as Application_Error, are then stored in a list of <a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.aspx">MethodInfo</a>s and passed along to HttpApplication. Then, during HttpApplication initialization, events are bound to the methods within Global.asax.</p>
<p>That&#8217;s how Application_Error of Global.asax gets called even though the method isn&#8217;t overriding a base class implementation as is typical for the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">template pattern</a>. That&#8217;s also why code within global.asax isn&#8217;t binary reusable across applications. An HttpModule, on the other hand, can be loaded into any number of applications.
</p>
<p>In practice, implementing an HttpModule it a matter of creating a class that implements the <a href="http://msdn.microsoft.com/en-us/library/system.web.ihttpmodule.aspx">IHttpModule</a> interface:
</p>
<pre class="prettyprint lang-cs">
   public interface IHttpModule {
      void Init(HttpApplication context);
      void Dispose();
   }
</pre>
<p>The crux of error handling with Asp.Net is the <a href="http://msdn.microsoft.com/en-us/library/system.web.httpapplication.error.aspx">Error</a> event of HttpApplication. The easiest way to hook up the event to a method is within the <a href="http://msdn.microsoft.com/en-us/library/system.web.ihttpmodule.init.aspx">Init</a> method of the class. In addition, we assign the application object to a field so that later we can access the most recently thrown exception through it:</p>
<pre class="prettyprint lang-cs">
   public class EmailingExceptionModule : IHttpModule {
      private HttpApplication _application;

      public void Init(HttpApplication a) {
         _application = a;
         _application.Error += OnUnhaltedException;
      }

      public void Dispose() {}

      private void OnUnhaltedException(object sender, EventArgs e) {
         Exception ex = _application.Server.GetLastError().InnerException;
         // Implementation left out for brevity. Please download source
      }
   }
</pre>
<p>The OnUnhaltedException method is where to add code that collects information about the exception and the environment, and that composes and ships the email. Depending on the environment, you may find the need to include additional information in the email. Given the source code, adding to the email is a matter of adding key/value pairs in the form of labels and values to a dictionary. Each dictionary then gets rendered as a table of the key and value columns.
</p>
<p>To have an Asp.Net application load the EmailingExceptionModule and to configure its email related settings, add the following nodes to the application&#8217;s web.config:
</p>
<pre class="prettyprint lang-xml">
   &lt;configuration&gt;
      &lt;appSettings&gt;
         &lt;add key="EmailingExceptionModule_SenderAddress" value="sender@domain.com"/&gt;
         &lt;add key="EmailingExceptionModule_ReceiverAddress" value="receiver@domain.com"/&gt;
         &lt;add key="EmailingExceptionModule_SmtpServer" value="mail.domain.com"/&gt;
         &lt;add key="EmailingExceptionModule_SubjectPrefix" value="MyApp: "/&gt;
      &lt;/appSettings&gt;
      &lt;system.web&gt;
         &lt;httpModules&gt;
            &lt;add name="EmailingExceptionModule" type="Holm.AspNet.EmailingExceptionModule,
                       EmailingExceptionModule, Version=1.0.0.0, Culture=neutral,
                       PublicKeyToken=13806f613f05e959"/&gt;
         &lt;/httpModules&gt;
      &lt;/system.web&gt;
   &lt;/configuration&gt;
</pre>
<p>So what&#8217;s the user experience of unhalted exceptions? Outside the confines of the EmailingExceptionModule, there&#8217;s no indication that the application took note of what happened. Depending on the user&#8217;s profile, it might be helpful to prompt for additional information at the crash point. Or perhaps turn to the <a href="http://blogs.msdn.com/angus_logan/archive/2007/11/07/announcment-windows-live-messenger-im-control-presence-api-conversations-from-web-to-client-querying-presence.aspx">Windows Live Messenger IM Control &amp; Presence API</a> and have the user engage in an MSN conversation with a developer.
</p>
<p>What&#8217;s the advantage of emailing developers unhalted exceptions over storing the information in the file system or a database? I believe in keeping things simple and practical, and handing off information to the file system or a database isn&#8217;t. Most likely the information will end up gathering virtual dust on some server. The email approach, on the other hand, is a proactive, visible, and efficient means to the end of rapidly course-correcting for wrong assumptions.</p>
<p><b>Update, Sep 15</b>: While you <a href="http://www.elumenotion.com/Blog/Lists/Posts/Post.aspx?ID=23">don&#8217;t need a PDB file to debug code</a> through Visual Studio (that&#8217;s what &lt;compilation debug=&#8221;true&#8221;&gt; in web.config is for), the PDB file is required for the <a href="http://timstall.dotnetdevelopersjournal.com/deploying_pdbs_to_get_the_exact_line_number_of_an_exception.htm">stack trace to contain line numbers</a>. Since the PDB file typically has to reside next to the corresponding DLL for the .Net runtime to pick it up, the PDB file may need to be deployed to the GAC along with the DLL. Refer to the first three paragraphs of the &#8220;Debugging assemblies that live in the GAC&#8221; section of <a href="http://blogs.msdn.com/markarend/archive/2008/09/09/debugging-web-parts-and-other-sharepoint-custom-code.aspx">this</a> post for how to GAC deploy PDB files.
<p>For a centrally deployed Asp.Net application, it may be acceptable to ship and deploy the PDB file with the application. Keep in mind, though, that because the PDB file is a mapping of locations in the IL to the source file, having access to the PDB file makes it easier for someone to reverse engineer the code. It&#8217;s also possible to <a href="http://timstall.dotnetdevelopersjournal.com/getting_file_and_line_numbers_without_deploying_the_pdb_file.htm">get at line numbers without the PDB file</a> being deployed, but the approach is somewhat involved. Based on the mapping nature of the PDB file, the idea is to write out IL offsets as part of the exception and to post-process the offsets using a PDB file at a separate location.</p>
<p>Yet another alternative to shipping the PDB file is to setup a symbol server. With <a href="http://blogs.msdn.com/rmbyers/archive/2007/06/21/customizing-pdb-lookup-for-source-information-in-stacktrace.aspx">this</a> nifty piece of code, the <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx">StackTrace</a> class loads the PDB file of the symbol server, adding line numbers to the stack trace.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2008%2F08%2F30%2Faspnet-error-handling-by-httpmodule%2F&amp;title=Asp.Net%20error%20handling%20by%20HttpModule" id="wpa2a_32"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2008/08/30/aspnet-error-handling-by-httpmodule/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to modify the enclosing tag of a web control</title>
		<link>http://www.bugfree.dk/blog/2008/07/30/how-to-modify-the-enclosing-tag-of-a-web-control/</link>
		<comments>http://www.bugfree.dk/blog/2008/07/30/how-to-modify-the-enclosing-tag-of-a-web-control/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 20:45:47 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[Html]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2008/07/30/how-to-modify-a-web-control%e2%80%99s-enclosing-tag/</guid>
		<description><![CDATA[In this post I&#8217;ll rework a piece of code that changes the enclosing tag of a web control from a span to a div. A substitution of particular value with SharePoint, where adding web controls is a common way to extend the out of box experience. With SharePoint, and Asp.Net in general, a page is [...]]]></description>
			<content:encoded><![CDATA[<p>In this post I&#8217;ll rework a piece of code that changes the enclosing tag of a web control from a <a href="http://webdesign.about.com/od/htmltags/a/aa011000a.htm">span to a div</a>. A substitution of particular value with SharePoint, where adding web controls is a common way to extend the out of box experience. With SharePoint, and Asp.Net in general, a page is typically composed of reusable controls, each responsible for rendering its part of the page.
</p>
<p>To showcase anti-patterns of API usage, intermediate code is included, i.e., code that may render the correct tags, although not necessarily in the true spirit of the .Net framework.
</p>
<p>To set the stage, imagine writing a web control that inherits from ASP.Net <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.aspx">WebControl</a>. The goal is then to modify the behavior of the control in such a way that it (1) encloses its content in a div tag and (2) adds a CSS class for styling, and (3) can be added to a page like so:
</p>
<pre class="prettyprint lang-html">
   &lt;MyControls:MyControl CssClass="myCssClass" runat="server" /&gt;
</pre>
<p>After making its way through the page rendering pipeline, the control tag gets transformed to:
</p>
<pre class="prettyprint lang-html">
   &lt;div class="myCssClass"&gt;
      Hello World
   &lt;/div&gt;
</pre>
<p>Within the control, a straight-forward way of achieving the intended output may be to hand craft the html and render it in <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.rendercontents.aspx">RenderContents</a> of WebControl. It almost goes without saying that rendering html by hand is but only a starting point when working with .Net. The next progression from there may be to override <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderbegintag.aspx">RenderBeginTag</a> and <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderendtag.aspx">RenderEndTag</a> of WebControl:
</p>
<pre class="prettyprint lang-cs">
   // version 1
   public class MyControl : WebControl {
      public override void RenderBeginTag(HtmlTextWriter w) {
         w.RenderBeginTag(string.Format("div class=\"{0}\"", CssClass));
      }

      public override void RenderEndTag(HtmlTextWriter w) {
         w.RenderEndTag();
      }

      protected override void RenderContents(HtmlTextWriter w) {
         w.Write("Hello World");
      }
   }
</pre>
<p>Resulting in this piece of html:</p>
<pre class="prettyprint lang-html">
   &lt;div class="myCssClass"&gt;
      Hello World
   &lt;/div class="myCssClass"&gt;
</pre>
<p>Clearly, <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderbegintag.aspx">RenderBeginTag</a> and <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.renderendtag.aspx">RenderEndTag</a> of <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.htmltextwriter.aspx">HtmlTextWriter</a> don&#8217;t know how to separate tag from attribute. Nonetheless, the code reveals the stack based approach taken by the Render-pair of methods.</p>
<p>Gleaning over the documentation of HtmlTextWriter, however, I encountered the <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.htmltextwriter.addattribute.aspx">AddAttribute</a> method for setting attributes on a tag. Inside HtmlTextWriter, what AddAttribute does is add attributes and associated values to an array that gets rendered during the next call to RenderBeginTag. So besides introducing strongly typed attributes and tags, the next version contains a modified RenderBeginTag:</p>
<pre class="prettyprint lang-cs">
   // version 2
   public override void RenderBeginTag(HtmlTextWriter w) {
      w.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
      w.RenderBeginTag(HtmlTextWriterTag.Div);
   }
</pre>
<p>Now the control renders as expected, although the code still has a certain bad smell to it. WebControl ought to know how to properly render its begin and end tag. After all it&#8217;s WebControl that exposes, among others, the <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.cssclass.aspx">CssClass</a> property. So taking another dive into the documentation, I found the virtual, read-only <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.tagkey.aspx">TagKey</a> property of WebControl. Strangely named as it may be, overriding TagKey makes WebControl call our override as it renders the control, adding in optional attributes, such as CssClass. Implementing the property also turns RenderBeginTag and RenderEndTag obsolete:</p>
<pre class="prettyprint lang-cs">
   // version 3
   protected override HtmlTextWriterTag TagKey {
      get {
         return HtmlTextWriterTag.Div;
      }
   }
</pre>
<p>As an added bonus, changing the enclosing tag can also be done calling the WebControl&#8217;s constructor, passing in the desired tag:
</p>
<pre class="prettyprint lang-cs">
   // version  4
   public class MyControl : WebControl {
      public MyControl() : base(HtmlTextWriterTag.Div) { }

      protected override void RenderContents(HtmlTextWriter w) {
         w.Write("Hello World");
      }
   }
</pre>
<p>As it turns out, calling the constructor is how WebControl derived classes get to use span in the first place. The default WebControl constructor passes control onto another constructor that sets the value of what gets returned by the base class TagKey implementation. In essence, overriding TagKey makes it a player in the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">template design pattern</a>:
</p>
<pre class="prettyprint lang-cs">
   // .Net framework code
   protected WebControl() : this(HtmlTextWriterTag.Span) { }

   public WebControl(HtmlTextWriterTag tag) {
      tagKey = tag;
   }
</pre>
<p>Also worth noting is that for controls deriving from WebControl derived classes, such as <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.compositecontrol.aspx">CompositeControl</a>, the constructor cannot be used to set the enclosing tag. The constructor exposed by CompositeControl and friends doesn&#8217;t call up the constructor chain passing in the tag, making TagKey the choice to go.
</p>
<p>Finally, deep down the inhertitance chain below WebControl lives <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webparts.webpart.aspx">WebPart</a>, a type of control very popular with SharePoint. Interestingly enough, WebPart defaults to using div as its enclosing tag, because walking up the chain, we come across the constructor of <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.panel.aspx">Panel</a>:
</p>
<pre class="prettyprint lang-cs">
   // .Net framework code
   public Panel() : base(HtmlTextWriterTag.Div) { }
</pre>
<p>So, using Panel provides another way to implement a web control that owns a distinct part of a page.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2008%2F07%2F30%2Fhow-to-modify-the-enclosing-tag-of-a-web-control%2F&amp;title=How%20to%20modify%20the%20enclosing%20tag%20of%20a%20web%20control" id="wpa2a_34"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2008/07/30/how-to-modify-the-enclosing-tag-of-a-web-control/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code based, dynamic CAML query composition</title>
		<link>http://www.bugfree.dk/blog/2008/07/03/code-based-dynamic-caml-query-composition/</link>
		<comments>http://www.bugfree.dk/blog/2008/07/03/code-based-dynamic-caml-query-composition/#comments</comments>
		<pubDate>Thu, 03 Jul 2008 18:50:52 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2008/07/03/code-based-dynamic-caml-query-generation/</guid>
		<description><![CDATA[Today I faced an interesting challenge while querying list items in SharePoint. On a page I have a control that displays list items based on the terms used to tag the page, i.e., the content type on which the page is based contains a multi-valued field that holds a subset of predefined tags. Similarly, for [...]]]></description>
			<content:encoded><![CDATA[<p>Today I faced an interesting challenge while querying list items in SharePoint. On a page I have a control that displays list items based on the terms used to tag the page, i.e., the content type on which the page is based contains a multi-valued field that holds a subset of predefined tags. Similarly, for items in a SharePoint list, each item is tagged using a subset of the same predefined tags. The responsibility of the control is then to (1) read the tags associated with the page and (2) query the tags of the list items in an OR-wise fashion. The (3) outcome is then displayed by the control as a set of context specific items.
</p>
<p>To decide on the items to display, an initial approach might be to go through the list one item at a time, looking for matching tags. But <a href="http://technet.microsoft.com/en-us/library/cc262813.aspx">working with large lists in SharePoint</a> this approach is not recommended. Alternatively, the predicate against which each item in the list is evaluated could take on the form of a CAML query. Looking for items matching a single tag is then easily expressed:</p>
<pre class="prettyprint lang-xml">
   &lt;Where&gt;
      &lt;Eq&gt;
         &lt;FieldRef Name='MyField' /&gt;
         &lt;Value Type='LookupMulti'&gt;tag1&lt;/Value&gt;
      &lt;/Eq&gt;
   &lt;/Where&gt;
</pre>
<p>Next, consider a query with two tags OR&#8217;ed together. Although more verbose, the query is still fairly straightforward to compose on the fly:</p>
<pre class="prettyprint lang-xml">
   &lt;Where&gt;
      &lt;Or&gt;
         &lt;Eq&gt;
            &lt;FieldRef Name='MyField' /&gt;
            &lt;Value Type='LookupMulti'&gt;tag1&lt;/Value&gt;
         &lt;/Eq&gt;
         &lt;Eq&gt;
            &lt;FieldRef Name='MyField' /&gt;
            &lt;Value Type='LookupMulti'&gt;tag2&lt;/Value&gt;
         &lt;/Eq&gt;
      &lt;/Or&gt;
   &lt;/Where&gt;
</pre>
</p>
<p>However, for CAML queries where more than two tags are OR&#8217;ed together, the binary nature of the OR operator works against us. Where real programming languages have their parsers automatically transform an expression like (a || b || c) into ((a || b) || c), the CAML query parser applies no such transform &#8212; In a sense CAML is more like an XML serialized, abstract syntax tree than a query language intended for direct use:</p>
<pre class="prettyprint lang-xml">
    &lt;Where&gt;
      &lt;Or&gt;
         &lt;Or&gt;
            &lt;Eq&gt;
               &lt;FieldRef Name='MyField' /&gt;
               &lt;Value Type='LookupMulti'&gt;tag1&lt;/Value&gt;
            &lt;/Eq&gt;
            &lt;Eq&gt;
               &lt;FieldRef Name='MyField' /&gt;
               &lt;Value Type='LookupMulti'&gt;tag2&lt;/Value&gt;
            &lt;/Eq&gt;
         &lt;/Or&gt;
         &lt;Eq&gt;
            &lt;FieldRef Name='MyField' /&gt;
            &lt;Value Type='LookupMulti'&gt;tag3&lt;/Value&gt;
         &lt;/Eq&gt;
      &lt;/Or&gt;
   &lt;/Where&gt;
</pre>
<p>So how do we go about composing a query that OR together <em>n</em> tags (not to mention a mix of ORs and ANDs)? One approach might be using the <a href="http://www.u2u.info/SharePoint/U2U%20Community%20Tools/Forms/AllItems.aspx">U2U CAML Query Builder</a>. The tool delivers a UI for formulating queries, but also exposes its <a href="http://www.u2u.be/res/Article.aspx?ART=camlquerybuilderv2">CAML query builder API</a> as a .Net assembly. Unfortunately, documentation on how to use the builder is sparse. Nonetheless, I went for the case of composing a query that OR together three tags:</p>
<pre class="prettyprint lang-cs">
   string ComposeCamlQuery() {
      Builder b = new Builder(CamlTypes.GetListItems);
      b.AddViewField("Title");
      b.AddViewField("MyField");

      bool addCombinerNode;
      foreach (string tag in new string[] { "tag1", "tag2", "tag3" })
         b.AddWhereField("MyField", tag, "LookupMulti",
                         "Or", out addCombinerNode);
      return b.CamlDocument.InnerXml;
   }
</pre>
<p>The outcome is a rather strange looking CAML query with extra &lt;And&gt;&lt;/And&gt; and missing &lt;Eq&gt;&lt;/Eq&gt; tags. Funny thing is that this type of the query can be correctly composed through the UI, so most likely I&#8217;m not using the API correctly:</p>
<pre class="prettyprint lang-xml">
   &lt;Where&gt;
      &lt;And&gt;
         &lt;And&gt;
            &lt;Or&gt;
               &lt;FieldRef Name="MyField" /&gt;
               &lt;Value Type="LookupMulti"&gt;tag1&lt;/Value&gt;
            &lt;/Or&gt;
            &lt;Or&gt;
               &lt;FieldRef Name="MyField" /&gt;
               &lt;Value Type="LookupMulti"&gt;tag2&lt;/Value&gt;
            &lt;/Or&gt;
         &lt;/And&gt;
         &lt;Or&gt;
            &lt;FieldRef Name="MyField" /&gt;
            &lt;Value Type="LookupMulti"&gt;tag3&lt;/Value&gt;
         &lt;/Or&gt;
      &lt;/And&gt;
   &lt;/Where&gt;
</pre>
<p>I eventually abandoned the idea of using the CAML Query Builder API. Instead, a colleague pointed me to <a href="http://www.sharepointblogs.com/tmt/archive/2007/08/30/dynamic-caml-query.aspx">Waldek Mastykarz&#8217;s post</a> on generating dynamic CAML queries. As long as all tags are to be either AND&#8217;ed or OR&#8217;ed together, Mastykarz provides an elegant solution, which I modified to be recursive, more generic, and read like an induction proof (at a negligible performance cost):</p>
<pre class="prettyprint lang-cs">
   ComposeCamlQuery(new[] { "tag1", "tag2", "tag3" },
                    "Or",
                    "&lt;Where&gt;{0}&lt;/Where&gt;",
                    @"&lt;Eq&gt;
                       &lt;FieldRef Name='MyField' /&gt;
                       &lt;Value Type='LookupMulti'&gt;{0}&lt;/Value&gt;
                      &lt;/Eq&gt;");

   string ComposeCamlQuery(IList&lt;string&gt; ops, string relOp,
                           string query, string leaf) {
      return ops.Count == 1
         ? string.Format(query,
                         string.Format(leaf, ops[0]))
         : ComposeCamlQuery(ops.Skip(1).ToList(),
                            relOp,
                            string.Format(query,
                               string.Format("&lt;{0}&gt;{1}{{0}}&lt;/{0}&gt;",
                               relOp,
                               string.Format(leaf, ops[0]))),
                            leaf);
   }
</pre>
<p>Obviously, more complex code could be written for a mix of AND&#8217;s and OR&#8217;s. Before doing so, however, you probably want to evaluate other approaches for filtering list items:
</p>
<ol>
<li>Formulate a simpler, too general query and post-process the result
</li>
<li>Formulate smaller queries and optionally merge the results and do post-processing
</li>
<li>Use the SharePoint Search API
</li>
</ol>
<p>I also considered such alternatives as <a href="http://www.codeplex.com/LINQtoSharePoint">Linq to SharePoint</a> or <a href="http://www.codeplex.com/camldotnet">Caml.net</a>, but although the first holds a lot of promise, it isn&#8217;t ready for prime time. As for the latter, its focus is more on composing type-safe queries than dynamic ones, so it&#8217;s more of a supplement to the first two alternatives.</p>
<p>As for SharePoint Search, the downside is that search has to be configured and that the list must have been indexed for the outcome to be accurate. Depending on the frequency with which the list is modified, the time between incremental crawls, and the context in which the results are displayed, the search approach may or may not be the solution you&#8217;re looking for.</p>
<p>
<b>Update, July 19</b>: Added recursive code solution.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2008%2F07%2F03%2Fcode-based-dynamic-caml-query-composition%2F&amp;title=Code%20based%2C%20dynamic%20CAML%20query%20composition" id="wpa2a_36"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2008/07/03/code-based-dynamic-caml-query-composition/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>My SharePoint developer’s companion</title>
		<link>http://www.bugfree.dk/blog/2008/05/19/my-sharepoint-developer%e2%80%99s-companion/</link>
		<comments>http://www.bugfree.dk/blog/2008/05/19/my-sharepoint-developer%e2%80%99s-companion/#comments</comments>
		<pubDate>Mon, 19 May 2008 19:17:04 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Book]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2008/05/18/my-sharepoint-developer%e2%80%99s-companion/</guid>
		<description><![CDATA[As part of my preparation for the SharePoint configuration exams (70-630 and 70-731), I just finished working my way through Bill English&#8216;s SharePoint Administrator&#8217;s Companion. This book obviously targets SharePoint administrators. But after finishing the book, I believe it&#8217;s a must read for SharePoint developers as well. As such, I&#8217;d argue that a developer should [...]]]></description>
			<content:encoded><![CDATA[<p>As part of my preparation for the SharePoint configuration exams (<a href="http://www.microsoft.com/learning/exams/70-630.mspx">70-630</a> and <a href="http://www.microsoft.com/learning/exams/70-631.mspx">70-731</a>), I just finished working my way through <a href="http://mindsharpblogs.com/Bill/">Bill English</a>&#8216;s <a href="http://www.amazon.com/Microsoft%C2%AE-Office-SharePoint%C2%AE-Administrators-Companion/dp/0735622825/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1211133765&amp;sr=8-1">SharePoint Administrator&#8217;s Companion</a>.
</p>
<p>This book obviously targets SharePoint administrators. But after finishing the book, I believe it&#8217;s a must read for SharePoint developers as well. As such, I&#8217;d argue that a developer should know what and how SharePoint is capable of, starting with the point and click approach of this book and then progressing towards code. And by capable I&#8217;m referring to all parts of SharePoint, including the Central Administration and the Shared Services Provider.
</p>
<p>Knowing the capabilities of point and click comes in handy when discussing requirements. It often lays the groundwork for a prototype and helps you figure out where to extend SharePoint to fulfill the business needs. In addition, knowing what SharePoint can do on a general level makes estimates more reliable. Learning about administrative tasks also has the added benefit of establishing a common terminology between a developer and an administrator.
</p>
<p>All in all, the SharePoint Administrator&#8217;s Companion does a solid job of providing an overview of the capabilities of the SharePoint platform, demonstrated mostly through point and click. I&#8217;d therefore advocate that any developer should know the content of this book by heart, and use it as a starting point before moving on to more code-centric books such as the <a href="http://www.amazon.com/Microsoft-Windows-SharePoint-Services-Developer/dp/0735623201/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1211147074&amp;sr=8-1">Inside Microsoft Windows SharePoint Services 3.0</a> and the <a href="http://www.amazon.com/Inside-Microsoft-Office-SharePoint-Server/dp/0735623686/ref=bxgy_cc_b_img_a">Inside Microsoft Office SharePoint Service 2007</a>.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2008%2F05%2F19%2Fmy-sharepoint-developer%25e2%2580%2599s-companion%2F&amp;title=My%20SharePoint%20developer%E2%80%99s%20companion" id="wpa2a_38"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2008/05/19/my-sharepoint-developer%e2%80%99s-companion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>70-541: WSS 3.0, application development</title>
		<link>http://www.bugfree.dk/blog/2007/12/21/70-541-wss-30-application-development/</link>
		<comments>http://www.bugfree.dk/blog/2007/12/21/70-541-wss-30-application-development/#comments</comments>
		<pubDate>Fri, 21 Dec 2007 16:23:59 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2007/12/21/70-541-wss-30-application-development/</guid>
		<description><![CDATA[Today I passed my first Microsoft exam ever, the 70-541: Microsoft Windows SharePoint Services 3.0, Application Development. In preparation for the exam I found the Inside Microsoft Windows SharePoint Services 3.0 book and the Windows SharePoint Services 3.0 SDK to be the best study materials. In addition, I looked to others for tips and tricks. [...]]]></description>
			<content:encoded><![CDATA[<p>Today I passed my first Microsoft exam ever, the <a href="http://www.microsoft.com/learning/exams/70-541.mspx">70-541</a>: Microsoft Windows SharePoint Services 3.0, Application Development.</p>
<p>In preparation for the exam I found the <a href="http://www.amazon.com/Microsoft-Windows-SharePoint-Services-Developer/dp/0735623201/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1198497448&#038;sr=8-1">Inside Microsoft Windows SharePoint Services 3.0</a> book and the <a href="http://msdn2.microsoft.com/en-us/library/ms472057.aspx">Windows SharePoint Services 3.0 SDK</a> to be the best study materials. In addition, I looked to <a href="http://www.sharepoint-tips.com/2007/01/sharepoint-2007-beta-exams-tips.html">others</a> for tips and tricks. </p>
<p>I found the SDK to be supprisingly thorough, compared to the book, which doesn&#8217;t cover the entire curriculum. The book alone does get one enough points to pass the exam, though.</p>
<p>Overall the exam questions could benefit from a review for verbosity and clear wording. Also, one question was about the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.page.registerhiddenfield(VS.80).aspx">RegisterHiddenField</a> method and the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.page.registerhiddenfield(VS.80).aspx">RequestFromAdminPort</a> property, which MSDN marks as obsolete. Another question was about adding a column to a content type and pushing the change to a list based on the content type. On that question I could&#8217;ve sworn that two of the possible answers were correct.</p>
<p>Nonetheless, learning SharePoint with a specific goal and deadline in mind serves as a good motivator.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2007%2F12%2F21%2F70-541-wss-30-application-development%2F&amp;title=70-541%3A%20WSS%203.0%2C%20application%20development" id="wpa2a_40"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2007/12/21/70-541-wss-30-application-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Good SharePoint development practices</title>
		<link>http://www.bugfree.dk/blog/2007/07/29/good-sharepoint-development-practices/</link>
		<comments>http://www.bugfree.dk/blog/2007/07/29/good-sharepoint-development-practices/#comments</comments>
		<pubDate>Sun, 29 Jul 2007 14:25:23 +0000</pubDate>
		<dc:creator>Ronnie Holm</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.bugfree.dk/blog/2007/07/29/future-sharepoint-development-environment/</guid>
		<description><![CDATA[Lately I&#8217;ve been working on creating a portal with Windows SharePoint Services 2007 (WSS 3.0) for a large customer. The easy and intuitive way to create such a portal is to configure it through the web browser and using SharePoint Designer (a renamed and spruced up FrontPage) for everything not code-related. Unfortunately, using the web [...]]]></description>
			<content:encoded><![CDATA[<p>Lately I&#8217;ve been working on creating a portal with <a href="http://www.microsoft.com/sharepoint/default.mspx">Windows SharePoint Services 2007</a> (WSS 3.0) for a large customer. The easy and intuitive way to create such a portal is to configure it through the web browser and using SharePoint Designer (a renamed and spruced up FrontPage) for everything not code-related. </p>
<p>Unfortunately, using the web interface and SharePoint Designer doesn&#8217;t scale well. With the drag and drop tools there is just no real support for deploying your portal to another server, and hence to unify the individual contributions of team members.</p>
<p>Therefore, the <a href="http://msdn2.microsoft.com/en-us/library/bb530302.aspx">current</a> way to go for any real SharePoint development is to work with the 12 Hive directly. Named after Office 12 (Office 2007), the 12 Hive is a hierarchy of xml files residing in &#8220;Program Files\Common Files\Microsoft Shared\web server extensions\12&#8243; that controls almost everything about how SharePoint and your portal behaves.</p>
<p>Using Visual Studio (VS), you’d create a 12 Hive parallel file hierarchy of new folders and files and work within VS as usual. Like with any other project, you&#8217;d use version control, <a href="2006/11/19/cruisecontrolnet-and-build-queues/">continuous integration</a>, and so on, on xml and .Net code. With VS, deployment (to your development box) would then involve checking out xml and code from source control and compiling the code. </p>
<p>Then, using a build script, you&#8217;d xcopy the xml and binary into the 12 Hive and GAC, respectively, and possibly run various stsadm commands to activate your features. Alternatively, you&#8217;d create a SharePoint solution package that pretty much does the same thing when invoked by SharePoint.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.bugfree.dk%2Fblog%2F2007%2F07%2F29%2Fgood-sharepoint-development-practices%2F&amp;title=Good%20SharePoint%20development%20practices" id="wpa2a_42"><img src="http://www.bugfree.dk/blog/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.bugfree.dk/blog/2007/07/29/good-sharepoint-development-practices/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

