02 April 2009

Microsoft SharePoint Designer 2007 is now free

When I first heared the news that Microsoft was going to give away SharePoint Designer 2007 for free, I thought it was a April Fool's joke. But now on April 2nd, I actual believe. :-)

Download it from Microsoft Download Center.
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=baa3ad86-bfc1-4bd4-9812-d9e710d44f42

24 March 2009

Understanding Field Controls and Web Parts in SharePoint Server 2007 Publishing Sites

I just read an great article from Andrew Connell about the use of Field Controls and Web Parts in MOSS 2007 Publishing sites.

He describes clearly the advantages and disadvantages of using them and that you should considered in the early phase of the implementation of a new publishing site which approach to use.

Read the article on MSDN
Understanding Field Controls and Web Parts in SharePoint Server 2007 Publishing Sites.

15 March 2009

SharePoint PublishingWeb class inside out

For a project I've done in the past, I had to create an application that could report all sorts of SharePoint site information. While developing this application, the biggest challenge was to gather information about publishing sites, without the use off the Micosoft.SharePoint.Publishing assembly. The reason for this was that the application also had to run on a WSS only installation of SharePoint. During refactoring I found out that most information was stored in the propertybag of the web.

I created a SharePoint Publishing helper class that can retrieve values for the following PublishingWeb properties and functions.
  • GetAvailablePageLayouts
  • GetIncludeInNavigation
  • IncludeInCurrentNavigation
  • IncludeInGlobalNavigation
  • IncludePagesInNavigation
  • IncludeSubSitesInNavigation
  • InheritAlternateCssUrl
  • InheritCurrentNavigation
  • InheritCustomMasterUrl
  • InheritGlobalNavigation
  • IsInheritingAvailablePageLayouts
  • IsInheritingAvailableWebTemplates
  • IsPublishingWeb
  • NavigationAutomaticSortingMethod
  • NavigationShowSiblings
  • NavigationSortAscending
  • OrderingMethod
  • PagesListId
public static class SharePointPublishingHelper
{
 public static bool IsPublishingWeb(SPWeb web)
 {
  return GetBooleanValueFromPropertyBag(web, "__PublishingFeatureActivated", false);
 }

 public static bool IncludeInGlobalNavigation(SPWeb web)
 {
  return GetIncludeInNavigation(web, "__GlobalNavigationExcludes");
 }
 
 public static bool IncludeInCurrentNavigation(SPWeb web)
 {
  return GetIncludeInNavigation(web, "__CurrentNavigationExcludes");
 }
 
 private static bool GetIncludeInNavigation(SPWeb web, string propertyKey)
 {
  if(web == null)
  {
   throw new ArgumentNullException("web");
  }
  if (string.IsNullOrEmpty(propertyKey))
  {
   throw new ArgumentException("The argument can't be null or a empty string.", "propertyKey");
  }
 
  SPWeb parentWeb = web.ParentWeb;
  if (!web.IsRootWeb && parentWeb != null)
  {
   string globalNavigationExcludes = GetValueFromPropertyBag(parentWeb, propertyKey) as string;
   if (!string.IsNullOrEmpty(globalNavigationExcludes))
   {
    string[] list = globalNavigationExcludes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
    bool found = list.Contains(web.ID.ToString("D"));
 
    return !found;
   }
  }
 
  return true;
 }
 
 public static bool InheritGlobalNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return web.Navigation.UseShared;
 }
 
 public static bool InheritCurrentNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritCurrentNavigation", true);
 }
 
 public static bool IncludeSubSitesInNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__IncludeSubSitesInNavigation", true);
 }
 
 public static bool IncludePagesInNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__IncludePagesInNavigation", true);
 }
 
 public static string OrderingMethod(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__NavigationOrderingMethod").ToString();
  switch (value)
  {
   case "0":
    return "Automatic";
   case "1":
    return "ManualWithAutomaticPageSorting";
   case "2":
    return "Manual";
   default:
    break;
  }
 
  return "Manual";
 }
 
 public static bool NavigationShowSiblings(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return GetBooleanValueFromPropertyBag(web, "__NavigationShowSiblings", true);
 }
 
 public static string NavigationAutomaticSortingMethod(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__NavigationAutomaticSortingMethod").ToString();
  switch (value)
  {
   case "0":
    return "Title";
   case "1":
    return "CreatedDate";
   case "2":
    return "LastModifiedDate";
   default:
    break;
  }
 
  return "Title";
 }
 
 public static bool NavigationSortAscending(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__NavigationSortAscending", true);
 }
 
 public static Guid PagesListId(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__PagesListId").ToString();
  if (string.IsNullOrEmpty(value))
  {
   return Guid.Empty;
  }
 
  return new Guid(value);
 }
 
 public static bool InheritCustomMasterUrl(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritsCustomMasterUrl", false);
 }
 
 public static bool InheritAlternateCssUrl(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritsAlternateCssUrl", false);
 }
 
 public static bool IsInheritingAvailableWebTemplates(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritWebTemplates", false);
 }
 
 public static bool IsInheritingAvailablePageLayouts(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__PageLayouts").ToString();
  if (!string.IsNullOrEmpty(value))
  {
   return value.Equals("__inherit", StringComparison.InvariantCultureIgnoreCase);
  }
 
  return false;
 }
 
 public static string[] GetAvailablePageLayouts(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  List list = new List();
 
  string value = GetValueFromPropertyBag(web, "__PageLayouts").ToString();
  if (!string.IsNullOrEmpty(value))
  {
   SPWeb rootWeb = web.Site.RootWeb;
 
   var pageLayouts = XElement.Parse(value).Elements("layout");
   foreach (var pageLayout in pageLayouts)
   {
    string itemUrl = null;
 
    string id = null;
    XAttribute guidAttribute = pageLayout.Attribute("guid");
    if (guidAttribute != null)
    {
     id = guidAttribute.Value;
    }
 
    // first try to find pagelayout by id
    if (!string.IsNullOrEmpty(id))
    {
     SPFile file = rootWeb.GetFile(new Guid(id));
     if (file != null && file.Exists)
     {
      itemUrl = file.ServerRelativeUrl;
     }
    }
 
    // if no pagelayout is found by id, try the url
    if (string.IsNullOrEmpty(itemUrl))
    {
     string url = null;
     XAttribute urlAttribute = pageLayout.Attribute("url");
     if (urlAttribute != null)
     {
      url = urlAttribute.Value;
     }
 
     SPFile file = rootWeb.GetFile(url);
     if (file != null && file.Exists)
     {
      itemUrl = file.ServerRelativeUrl;
     }
    }
 
    if (!string.IsNullOrEmpty(itemUrl))
    {
     list.Add(itemUrl);
    }
   }
  }
 
  return list.ToArray();
 }
 
 private static object GetValueFromPropertyBag(SPWeb web, string key)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
  if (string.IsNullOrEmpty(key))
  {
   throw new ArgumentException("The argument can't be null or a empty string.", "key");
  }
 
  object value = null;
 
  // First check the AllProperties collection
  if (web.AllProperties.ContainsKey(key))
  {
   value = web.AllProperties[key];
  }
 
  // Still empty, check also the Properties collection
  if (value == null)
  {
   if (web.Properties.ContainsKey(key))
   {
    value = web.Properties[key];
   }
  }
 
  return value;
 }
 
 private static bool GetBooleanValueFromPropertyBag(SPWeb web, string key, bool defaultValue)
 {
  string value = GetValueFromPropertyBag(web, key) as string;
 
  bool ret;
  if (!bool.TryParse(value, out ret))
  {
   ret = defaultValue;
  }
 
  return ret;
 }
}

08 March 2009

Using LINQ to query SharePoint collections

I came across a challenge when I wanted to using LINQ on several SharePoint collection classes and I noticed that it wasn't possible to do this....So why not? LINQ lets you query any collection implementing the IEnumerable interface and after some research I found that most of the SharePoint collections don't implement this interface.

Ok, how to overcome this challenge? Arrays implement IEnumerable....Copy the items from the collection to an array! SharePoint collections implement the ICollection interface which provides the method: void CopyTo(Array array, int index), so this should not be a problem. Well it does!

SharePoint collections derive from a class called SPBaseCollection and this class implements ICollection. But because the explicit implementation of CopyTo, this method is private.

For this I wrote a little helper extension method that makes it possible to copy a SharePoint collections (or any class that implements ICollection) to an array of a particular type and validate for null at the same time.
public static class Helpers
{
 public static T[] CopyToArray(this ICollection collection)
 {
     if (collection == null) { return new T[0]; }

     T[] array = new T[collection.Count];
     collection.CopyTo(array, 0);

     return array;
 }
}
Now it is possible to make Linq queries like this:
using (SPSite site = new SPSite("http://demosite"))
{
 using (SPWeb web = site.OpenWeb())
 {
     // Get all webs ordered by Title
     var items1 = web.Webs.CopyToArray< SPWeb>().OrderBy(p => p.Title);
     foreach (var item in items1)
     {
         Console.WriteLine(item.Title);
     }

     // Get all content types grouped by group and ordered by group and name
     var items2 = web.ContentTypes.CopyToArray< SPContentType>().GroupBy(p => p.Group).OrderBy(g => g.Key);
     foreach (IGrouping<> group in items2)
     {
         Console.WriteLine(group.Key);

         foreach (var item in group.OrderBy(p => p.Name))
         {
             Console.WriteLine(item.Name);
         }
     }

     // Get a list by name and not by title
     var list = web.Lists.CopyToArray< SPList>().SingleOrDefault(p => p.RootFolder.Name.Equals("pages", StringComparison.InvariantCultureIgnoreCase));
     if (list != null)
     {
         Console.WriteLine("List: {0} found!", list.Title);
     }
 }
}

23 February 2009

Create a Fake HttpContext for SharePoint

While coding for SharePoint I usualy start by putting code in a console application to create the nessasary functionaly and on a later stage move it over to a browser application. I do this because I find it speeding up the development cycle, because SharePoint deployment cause a bit of overhead. But once in a while I need the HttpContext.Current to be set and I there isn't one in a console app.

To overcome this problem I created my own WorkerRequest class and a helper method that returns a HttpContext to fake a current http context. Both the class and method take a SPWeb as contructor parameter to put the correct SharePoint context into the http context.
public class FakeSharePointWorkerRequest : SimpleWorkerRequest
{
    private readonly string _ServerName;

    public FakeSharePointWorkerRequest(SPWeb web) : base(web.ServerRelativeUrl, web.Site.WebApplication.IisSettings[SPUrlZone.Default].Path.FullName, string.Empty, string.Empty, null)
    {
        _ServerName = web.Site.HostName;
    }

    public override string GetServerName()
    {
        return _ServerName;
    }
}

public static HttpContext GetFakeHttpContextForSharePoint(SPWeb web)
{
    FakeSharePointWorkerRequest workerRequest = new FakeSharePointWorkerRequest(web);
    HttpContext httpContext = new HttpContext(workerRequest);
    httpContext.Items["HttpHandlerSPWeb"] = web;
    httpContext.Items["HttpHandlerSPSite"] = web.Site;
 
    return httpContext;
}
Usage example
using(SPSite site = new SPSite("http://demosite"))
{
    using(SPWeb web = site.OpenWeb())
    {
        bool httpContextIsFake = false;
        if (HttpContext.Current == null)
        {
            // Must be set before using the SPLimitedWebPartManager in a console app
            HttpContext.Current = GetFakeHttpContextForSharePoint(web);
            httpContextIsFake = true;
        }
 
        // Do your own thingies!
        // .....
 
        // Don't forget to reset the current http context
        if (httpContextIsFake)
        {
            HttpContext.Current = null;
        }                     
    }
}

17 February 2009

Programmatically show all list templates for a SharePoint web

To programmatically create lists in a SharePoint web, I found you have to look for list templates in two different locations.

The first (obvious) location is in the ListTemplates collection on the SPWeb object, but then u would mis the custom list templates stored in the List Template Gallery.

The code belows shows all list templates for a web.

using(SPSite site = new SPSite("http://demosite"))
{
    using(SPWeb web = site.OpenWeb())
    {
        Console.WriteLine("==== List Templates");
        foreach(SPListTemplate template in web.ListTemplates)
        {
            Console.WriteLine(template.Name);
        }
  
        Console.WriteLine("==== List Templates from the List Template Gallery");
        foreach (SPListTemplate template in site.GetCustomListTemplates(web))
        {
            Console.WriteLine(template.Name);
        }
    }
}

12 February 2009

Introduction

Welcome to my webblog!

I'm Danny de Haas, a Dutch guy who is living in Amsterdam. I'm a professional software developer since 1999 and have experiences with C#, VB.NET, VB6, SQL 2000/2005, SharePoint Portal Server 2003 and MOSS 2007.

I work for a Dutch software company called Macaw and I am a member of the solution center 'Rich Internet Solutions' (RIS). Most of the time I've been busy with SharePoint Web Content Management. This platform has alot to talk about. So stay tuned! :-)

....to be continued.