Showing posts with label Windows SharePoint Services. Show all posts
Showing posts with label Windows SharePoint Services. Show all posts

Monday, October 13, 2008

Add Web Part to SharePoint with F# Script

In building deployment scripts for SharePoint, there are times when I want to automate the deployment of webparts by building a script to automatically add web parts to specific web pages. I found a book that talked about writing these types of scripts in Mark Gerow's SharePoint 2007 Development Recipes, which had many other useful examples of scripting SharePoint 2007. He's already written a C# version of this script that I've decided to implement in F# for contrast.

Here's the F# version of the code:


#light
#I @"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI"
#r @"Microsoft.SharePoint.dll"

open Microsoft.SharePoint
open Microsoft.SharePoint.WebPartPages
open System.Web.UI.WebControls.WebParts
open System.Xml

let addWebPart page wp zone order pscope (web:SPWeb) =
let webparts = (page, pscope) |> web.GetLimitedWebPartManager
(wp,zone,order) |> webparts.AddWebPart
wp |> webparts.SaveChanges

let disableCheckout (splist:SPList) spOperation =
let oldvalue = splist.ForceCheckout
splist.ForceCheckout <- false
splist.Update()

spOperation

splist.ForceCheckout <- oldvalue
splist.Update()

let spUnsafeUpdate spOperation (siteurl:string) (webname:string) doclib =
let site = new SPSite(siteurl)
let web = site.OpenWeb(webname)
web.AllowUnsafeUpdates <- true

// Disable versioning when updating Document Library
match doclib with
| "" ->
spOperation web
| _ ->
disableCheckout
<| web.Lists.Item(doclib)
<| spOperation web

web.Update()
web.Dispose()
site.Dispose()


let siteurl = "http://localhost/"
let webname = "recipes"
let doclibName=""

// Add page viewer web part
let viewer = new PageViewerWebPart(SourceType=PathPattern.URL,
ContentLink="http://msdn.microsoft.com/en-us/fsharp/default.aspx")

// Add webpart using unsafe updates...
// Experimenting with ranges of expression with F#'s pipeline operators.
// Traditional format for the following code would be
// spUnsafeUpdate siteurl webname doclibName (addWebPart "Default.aspx" editor "Right" 0 Personalization.Shared)
//
addWebPart
<| "Default.aspx"
<| viewer
<| "Left"
<| 0
<| PersonalizationScope.Shared
|> spUnsafeUpdate
<| siteurl
<| webname
<| doclibName


// Add content editor web part
let xmlDoc = new XmlDocument()
let xmlElem = xmlDoc.CreateElement("xmlElem")
xmlElem.InnerText <- "Test content editor web part"
let editor = new ContentEditorWebPart(Content=xmlElem)

addWebPart
<| "Default.aspx"
<| editor
<| "Right"
<| 0
<| PersonalizationScope.Shared
|> spUnsafeUpdate
<| siteurl
<| webname
<| doclibName


Wednesday, October 01, 2008

More SharePoint scripting with F#

F# Interactive mode in Visual Studio is a great way to interactively script SharePoint objects. I'd almost compare this to using sql query editor against a database. I can write the SharePoint code in Visual Studio and have all the code completion and type checking features. I can select the portion of the source code and execute it by pressing Alt+Enter. It's pretty sweet. Combine this with queries built with CAML statements, I can basically do ad hoc queries against SharePoint objects. I don't know any other tool in the SharePoint tool suite that can do this. I can easily imagine a SharePoint management studio tool built with customized Visual Studio plugins that provide a way to explore the SharePoint objects graphically similar to what SQL Server Management Studio does for SQL Server database and uses F# to manipulate SharePoint similar to how SQL manipulates the database.

Here are some example scripts adapted from the book Inside Microsoft Windows SharePoint Services 3.0 by Ted Pattison and Daniel Larson


#light
#I @"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI"
#r @"Microsoft.SharePoint.dll"

open System
open Microsoft.SharePoint

// Utility functions to convert SPxCollection to seq<SPx>
let SPListToSeq (splist:SPListCollection) =
seq { for i in 0 .. (splist.Count-1) -> splist.get_Item(i)}

let SPFieldToSeq (splist:SPFieldCollection) =
seq { for i in 0 .. (splist.Count-1) -> splist.get_Item(i)}

let SPListItemToSeq (splist:SPListItemCollection) =
seq { for i in 0 .. (splist.Count-1) -> splist.get_Item(i)}

let SPContentTypeToSeq (splist:SPContentTypeCollection) =
seq { for i in 0 .. (splist.Count-1) -> splist.get_Item(i)}

let site = new SPSite("http://localhost/")
let web = site.OpenWeb()

// Add new SharePoint List called "F# SharePoint News
let id = ("F# SharePoint News",
"List for news on F# and SharePoint items.",
SPListTemplateType.Announcements)
|> web.Lists.Add
let list = web.Lists.[id]
list.OnQuickLaunch <- true
list.Update()

// Add news item to the newly created SharePoint List
let newItem = list.Items.Add()
newItem.["Title"] <-"Check for expired items today!"
newItem.["Body"] <- "We're are expiring this today and see if our query works!"
newItem.["Expires"] <- DateTime.Now
newItem.Update()


// Checking all items in "F# SharePoint News" list that expires today
let queryClause =
@"<Where>
<Eq>
<FieldRef Name='Expires' />
<Value Type='DateTime'><Today /></Value>
</Eq>
</Where>"

let query = new SPQuery(ViewFields = @"<FieldRef Name='Title'/><FieldRef Name='Expires'/>",
Query=queryClause)

let mylist = web.Lists.["F# Sharepoint News"]
SPListItemToSeq (mylist.GetItems(query))
|> Seq.iter (fun x -> printf "%s\n" x.Title)

// Checking available content types
SPContentTypeToSeq web.AvailableContentTypes
|> Seq.iter (fun x -> printf "%s\n\tDescription = %s\n\tID=%s\n" x.Name x.Description (x.Id.ToString()))

web.Close()
site.Close()

Tuesday, September 09, 2008

Exploring SharePoint 2007 Object Model with F#

I have been busy with other things that detracted from continued efforts in working with F# and WPF. While I've been busy, I found out that F# 1.9.6 has been released. After quick perusal of F# 1.9.6 release notes, I realized my previously posted codes will break during compilation. Two immediate items that I noticed are:

  • IEnumerable.* are deleted
  • base is now a keyword

I haven't had time to scour my previously posted F# code and correct it to work with F# 1.9.6 so be forewarned if you're trying to compile my previously posted F# code with the new F# compiler. Hopefully, sometime in the future I'll be able to correct the posted code so it compiles and runs with the new F# compiler.

Lately, I have been exploring other pieces of Microsoft technologies such SharePoint 2007, InfoPath 2007, Windows Workflow Foundation, and Excel Services with the goal of crafting a strategy on how to best leverage these technologies in a corporate environment. I needed a way to get up to speed quickly in the SharePoint environment and wanted a way to interactively explore the Windows SharePoint Services (WSS) object model.

I immediately thought of using F# interactive as way to explore WSS object model. I fired up the new F# 1.9.6 interactive shell and wanted to follow the example codes in the book Inside Microsoft Windows SharePoint Services 3.0 by Ted Pattison and Daniel Larson.

Before I could try out the examples in the aforementioned book, I had to created a MOSS 2007 system in a Virtual PC environment based on the instructions by Tony Zink in his post How to Create a MOSS 2007 VPC Image: The Whole 9 Yards .

One problem that I ran into while trying out the examples from the book is that I'm unable to iterate through SPListCollection. SPListCollection does not implement IEnumerable and I do not know an equivalent foreach capability in F#. As a workaround, I implemented the SPListCollectionAdapter as described by Asfar Sadewa in his blog entry linq-ing splistcollection. After implementing this adapter, I can now iterate through SPListCollection as shown in the following example:


Exploring WSS Object Model with F#

#light
#I @"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI"
#r @"Microsoft.SharePoint.dll"
#r @"c:\dev\F#\SharePoint\SharePointUtility.dll"

open Microsoft.SharePoint
open SharePoint.Utility

let path="http://localhost/"
let collection = new SPSite(path)
let site = collection.RootWeb
let lists = SPListCollectionAdapter(site.Lists)
Seq.iter (fun (x:SPList) -> printf "%s\n" x.Title) lists

I was highly encouraged by this initial success. I next tried to implement a simple hello world SharePoint feature as shown in the following code:


Building Test Hello World Sharepoint Feature

#light
namespace HelloWorld

open System
open Microsoft.SharePoint

// From Chapter 1 of Inside Microsoft Windows SharePoint Services 3.0 by Ted Pattison & Daniel Larson
type FeatureReceiver() =
class
inherit SPFeatureReceiver()


override this.FeatureInstalled _ = ()
override this.FeatureUninstalling _ = ()

override this.FeatureActivated (properties:SPFeatureReceiverProperties) =
let site = properties.Feature.Parent :?> SPWeb
site.Properties.["OriginalTitle"] <- site.Title
site.Properties.Update()
site.Title <- "Hello World"
site.Update()

override this.FeatureDeactivating (properties:SPFeatureReceiverProperties) =
let site = properties.Feature.Parent :?> SPWeb
site.Title <- site.Properties.["OriginalTitle"]
site.Update()
end

I was delighted that this worked flawlessly in SharePoint 2007. It looks like I can go back to using some F# in exploring SharePoint 2007.