January 29, 2009

Microsoft Web Platform Installer 1.0

Microsoft has launched a useful tool for .NET web developers. Here under is the overview of the product (source: Microsoft).

Overview

The Web Platform Installer (Web PI) is a simple tool that installs Microsoft's entire Web Platform, including IIS, Visual Web Developer 2008 Express Edition, SQL Server 2008 Express Edition and the .NET Framework. Using the Web Platform Installer’s user interface, you can choose to install either specific products or the entire Microsoft Web Platform onto your computer. The Web PI also helps keep your products up to date by always offering the latest additions to the Web Platform.

Here is the link:
http://www.microsoft.com/web/channel/products/WebPlatformInstaller.aspx

January 20, 2009

SharePoint BeLux Developers group on LinkedIn

I've created a new group on LinkedIn called SharePoint BeLux Developers.



This group is a place where SharePoint developers from mainly Belgium and Luxemburg can share their ideas, post articles and speak about their experiences in SharePoint development.

Here is the link to register: http://www.linkedin.com/groups?gid=1773607&trk=hb_side_g

January 15, 2009

How to create SharePoint alerts for Discussion Board list items programmatically

First, thank you to Pam for posting a good remark about my previous article: "How to create SharePoint alerts for lists or list items programmatically"

In fact, she has noticed in using my code to create an alert for a Discussion Board list item that the values stored in the ImmedSubscriptions table in the content db were not the same than an alert created from the user interface. According to the values stored in the db, an alert created from the user interface seems to be like an alert created at the list level with a filter referencing the item.

To understand why an alert for a Discussion Board list item seems to be like an alert created at the list level with a filter, we need to create an alert for a Discussion Board list item and an alert for e.g. a Documents Library list item from the user interface and to compare themselves together.

In doing that, we can see the difference between the two alerts. In the case of an alert for Discussion Board list item, the screen is exactly the same than the screen displayed for a list (more options than for a list item) and the values stored in the db show that it is like an alert for a list.





DB Values
ListId: 57AD9100-E9B8-4097-9CC3-97F87FC50CA8
ListUrl: Shared Documents
ListTitle: Shared Documents
ItemId: 1
AlertTitle: Shared Documents: WSS_Quick_Reference_Guide.doc
AlertType: 1
AlertTemplateName: SPAlertTemplateType.DocumentLibrary
EventType: -1
Filter:

In the case of an alert for Documents Library list item, the screen is the screen usually displayed for a list item and the values stored in the db show that it is an alert for a list item.





DB Values
ListId: 3F8B0E63-2005-4F5F-AF93-FDF20D54AB1A
ListUrl: Lists/Team Discussion
ListTitle: Team Discussion
ItemId: NULL
AlertTitle: Team Discussion: test
AlertType: 0
AlertTemplateName: SPAlertTemplateType.DiscussionBoard
EventType: -1
Filter: lists/team discussion/test

After a good reflection, it's logical. When you create an alert on e.g. a Documents Library list item, the alert is created at the list item level (e.g. someone changes metadata, etc...). In the case of a Discussion Board list item, when someone posts a reply, it doesn't change the list item itself. In fact, it creates a new list item linked with it. That explains why the values stored seems like to be values for a list level alert except the filter referencing the item.


In this way, the code to create an alert for a Discussion Board list item is exactly the same than the one used for a an alert for list with the filter referencing the item by its url.


using (SPSite mySiteCollection = new SPSite("http://mossjno/
"
))
{
    using (SPWeb mySite = mySiteCollection.OpenWeb(mySiteCollection.RootWeb.ID))
    {
        string myUserLogin = @"MOSSJNO\tester1";
        SPUser myUser = mySite.AllUsers[myUserLogin];
        SPAlert newAlert = myUser.Alerts.Add();
        newAlert.Title = "Test alert for Discussion Board list item";
 
        SPList myList = mySite.Lists["Team Discussion"];
        SPListItem myListItem = myList.GetItemById(1);
        newAlert.AlertType = SPAlertType.List;
        newAlert.List = myList;
        newAlert.AlertTemplate = myList.AlertTemplate;
 
        newAlert.EventType = SPEventType.All;
 
        newAlert.Filter = string.Format("<Query><BeginsWith><FieldRef Name=\"ItemFullUrl\"/><Value type=\"string\">{0}</Value></BeginsWith></Query>", myListItem.Url);
        newAlert.AlertFrequency = SPAlertFrequency.Immediate;
 
        newAlert.Update(true);
    }
}

DB Values
ListId: 3F8B0E63-2005-4F5F-AF93-FDF20D54AB1A
ListUrl: Lists/Team Discussion
ListTitle: Team Discussion
ItemId: NULL
AlertTitle: Test alert for Discussion Board list item
AlertType: 0
AlertTemplateName: SPAlertTemplateType.DiscussionBoard
EventType: -1
Filter: lists/team discussion/test

January 13, 2009

European SharePoint Best Practices Conference


The first SharePoint Best PracticesTM Conference in Washington, DC in September, 2008 was an overwhelming success. . The First European conference (April 6-8 2009) promises to be just as popular.

Link: http://www.sharepointbestpractices.co.uk/

Announcing: Community Technology Preview of Visual Studio 2008 extensions for SharePoint v1.3

The Microsoft SharePoint Team Blog has announced the CTP of Visual Studio 2008 extensions for SharePoint v1.3

Link: http://blogs.msdn.com/sharepoint/archive/2009/01/12/announcing-community-technology-preview-of-visual-studio-2008-extensions-for-sharepoint-v1-3.aspx

Storing metadata in SharePoint Lists vs. SQL Database

A colleague gave me an interesting link speaking about storing metadata in SharePoint Lists vs. SQL Database. It can help you to take the right decision about building a SharePoint application or a classic ASP.NET application.

Link: http://www.sharepointusecases.com/index.php/2008/11/storing-data-in-sharepoint-lists-vs-sql-database/

January 07, 2009

How to create a custom expiration formula and deploy it through a SharePoint solution

In this tutorial, we start from a SharePoint site based on the Team Site template.



We will apply the custom expiration formula to the out-of-the-box Shared Documents documents library. Our formula will check if the Title of the item starts with underscore and if it's the case, it will set the item expiration date to today.



To set an expiration policy, you have to click on the Information management policy settings in the Documents Library Settings.



After, you have to select Define a policy... and click on OK.



In the Edit Policy page, you have to check Enable Expiration and you will see a dropdown list with the custom expiration formula installed on the server (highlighted section).



So, let's open Visual Studio 2008 (with WSS Extensions 1.2.)...



First, you have to create a new Empty SharePoint project.





Now, he have to add 2 references to the project:
- Microsoft Office Server DLC Component (Microsoft.Office.Policy.dll)
- Windows SharePoint Service (Microsoft.SharePoint.dll)






The next step is to add the class which will contain the code for the custom expiration formula. For that, you have to add a new class to the project. In this example, I call it TitleStartingWithUnderscoreExpirationFormula.



You have to remove all the namespaces except the System one and to add the Microsoft.SharePoint and Microsoft.Office.RecordsManagement.PolicyFeatures ones. You also have to put the class as public and to implement the IExpirationFormula interface. Implementing this interface involves to write the ComputeExpireDate method which takes 2 parameters (SPListItem and XmlNode) and returns a nullable DateTime object. In this method, we have to check if the Title property of the SPListItem passed as paremeter begins with '_'. If it's the case, the method must return the today. Otherwise, it must return a null value.

using Microsoft.Office.RecordsManagement.PolicyFeatures;
using System;
using Microsoft.SharePoint;
 
namespace UnderscoreInTitlePolicy
{
    public class TitleStartingWithUnderscoreExpirationFormula : IExpirationFormula
    {
        public Nullable<DateTime> ComputeExpireDate(SPListItem item, System.Xml.XmlNode parametersData)
        {
            DateTime? expirationDate = null;
 
            if (item.Title.StartsWith("_"))
            {
                expirationDate = DateTime.Today;
            }
            return expirationDate;
        }
    }
}

To deploy our formula through a feature, we have to create a class inheriting from the SPFeatureReceiver class and to override the FeatureActivated and the FeatureDeactivating methods.
In the FeatureActivated method, we have to put the code to register our new custom formula. For that, we have to create a manifest (built using a StringBuilder object) which is a xml containing a PolicyResource node having three attributes:
- id (UnderscoreInTitlePolicy.TitleStartingWithUnderscoreExpirationFormula)
- featureId (Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration)
- type (DateCalculator)
The PolicyResource node has also 4 elements (Name, Description, AssemblyName and ClassName). To finish, we have to validate the manifest (ValidateManifest method of the PolicyResource class) and to add it the the policy resource collection (Add method of the PolicyResourceColletion class).
In the FeatureDeactivating method, we simplly have to delete the manifest from the policy resource collection (Delete method of the PolicyResourceColletion class).



using System;
using Microsoft.SharePoint;
using Microsoft.Office.RecordsManagement.InformationPolicy;
using System.Text;
 
namespace UnderscoreInTitlePolicy
{
    public class UnderscoreInTitlePolicyFeatureReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<PolicyResource xmlns='urn:schemas-microsoft-com:office:server:policy' ");
            sb.Append("  id = 'UnderscoreInTitlePolicy.TitleStartingWithUnderscoreExpirationFormula' ");
            sb.Append("  featureId='Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration' ");
            sb.Append("  type = 'DateCalculator'>");
            sb.Append("<Name>Title Starting With Underscore Expiration</Name>");
            sb.Append("<Description>Set the expiration date to today for items having the title starting with underscore</Description>");
            sb.Append("<AssemblyName>UnderscoreInTitlePolicy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5</AssemblyName>");
            sb.Append("<ClassName>UnderscoreInTitlePolicy.TitleStartingWithUnderscoreExpirationFormula</ClassName>");
            sb.Append("</PolicyResource>");
            try
            {
                PolicyResource.ValidateManifest(sb.ToString());
                PolicyResourceCollection.Add(sb.ToString());
            }
            catch { }
        }
 
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            try
            {
                PolicyResourceCollection.Delete("UnderscoreInTitlePolicy.TitleStartingWithUnderscoreExpirationFormula");
            }
            catch { }
        }
 
        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            // No operation
        }
 
        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            // No operation
        }
    }
}

The next step is to create the feature itself, for that we have to leave the Solution Explorer and switch in the WSP View.



You have to click on the new button (blank document icon). You will see that a feature (Feature 1) will be added to the solution. You have to edit the feature.xml file to set the scope of the feature to Farm and to add and specify the AssemblyReceiver and ClassReceiver attributes.



<?xml version="1.0" encoding="utf-8"?>
<Feature 
  Id="0925412d-5ac9-4acc-987e-5cec1d814d7f" 
  Title="Underscore In Title Policy Feature" 
  Scope="Farm" 
  Version="1.0.0.0" 
  Hidden="FALSE" 
  DefaultResourceFile="core" 
  xmlns="http://schemas.microsoft.com/sharepoint/"
  ReceiverAssembly="UnderscoreInTitlePolicy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5"
  ReceiverClass="UnderscoreInTitlePolicy.UnderscoreInTitlePolicyFeatureReceiver"/>

To finish, you have to rebuild the solution and to deploy it. Visual Studio automatically deploys the SharePoint solution and activate the Feature. You will see that our formula is now available in Expiration section of the Edit Policy page of your document library.







Download the project: Here

MSDN Links:
Creating a Custom Expiration Formula Based on Metadata in SharePoint Server 2007 (Part 1 of 2)
Creating a Custom Expiration Formula Based on Metadata in SharePoint Server 2007 (Part 2 of 2)