Archive for September, 2010

Adding a Webpart to home.aspx during Site creating in Enterprise Wiki

September 8, 2010

Consider following scenario:

Create a custom site template based on Enterprise Wiki (Publishing Site) and add a web part to the home page during site creating.

The creating of the template is not tricky and you can find the description here.  The tricky part is actually adding the web part to the homepage.

So here is how you can do it:

Delete the module that creates the home.aspx from the onet.xml. and create it manually in code behind (I used a feature receiver on a feature that is activated when the site is created. The method that adds the homepage can look like this.

public static void AddHomePageToDocumentLibrary(SPWeb web, string pageContent)
{
        var pubWeb = PublishingWeb.GetPublishingWeb(web);
        var pageLayout = pubWeb.GetAvailablePageLayouts()[0];
        PublishingPage newPage = pubWeb.GetPublishingPages().Add("home.aspx", pageLayout);
        newPage.ListItem[FieldId.PublishingPageContent] = pageContent;
        newPage.ListItem.Update();
        newPage.Update();
}

The page content should contain following div:

<div class='ms-rtestate-read ms-rte-wpbox' contentEditable='false'><div class='ms-rtestate-read d127f8fd-2a2e-4495-9e0f-d32d5ca2e5c7' id='div_d127f8fd-2a2e-4495-9e0f-d32d5ca2e5c7'></div><div style='display:none' id='vid_d127f8fd-2a2e-4495-9e0f-d32d5ca2e5c7'></div></div>

This div is by run time replaced with an actual webpart. The guid d127f8fd-2a2e-4495-9e0f-d32d5ca2e5c7 is important as it identifies the webpart that should be added to the page.

Finally we have to add the webpart to the webpart zone.


public static void AddWebPartToHomePage(System.Web.UI.WebControls.WebParts.WebPart webPart, SPWeb web, Guid webpartId)
        {
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager("seiten/home.aspx", PersonalizationScope.Shared))
            {
                string storageKeyId = StorageKeyToID(webpartId);
                webPart.ID = storageKeyId;
                mgr.AddWebPart(webPart, "wpz", 0);
            }
        }

private static string StorageKeyToID(Guid storageKey)
        {
            if (!(Guid.Empty == storageKey))
            {
                return ("g_" + storageKey.ToString().Replace('-', '_'));
            }
            return string.Empty;
        }

The webpart is the webpart we want to add, web is the web that we create and the guid is the guid that identifies the webpart. In our case it is d127f8fd-2a2e-4495-9e0f-d32d5ca2e5c7. The “wpz” zone is the hidden webpart zone that SharePoint 2010 uses to store inline webparts.

I tried to create these webparts in onet.xml, but it did not work. The webparts were simply not displayed, though all attributes were filled.

References

http://donalconlon.wordpress.com/2010/05/04/sp2010-creating-a-wiki-page-using-the-om/

Advertisement

Pex and Moles Testing Framework for SharePoint

September 1, 2010

Here is a quickstart for working with unit testing framework for SharePoint. This Framework is called Moles. You can download it here. It is free academic use and Microsoft partners.

So how this Framework works: It allows you to replace any method with by you defined delegate. So here is a simplistic function:

Simple Intro

public static bool IsInFuture(DateTime date)
{
	return date > DateTime.Now;
}

So this function is not easily unit testable, because the DateTime.Now is not a constant value. What we can do with moles is following:

[TestMethod()]
[HostType("Moles")]
public static void IsInFutureTest()
{
      MDateTime.NowGet = () => new DateTime(2010,09,01);
      bool actual = SuperClass.IsInFuture(new DateTime(2010, 09,03));
      Assert.IsTrue(actual);
}

The interesting thing here is the MDateTime construct, that comes from moles and the function replaces the actual method call with by us defined function that returns a constant date.
So here is what we have to do when we want to use the MDateTime construct:

  1. Install Pex and Moles.
  2. Add a new item of type “Moles and Stubs for Testing”  into the unit test project.  This file has to be called mscorlib.moles, because  the DateTime class is located in the mscorlib.dll. When you add this file the moles Framework analyses the dll and create the stubs. These stubs are the classes with the “M” prefix.
  3. Add following attribute [HostType(“Moles”)] to the test method. This tells moles framework to replace the actual methods with custom delegates.
  4. For this type you have to also add following row to the assemblyinfo.cs of the test project [assembly: Microsoft.Moles.Framework.MoledType(typeof(DateTime))]

SharePoint Unit Testing

You can stub in this way all SharePoint objects e.g. SPContext, SPList etc. All you have to do is to add new moles file with the name Microsoft.SharePoint.moles. This has actually one drawback and it is that it is a lot of coding to fullfill all the expectations that you use in the method to be tested. There come behaviors for SharePoint in play. It offers stubs with predefined behaviors against you can unit test your code. In all these cases you  don’t access the physically SharePoint, in extreme there can be no SharePoint installed at all.

So where can you find Behaviors for SharePoint. They are part of the Moles project and you can find it on the machine where moles are installed on the following path \Program Files (x86)\Microsoft Moles\Documentation\behaviors.samples.zip\behaviors\Microsoft.SharePoint.Behaviors. All You have to do is to compile this project and you have an assembly called Microsoft.SharePoint.Behaviors.dll that you can reference in your test projects. Here is a short sample how you can work with SharePoint behaviors:

[TestMethod()]
[HostType("Moles")]
public static void  IsListNameCorrectTest()
{
BSPSite site = new BSPSite();
BSPWeb web = site.SetRootWeb();
BSPList list = web.Lists.SetOne();
list.Title = "TestList";
bool actual = MyClass.IsListNameCorrect(list);
Assert.IsTrue(actual);
}

public static class MyClass
{
public bool IsListNameCorrect(SPList list)
{
return list.Title.Length < 200;
}
}